Skip to content

Commit 3818e58

Browse files
authored
Merge pull request #76 from summerwind/fix-crash-on-startup
Fix crash on startup after the HRDA addition
2 parents bdc1279 + 50487bb commit 3818e58

File tree

2 files changed

+256
-19
lines changed

2 files changed

+256
-19
lines changed

controllers/horizontalrunnerautoscaler_controller.go

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -128,27 +128,10 @@ func (r *HorizontalRunnerAutoscalerReconciler) Reconcile(req ctrl.Request) (ctrl
128128
}
129129

130130
func (r *HorizontalRunnerAutoscalerReconciler) SetupWithManager(mgr ctrl.Manager) error {
131-
r.Recorder = mgr.GetEventRecorderFor("runnerdeployment-controller")
132-
133-
if err := mgr.GetFieldIndexer().IndexField(&v1alpha1.RunnerReplicaSet{}, runnerSetOwnerKey, func(rawObj runtime.Object) []string {
134-
runnerSet := rawObj.(*v1alpha1.RunnerReplicaSet)
135-
owner := metav1.GetControllerOf(runnerSet)
136-
if owner == nil {
137-
return nil
138-
}
139-
140-
if owner.APIVersion != v1alpha1.GroupVersion.String() || owner.Kind != "RunnerDeployment" {
141-
return nil
142-
}
143-
144-
return []string{owner.Name}
145-
}); err != nil {
146-
return err
147-
}
131+
r.Recorder = mgr.GetEventRecorderFor("horizontalrunnerautoscaler-controller")
148132

149133
return ctrl.NewControllerManagedBy(mgr).
150-
For(&v1alpha1.RunnerDeployment{}).
151-
Owns(&v1alpha1.RunnerReplicaSet{}).
134+
For(&v1alpha1.HorizontalRunnerAutoscaler{}).
152135
Complete(r)
153136
}
154137

controllers/integration_test.go

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
package controllers
2+
3+
import (
4+
"context"
5+
"github.com/summerwind/actions-runner-controller/github/fake"
6+
"time"
7+
8+
corev1 "k8s.io/api/core/v1"
9+
"k8s.io/apimachinery/pkg/types"
10+
"k8s.io/client-go/kubernetes/scheme"
11+
ctrl "sigs.k8s.io/controller-runtime"
12+
logf "sigs.k8s.io/controller-runtime/pkg/log"
13+
14+
. "github.com/onsi/ginkgo"
15+
. "github.com/onsi/gomega"
16+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
17+
"sigs.k8s.io/controller-runtime/pkg/client"
18+
19+
actionsv1alpha1 "github.com/summerwind/actions-runner-controller/api/v1alpha1"
20+
)
21+
22+
// SetupIntegrationTest will set up a testing environment.
23+
// This includes:
24+
// * creating a Namespace to be used during the test
25+
// * starting all the reconcilers
26+
// * stopping all the reconcilers after the test ends
27+
// Call this function at the start of each of your tests.
28+
func SetupIntegrationTest(ctx context.Context) *corev1.Namespace {
29+
var stopCh chan struct{}
30+
ns := &corev1.Namespace{}
31+
32+
workflowRuns := `{"total_count": 5, "workflow_runs":[{"status":"queued"}, {"status":"queued"}, {"status":"in_progress"}, {"status":"in_progress"}, {"status":"completed"}]}"`
33+
server := fake.NewServer(fake.WithListRepositoryWorkflowRunsResponse(200, workflowRuns))
34+
35+
BeforeEach(func() {
36+
stopCh = make(chan struct{})
37+
*ns = corev1.Namespace{
38+
ObjectMeta: metav1.ObjectMeta{Name: "testns-" + randStringRunes(5)},
39+
}
40+
41+
err := k8sClient.Create(ctx, ns)
42+
Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
43+
44+
mgr, err := ctrl.NewManager(cfg, ctrl.Options{})
45+
Expect(err).NotTo(HaveOccurred(), "failed to create manager")
46+
47+
replicasetController := &RunnerReplicaSetReconciler{
48+
Client: mgr.GetClient(),
49+
Scheme: scheme.Scheme,
50+
Log: logf.Log,
51+
Recorder: mgr.GetEventRecorderFor("runnerreplicaset-controller"),
52+
}
53+
err = replicasetController.SetupWithManager(mgr)
54+
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
55+
56+
deploymentsController := &RunnerDeploymentReconciler{
57+
Client: mgr.GetClient(),
58+
Scheme: scheme.Scheme,
59+
Log: logf.Log,
60+
Recorder: mgr.GetEventRecorderFor("runnerdeployment-controller"),
61+
}
62+
err = deploymentsController.SetupWithManager(mgr)
63+
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
64+
65+
client := newGithubClient(server)
66+
67+
autoscalerController := &HorizontalRunnerAutoscalerReconciler{
68+
Client: mgr.GetClient(),
69+
Scheme: scheme.Scheme,
70+
Log: logf.Log,
71+
GitHubClient: client,
72+
Recorder: mgr.GetEventRecorderFor("horizontalrunnerautoscaler-controller"),
73+
}
74+
err = autoscalerController.SetupWithManager(mgr)
75+
Expect(err).NotTo(HaveOccurred(), "failed to setup controller")
76+
77+
go func() {
78+
defer GinkgoRecover()
79+
80+
err := mgr.Start(stopCh)
81+
Expect(err).NotTo(HaveOccurred(), "failed to start manager")
82+
}()
83+
})
84+
85+
AfterEach(func() {
86+
close(stopCh)
87+
88+
server.Close()
89+
90+
err := k8sClient.Delete(ctx, ns)
91+
Expect(err).NotTo(HaveOccurred(), "failed to delete test namespace")
92+
})
93+
94+
return ns
95+
}
96+
97+
var _ = Context("Inside of a new namespace", func() {
98+
ctx := context.TODO()
99+
ns := SetupIntegrationTest(ctx)
100+
101+
Describe("when no existing resources exist", func() {
102+
103+
It("should create and scale runners", func() {
104+
name := "example-runnerdeploy"
105+
106+
{
107+
rs := &actionsv1alpha1.RunnerDeployment{
108+
ObjectMeta: metav1.ObjectMeta{
109+
Name: name,
110+
Namespace: ns.Name,
111+
},
112+
Spec: actionsv1alpha1.RunnerDeploymentSpec{
113+
Replicas: intPtr(1),
114+
Template: actionsv1alpha1.RunnerTemplate{
115+
Spec: actionsv1alpha1.RunnerSpec{
116+
Repository: "test/valid",
117+
Image: "bar",
118+
Env: []corev1.EnvVar{
119+
{Name: "FOO", Value: "FOOVALUE"},
120+
},
121+
},
122+
},
123+
},
124+
}
125+
126+
err := k8sClient.Create(ctx, rs)
127+
128+
Expect(err).NotTo(HaveOccurred(), "failed to create test RunnerDeployment resource")
129+
130+
runnerSets := actionsv1alpha1.RunnerReplicaSetList{Items: []actionsv1alpha1.RunnerReplicaSet{}}
131+
132+
Eventually(
133+
func() int {
134+
err := k8sClient.List(ctx, &runnerSets, client.InNamespace(ns.Name))
135+
if err != nil {
136+
logf.Log.Error(err, "list runner sets")
137+
}
138+
139+
return len(runnerSets.Items)
140+
},
141+
time.Second*5, time.Millisecond*500).Should(BeEquivalentTo(1))
142+
143+
Eventually(
144+
func() int {
145+
err := k8sClient.List(ctx, &runnerSets, client.InNamespace(ns.Name))
146+
if err != nil {
147+
logf.Log.Error(err, "list runner sets")
148+
}
149+
150+
if len(runnerSets.Items) == 0 {
151+
logf.Log.Info("No runnerreplicasets exist yet")
152+
return -1
153+
}
154+
155+
return *runnerSets.Items[0].Spec.Replicas
156+
},
157+
time.Second*5, time.Millisecond*500).Should(BeEquivalentTo(1))
158+
}
159+
160+
{
161+
// We wrap the update in the Eventually block to avoid the below error that occurs due to concurrent modification
162+
// made by the controller to update .Status.AvailableReplicas and .Status.ReadyReplicas
163+
// Operation cannot be fulfilled on runnersets.actions.summerwind.dev "example-runnerset": the object has been modified; please apply your changes to the latest version and try again
164+
Eventually(func() error {
165+
var rd actionsv1alpha1.RunnerDeployment
166+
167+
err := k8sClient.Get(ctx, types.NamespacedName{Namespace: ns.Name, Name: name}, &rd)
168+
169+
Expect(err).NotTo(HaveOccurred(), "failed to get test RunnerDeployment resource")
170+
171+
rd.Spec.Replicas = intPtr(2)
172+
173+
return k8sClient.Update(ctx, &rd)
174+
},
175+
time.Second*1, time.Millisecond*500).Should(BeNil())
176+
177+
runnerSets := actionsv1alpha1.RunnerReplicaSetList{Items: []actionsv1alpha1.RunnerReplicaSet{}}
178+
179+
Eventually(
180+
func() int {
181+
err := k8sClient.List(ctx, &runnerSets, client.InNamespace(ns.Name))
182+
if err != nil {
183+
logf.Log.Error(err, "list runner sets")
184+
}
185+
186+
return len(runnerSets.Items)
187+
},
188+
time.Second*5, time.Millisecond*500).Should(BeEquivalentTo(1))
189+
190+
Eventually(
191+
func() int {
192+
err := k8sClient.List(ctx, &runnerSets, client.InNamespace(ns.Name))
193+
if err != nil {
194+
logf.Log.Error(err, "list runner sets")
195+
}
196+
197+
return *runnerSets.Items[0].Spec.Replicas
198+
},
199+
time.Second*5, time.Millisecond*500).Should(BeEquivalentTo(2))
200+
}
201+
202+
{
203+
rs := &actionsv1alpha1.HorizontalRunnerAutoscaler{
204+
ObjectMeta: metav1.ObjectMeta{
205+
Name: name,
206+
Namespace: ns.Name,
207+
},
208+
Spec: actionsv1alpha1.HorizontalRunnerAutoscalerSpec{
209+
ScaleTargetRef: actionsv1alpha1.ScaleTargetRef{
210+
Name: name,
211+
},
212+
MinReplicas: intPtr(1),
213+
MaxReplicas: intPtr(3),
214+
ScaleDownDelaySecondsAfterScaleUp: nil,
215+
Metrics: nil,
216+
},
217+
}
218+
219+
err := k8sClient.Create(ctx, rs)
220+
221+
Expect(err).NotTo(HaveOccurred(), "failed to create test RunnerDeployment resource")
222+
223+
runnerSets := actionsv1alpha1.RunnerReplicaSetList{Items: []actionsv1alpha1.RunnerReplicaSet{}}
224+
225+
Eventually(
226+
func() int {
227+
err := k8sClient.List(ctx, &runnerSets, client.InNamespace(ns.Name))
228+
if err != nil {
229+
logf.Log.Error(err, "list runner sets")
230+
}
231+
232+
return len(runnerSets.Items)
233+
},
234+
time.Second*5, time.Millisecond*500).Should(BeEquivalentTo(1))
235+
236+
Eventually(
237+
func() int {
238+
err := k8sClient.List(ctx, &runnerSets, client.InNamespace(ns.Name))
239+
if err != nil {
240+
logf.Log.Error(err, "list runner sets")
241+
}
242+
243+
if len(runnerSets.Items) == 0 {
244+
logf.Log.Info("No runnerreplicasets exist yet")
245+
return -1
246+
}
247+
248+
return *runnerSets.Items[0].Spec.Replicas
249+
},
250+
time.Second*5, time.Millisecond*500).Should(BeEquivalentTo(3))
251+
}
252+
})
253+
})
254+
})

0 commit comments

Comments
 (0)