Surface EphemeralRunnerSet stats to AutoscalingRunnerSet (#2382)
This commit is contained in:
		
							parent
							
								
									322df79617
								
							
						
					
					
						commit
						babbfc77d5
					
				|  | @ -33,10 +33,14 @@ import ( | ||||||
| 
 | 
 | ||||||
| //+kubebuilder:object:root=true
 | //+kubebuilder:object:root=true
 | ||||||
| //+kubebuilder:subresource:status
 | //+kubebuilder:subresource:status
 | ||||||
| //+kubebuilder:printcolumn:JSONPath=".spec.minRunners",name=Minimum Runners,type=number
 | //+kubebuilder:printcolumn:JSONPath=".spec.minRunners",name=Minimum Runners,type=integer
 | ||||||
| //+kubebuilder:printcolumn:JSONPath=".spec.maxRunners",name=Maximum Runners,type=number
 | //+kubebuilder:printcolumn:JSONPath=".spec.maxRunners",name=Maximum Runners,type=integer
 | ||||||
| //+kubebuilder:printcolumn:JSONPath=".status.currentRunners",name=Current Runners,type=number
 | //+kubebuilder:printcolumn:JSONPath=".status.currentRunners",name=Current Runners,type=integer
 | ||||||
| //+kubebuilder:printcolumn:JSONPath=".status.state",name=State,type=string
 | //+kubebuilder:printcolumn:JSONPath=".status.state",name=State,type=string
 | ||||||
|  | //+kubebuilder:printcolumn:JSONPath=".status.pendingEphemeralRunners",name=Pending Runners,type=integer
 | ||||||
|  | //+kubebuilder:printcolumn:JSONPath=".status.runningEphemeralRunners",name=Running Runners,type=integer
 | ||||||
|  | //+kubebuilder:printcolumn:JSONPath=".status.finishedEphemeralRunners",name=Finished Runners,type=integer
 | ||||||
|  | //+kubebuilder:printcolumn:JSONPath=".status.deletingEphemeralRunners",name=Deleting Runners,type=integer
 | ||||||
| 
 | 
 | ||||||
| // AutoscalingRunnerSet is the Schema for the autoscalingrunnersets API
 | // AutoscalingRunnerSet is the Schema for the autoscalingrunnersets API
 | ||||||
| type AutoscalingRunnerSet struct { | type AutoscalingRunnerSet struct { | ||||||
|  | @ -228,10 +232,19 @@ type ProxyServerConfig struct { | ||||||
| // AutoscalingRunnerSetStatus defines the observed state of AutoscalingRunnerSet
 | // AutoscalingRunnerSetStatus defines the observed state of AutoscalingRunnerSet
 | ||||||
| type AutoscalingRunnerSetStatus struct { | type AutoscalingRunnerSetStatus struct { | ||||||
| 	// +optional
 | 	// +optional
 | ||||||
| 	CurrentRunners int `json:"currentRunners,omitempty"` | 	CurrentRunners int `json:"currentRunners"` | ||||||
| 
 | 
 | ||||||
| 	// +optional
 | 	// +optional
 | ||||||
| 	State string `json:"state,omitempty"` | 	State string `json:"state"` | ||||||
|  | 
 | ||||||
|  | 	// EphemeralRunner counts separated by the stage ephemeral runners are in, taken from the EphemeralRunnerSet
 | ||||||
|  | 
 | ||||||
|  | 	//+optional
 | ||||||
|  | 	PendingEphemeralRunners int `json:"pendingEphemeralRunners"` | ||||||
|  | 	// +optional
 | ||||||
|  | 	RunningEphemeralRunners int `json:"runningEphemeralRunners"` | ||||||
|  | 	// +optional
 | ||||||
|  | 	FailedEphemeralRunners int `json:"failedEphemeralRunners"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (ars *AutoscalingRunnerSet) ListenerSpecHash() string { | func (ars *AutoscalingRunnerSet) ListenerSpecHash() string { | ||||||
|  |  | ||||||
|  | @ -31,13 +31,27 @@ type EphemeralRunnerSetSpec struct { | ||||||
| // EphemeralRunnerSetStatus defines the observed state of EphemeralRunnerSet
 | // EphemeralRunnerSetStatus defines the observed state of EphemeralRunnerSet
 | ||||||
| type EphemeralRunnerSetStatus struct { | type EphemeralRunnerSetStatus struct { | ||||||
| 	// CurrentReplicas is the number of currently running EphemeralRunner resources being managed by this EphemeralRunnerSet.
 | 	// CurrentReplicas is the number of currently running EphemeralRunner resources being managed by this EphemeralRunnerSet.
 | ||||||
| 	CurrentReplicas int `json:"currentReplicas,omitempty"` | 	CurrentReplicas int `json:"currentReplicas"` | ||||||
|  | 
 | ||||||
|  | 	// EphemeralRunner counts separated by the stage ephemeral runners are in
 | ||||||
|  | 
 | ||||||
|  | 	// +optional
 | ||||||
|  | 	PendingEphemeralRunners int `json:"pendingEphemeralRunners"` | ||||||
|  | 	// +optional
 | ||||||
|  | 	RunningEphemeralRunners int `json:"runningEphemeralRunners"` | ||||||
|  | 	// +optional
 | ||||||
|  | 	FailedEphemeralRunners int `json:"failedEphemeralRunners"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // +kubebuilder:object:root=true
 | // +kubebuilder:object:root=true
 | ||||||
| // +kubebuilder:subresource:status
 | // +kubebuilder:subresource:status
 | ||||||
| // +kubebuilder:printcolumn:JSONPath=".spec.replicas",name="DesiredReplicas",type="integer"
 | // +kubebuilder:printcolumn:JSONPath=".spec.replicas",name="DesiredReplicas",type="integer"
 | ||||||
| // +kubebuilder:printcolumn:JSONPath=".status.currentReplicas", name="CurrentReplicas",type="integer"
 | // +kubebuilder:printcolumn:JSONPath=".status.currentReplicas", name="CurrentReplicas",type="integer"
 | ||||||
|  | //+kubebuilder:printcolumn:JSONPath=".status.pendingEphemeralRunners",name=Pending Runners,type=integer
 | ||||||
|  | //+kubebuilder:printcolumn:JSONPath=".status.runningEphemeralRunners",name=Running Runners,type=integer
 | ||||||
|  | //+kubebuilder:printcolumn:JSONPath=".status.finishedEphemeralRunners",name=Finished Runners,type=integer
 | ||||||
|  | //+kubebuilder:printcolumn:JSONPath=".status.deletingEphemeralRunners",name=Deleting Runners,type=integer
 | ||||||
|  | 
 | ||||||
| // EphemeralRunnerSet is the Schema for the ephemeralrunnersets API
 | // EphemeralRunnerSet is the Schema for the ephemeralrunnersets API
 | ||||||
| type EphemeralRunnerSet struct { | type EphemeralRunnerSet struct { | ||||||
| 	metav1.TypeMeta   `json:",inline"` | 	metav1.TypeMeta   `json:",inline"` | ||||||
|  |  | ||||||
|  | @ -17,16 +17,28 @@ spec: | ||||||
|     - additionalPrinterColumns: |     - additionalPrinterColumns: | ||||||
|         - jsonPath: .spec.minRunners |         - jsonPath: .spec.minRunners | ||||||
|           name: Minimum Runners |           name: Minimum Runners | ||||||
|           type: number |           type: integer | ||||||
|         - jsonPath: .spec.maxRunners |         - jsonPath: .spec.maxRunners | ||||||
|           name: Maximum Runners |           name: Maximum Runners | ||||||
|           type: number |           type: integer | ||||||
|         - jsonPath: .status.currentRunners |         - jsonPath: .status.currentRunners | ||||||
|           name: Current Runners |           name: Current Runners | ||||||
|           type: number |           type: integer | ||||||
|         - jsonPath: .status.state |         - jsonPath: .status.state | ||||||
|           name: State |           name: State | ||||||
|           type: string |           type: string | ||||||
|  |         - jsonPath: .status.pendingEphemeralRunners | ||||||
|  |           name: Pending Runners | ||||||
|  |           type: integer | ||||||
|  |         - jsonPath: .status.runningEphemeralRunners | ||||||
|  |           name: Running Runners | ||||||
|  |           type: integer | ||||||
|  |         - jsonPath: .status.finishedEphemeralRunners | ||||||
|  |           name: Finished Runners | ||||||
|  |           type: integer | ||||||
|  |         - jsonPath: .status.deletingEphemeralRunners | ||||||
|  |           name: Deleting Runners | ||||||
|  |           type: integer | ||||||
|       name: v1alpha1 |       name: v1alpha1 | ||||||
|       schema: |       schema: | ||||||
|         openAPIV3Schema: |         openAPIV3Schema: | ||||||
|  | @ -4306,6 +4318,12 @@ spec: | ||||||
|               properties: |               properties: | ||||||
|                 currentRunners: |                 currentRunners: | ||||||
|                   type: integer |                   type: integer | ||||||
|  |                 failedEphemeralRunners: | ||||||
|  |                   type: integer | ||||||
|  |                 pendingEphemeralRunners: | ||||||
|  |                   type: integer | ||||||
|  |                 runningEphemeralRunners: | ||||||
|  |                   type: integer | ||||||
|                 state: |                 state: | ||||||
|                   type: string |                   type: string | ||||||
|               type: object |               type: object | ||||||
|  |  | ||||||
|  | @ -21,6 +21,18 @@ spec: | ||||||
|         - jsonPath: .status.currentReplicas |         - jsonPath: .status.currentReplicas | ||||||
|           name: CurrentReplicas |           name: CurrentReplicas | ||||||
|           type: integer |           type: integer | ||||||
|  |         - jsonPath: .status.pendingEphemeralRunners | ||||||
|  |           name: Pending Runners | ||||||
|  |           type: integer | ||||||
|  |         - jsonPath: .status.runningEphemeralRunners | ||||||
|  |           name: Running Runners | ||||||
|  |           type: integer | ||||||
|  |         - jsonPath: .status.finishedEphemeralRunners | ||||||
|  |           name: Finished Runners | ||||||
|  |           type: integer | ||||||
|  |         - jsonPath: .status.deletingEphemeralRunners | ||||||
|  |           name: Deleting Runners | ||||||
|  |           type: integer | ||||||
|       name: v1alpha1 |       name: v1alpha1 | ||||||
|       schema: |       schema: | ||||||
|         openAPIV3Schema: |         openAPIV3Schema: | ||||||
|  | @ -4296,6 +4308,14 @@ spec: | ||||||
|                 currentReplicas: |                 currentReplicas: | ||||||
|                   description: CurrentReplicas is the number of currently running EphemeralRunner resources being managed by this EphemeralRunnerSet. |                   description: CurrentReplicas is the number of currently running EphemeralRunner resources being managed by this EphemeralRunnerSet. | ||||||
|                   type: integer |                   type: integer | ||||||
|  |                 failedEphemeralRunners: | ||||||
|  |                   type: integer | ||||||
|  |                 pendingEphemeralRunners: | ||||||
|  |                   type: integer | ||||||
|  |                 runningEphemeralRunners: | ||||||
|  |                   type: integer | ||||||
|  |               required: | ||||||
|  |                 - currentReplicas | ||||||
|               type: object |               type: object | ||||||
|           type: object |           type: object | ||||||
|       served: true |       served: true | ||||||
|  |  | ||||||
|  | @ -17,16 +17,28 @@ spec: | ||||||
|     - additionalPrinterColumns: |     - additionalPrinterColumns: | ||||||
|         - jsonPath: .spec.minRunners |         - jsonPath: .spec.minRunners | ||||||
|           name: Minimum Runners |           name: Minimum Runners | ||||||
|           type: number |           type: integer | ||||||
|         - jsonPath: .spec.maxRunners |         - jsonPath: .spec.maxRunners | ||||||
|           name: Maximum Runners |           name: Maximum Runners | ||||||
|           type: number |           type: integer | ||||||
|         - jsonPath: .status.currentRunners |         - jsonPath: .status.currentRunners | ||||||
|           name: Current Runners |           name: Current Runners | ||||||
|           type: number |           type: integer | ||||||
|         - jsonPath: .status.state |         - jsonPath: .status.state | ||||||
|           name: State |           name: State | ||||||
|           type: string |           type: string | ||||||
|  |         - jsonPath: .status.pendingEphemeralRunners | ||||||
|  |           name: Pending Runners | ||||||
|  |           type: integer | ||||||
|  |         - jsonPath: .status.runningEphemeralRunners | ||||||
|  |           name: Running Runners | ||||||
|  |           type: integer | ||||||
|  |         - jsonPath: .status.finishedEphemeralRunners | ||||||
|  |           name: Finished Runners | ||||||
|  |           type: integer | ||||||
|  |         - jsonPath: .status.deletingEphemeralRunners | ||||||
|  |           name: Deleting Runners | ||||||
|  |           type: integer | ||||||
|       name: v1alpha1 |       name: v1alpha1 | ||||||
|       schema: |       schema: | ||||||
|         openAPIV3Schema: |         openAPIV3Schema: | ||||||
|  | @ -4306,6 +4318,12 @@ spec: | ||||||
|               properties: |               properties: | ||||||
|                 currentRunners: |                 currentRunners: | ||||||
|                   type: integer |                   type: integer | ||||||
|  |                 failedEphemeralRunners: | ||||||
|  |                   type: integer | ||||||
|  |                 pendingEphemeralRunners: | ||||||
|  |                   type: integer | ||||||
|  |                 runningEphemeralRunners: | ||||||
|  |                   type: integer | ||||||
|                 state: |                 state: | ||||||
|                   type: string |                   type: string | ||||||
|               type: object |               type: object | ||||||
|  |  | ||||||
|  | @ -21,6 +21,18 @@ spec: | ||||||
|         - jsonPath: .status.currentReplicas |         - jsonPath: .status.currentReplicas | ||||||
|           name: CurrentReplicas |           name: CurrentReplicas | ||||||
|           type: integer |           type: integer | ||||||
|  |         - jsonPath: .status.pendingEphemeralRunners | ||||||
|  |           name: Pending Runners | ||||||
|  |           type: integer | ||||||
|  |         - jsonPath: .status.runningEphemeralRunners | ||||||
|  |           name: Running Runners | ||||||
|  |           type: integer | ||||||
|  |         - jsonPath: .status.finishedEphemeralRunners | ||||||
|  |           name: Finished Runners | ||||||
|  |           type: integer | ||||||
|  |         - jsonPath: .status.deletingEphemeralRunners | ||||||
|  |           name: Deleting Runners | ||||||
|  |           type: integer | ||||||
|       name: v1alpha1 |       name: v1alpha1 | ||||||
|       schema: |       schema: | ||||||
|         openAPIV3Schema: |         openAPIV3Schema: | ||||||
|  | @ -4296,6 +4308,14 @@ spec: | ||||||
|                 currentReplicas: |                 currentReplicas: | ||||||
|                   description: CurrentReplicas is the number of currently running EphemeralRunner resources being managed by this EphemeralRunnerSet. |                   description: CurrentReplicas is the number of currently running EphemeralRunner resources being managed by this EphemeralRunnerSet. | ||||||
|                   type: integer |                   type: integer | ||||||
|  |                 failedEphemeralRunners: | ||||||
|  |                   type: integer | ||||||
|  |                 pendingEphemeralRunners: | ||||||
|  |                   type: integer | ||||||
|  |                 runningEphemeralRunners: | ||||||
|  |                   type: integer | ||||||
|  |               required: | ||||||
|  |                 - currentReplicas | ||||||
|               type: object |               type: object | ||||||
|           type: object |           type: object | ||||||
|       served: true |       served: true | ||||||
|  |  | ||||||
|  | @ -238,6 +238,9 @@ func (r *AutoscalingRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl | ||||||
| 	if latestRunnerSet.Status.CurrentReplicas != autoscalingRunnerSet.Status.CurrentRunners { | 	if latestRunnerSet.Status.CurrentReplicas != autoscalingRunnerSet.Status.CurrentRunners { | ||||||
| 		if err := patchSubResource(ctx, r.Status(), autoscalingRunnerSet, func(obj *v1alpha1.AutoscalingRunnerSet) { | 		if err := patchSubResource(ctx, r.Status(), autoscalingRunnerSet, func(obj *v1alpha1.AutoscalingRunnerSet) { | ||||||
| 			obj.Status.CurrentRunners = latestRunnerSet.Status.CurrentReplicas | 			obj.Status.CurrentRunners = latestRunnerSet.Status.CurrentReplicas | ||||||
|  | 			obj.Status.PendingEphemeralRunners = latestRunnerSet.Status.PendingEphemeralRunners | ||||||
|  | 			obj.Status.RunningEphemeralRunners = latestRunnerSet.Status.RunningEphemeralRunners | ||||||
|  | 			obj.Status.FailedEphemeralRunners = latestRunnerSet.Status.FailedEphemeralRunners | ||||||
| 		}); err != nil { | 		}); err != nil { | ||||||
| 			log.Error(err, "Failed to update autoscaling runner set status with current runner count") | 			log.Error(err, "Failed to update autoscaling runner set status with current runner count") | ||||||
| 			return ctrl.Result{}, err | 			return ctrl.Result{}, err | ||||||
|  |  | ||||||
|  | @ -157,23 +157,6 @@ var _ = Describe("Test AutoScalingRunnerSet controller", func() { | ||||||
| 			err := k8sClient.List(ctx, runnerSetList, client.InNamespace(autoscalingRunnerSet.Namespace)) | 			err := k8sClient.List(ctx, runnerSetList, client.InNamespace(autoscalingRunnerSet.Namespace)) | ||||||
| 			Expect(err).NotTo(HaveOccurred(), "failed to list EphemeralRunnerSet") | 			Expect(err).NotTo(HaveOccurred(), "failed to list EphemeralRunnerSet") | ||||||
| 			Expect(len(runnerSetList.Items)).To(BeEquivalentTo(1), "Only one EphemeralRunnerSet should be created") | 			Expect(len(runnerSetList.Items)).To(BeEquivalentTo(1), "Only one EphemeralRunnerSet should be created") | ||||||
| 			runnerSet := runnerSetList.Items[0] |  | ||||||
| 			statusUpdate := runnerSet.DeepCopy() |  | ||||||
| 			statusUpdate.Status.CurrentReplicas = 100 |  | ||||||
| 			err = k8sClient.Status().Patch(ctx, statusUpdate, client.MergeFrom(&runnerSet)) |  | ||||||
| 			Expect(err).NotTo(HaveOccurred(), "failed to patch EphemeralRunnerSet status") |  | ||||||
| 
 |  | ||||||
| 			Eventually( |  | ||||||
| 				func() (int, error) { |  | ||||||
| 					updated := new(v1alpha1.AutoscalingRunnerSet) |  | ||||||
| 					err := k8sClient.Get(ctx, client.ObjectKey{Name: autoscalingRunnerSet.Name, Namespace: autoscalingRunnerSet.Namespace}, updated) |  | ||||||
| 					if err != nil { |  | ||||||
| 						return 0, fmt.Errorf("failed to get AutoScalingRunnerSet: %w", err) |  | ||||||
| 					} |  | ||||||
| 					return updated.Status.CurrentRunners, nil |  | ||||||
| 				}, |  | ||||||
| 				autoscalingRunnerSetTestTimeout, |  | ||||||
| 				autoscalingRunnerSetTestInterval).Should(BeEquivalentTo(100), "AutoScalingRunnerSet status should be updated") |  | ||||||
| 		}) | 		}) | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
|  | @ -398,9 +381,75 @@ var _ = Describe("Test AutoScalingRunnerSet controller", func() { | ||||||
| 					return updated.Annotations[runnerScaleSetRunnerGroupNameKey], nil | 					return updated.Annotations[runnerScaleSetRunnerGroupNameKey], nil | ||||||
| 				}, | 				}, | ||||||
| 				autoscalingRunnerSetTestTimeout, | 				autoscalingRunnerSetTestTimeout, | ||||||
| 				autoscalingRunnerSetTestInterval).Should(BeEquivalentTo("testgroup2"), "AutoScalingRunnerSet should have the runner group in its annotation") | 				autoscalingRunnerSetTestInterval, | ||||||
|  | 			).Should(BeEquivalentTo("testgroup2"), "AutoScalingRunnerSet should have the runner group in its annotation") | ||||||
| 		}) | 		}) | ||||||
| 	}) | 	}) | ||||||
|  | 
 | ||||||
|  | 	It("Should update Status on EphemeralRunnerSet status Update", func() { | ||||||
|  | 		ars := new(v1alpha1.AutoscalingRunnerSet) | ||||||
|  | 		Eventually( | ||||||
|  | 			func() (bool, error) { | ||||||
|  | 				err := k8sClient.Get( | ||||||
|  | 					ctx, | ||||||
|  | 					client.ObjectKey{ | ||||||
|  | 						Name:      autoscalingRunnerSet.Name, | ||||||
|  | 						Namespace: autoscalingRunnerSet.Namespace, | ||||||
|  | 					}, | ||||||
|  | 					ars, | ||||||
|  | 				) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return false, err | ||||||
|  | 				} | ||||||
|  | 				return true, nil | ||||||
|  | 			}, | ||||||
|  | 			autoscalingRunnerSetTestTimeout, | ||||||
|  | 			autoscalingRunnerSetTestInterval, | ||||||
|  | 		).Should(BeTrue(), "AutoscalingRunnerSet should be created") | ||||||
|  | 
 | ||||||
|  | 		runnerSetList := new(v1alpha1.EphemeralRunnerSetList) | ||||||
|  | 		Eventually(func() (int, error) { | ||||||
|  | 			err := k8sClient.List(ctx, runnerSetList, client.InNamespace(ars.Namespace)) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return 0, err | ||||||
|  | 			} | ||||||
|  | 			return len(runnerSetList.Items), nil | ||||||
|  | 		}, | ||||||
|  | 			autoscalingRunnerSetTestTimeout, | ||||||
|  | 			autoscalingRunnerSetTestInterval, | ||||||
|  | 		).Should(BeEquivalentTo(1), "Failed to fetch runner set list") | ||||||
|  | 
 | ||||||
|  | 		runnerSet := runnerSetList.Items[0] | ||||||
|  | 		statusUpdate := runnerSet.DeepCopy() | ||||||
|  | 		statusUpdate.Status.CurrentReplicas = 6 | ||||||
|  | 		statusUpdate.Status.FailedEphemeralRunners = 1 | ||||||
|  | 		statusUpdate.Status.RunningEphemeralRunners = 2 | ||||||
|  | 		statusUpdate.Status.PendingEphemeralRunners = 3 | ||||||
|  | 
 | ||||||
|  | 		desiredStatus := v1alpha1.AutoscalingRunnerSetStatus{ | ||||||
|  | 			CurrentRunners:          statusUpdate.Status.CurrentReplicas, | ||||||
|  | 			State:                   "", | ||||||
|  | 			PendingEphemeralRunners: statusUpdate.Status.PendingEphemeralRunners, | ||||||
|  | 			RunningEphemeralRunners: statusUpdate.Status.RunningEphemeralRunners, | ||||||
|  | 			FailedEphemeralRunners:  statusUpdate.Status.FailedEphemeralRunners, | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		err := k8sClient.Status().Patch(ctx, statusUpdate, client.MergeFrom(&runnerSet)) | ||||||
|  | 		Expect(err).NotTo(HaveOccurred(), "Failed to patch runner set status") | ||||||
|  | 
 | ||||||
|  | 		Eventually( | ||||||
|  | 			func() (v1alpha1.AutoscalingRunnerSetStatus, error) { | ||||||
|  | 				updated := new(v1alpha1.AutoscalingRunnerSet) | ||||||
|  | 				err := k8sClient.Get(ctx, client.ObjectKey{Name: autoscalingRunnerSet.Name, Namespace: autoscalingRunnerSet.Namespace}, updated) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return v1alpha1.AutoscalingRunnerSetStatus{}, fmt.Errorf("failed to get AutoScalingRunnerSet: %w", err) | ||||||
|  | 				} | ||||||
|  | 				return updated.Status, nil | ||||||
|  | 			}, | ||||||
|  | 			autoscalingRunnerSetTestTimeout, | ||||||
|  | 			autoscalingRunnerSetTestInterval, | ||||||
|  | 		).Should(BeEquivalentTo(desiredStatus), "AutoScalingRunnerSet status should be updated") | ||||||
|  | 	}) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| var _ = Describe("Test AutoScalingController updates", func() { | var _ = Describe("Test AutoScalingController updates", func() { | ||||||
|  |  | ||||||
|  | @ -200,11 +200,18 @@ func (r *EphemeralRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl.R | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	desiredStatus := v1alpha1.EphemeralRunnerSetStatus{ | ||||||
|  | 		CurrentReplicas:         total, | ||||||
|  | 		PendingEphemeralRunners: len(pendingEphemeralRunners), | ||||||
|  | 		RunningEphemeralRunners: len(runningEphemeralRunners), | ||||||
|  | 		FailedEphemeralRunners:  len(failedEphemeralRunners), | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// Update the status if needed.
 | 	// Update the status if needed.
 | ||||||
| 	if ephemeralRunnerSet.Status.CurrentReplicas != total { | 	if ephemeralRunnerSet.Status != desiredStatus { | ||||||
| 		log.Info("Updating status with current runners count", "count", total) | 		log.Info("Updating status with current runners count", "count", total) | ||||||
| 		if err := patchSubResource(ctx, r.Status(), ephemeralRunnerSet, func(obj *v1alpha1.EphemeralRunnerSet) { | 		if err := patchSubResource(ctx, r.Status(), ephemeralRunnerSet, func(obj *v1alpha1.EphemeralRunnerSet) { | ||||||
| 			obj.Status.CurrentReplicas = total | 			obj.Status = desiredStatus | ||||||
| 		}); err != nil { | 		}); err != nil { | ||||||
| 			log.Error(err, "Failed to update status with current runners count") | 			log.Error(err, "Failed to update status with current runners count") | ||||||
| 			return ctrl.Result{}, err | 			return ctrl.Result{}, err | ||||||
|  |  | ||||||
|  | @ -559,6 +559,181 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() { | ||||||
| 				ephemeralRunnerSetTestTimeout, | 				ephemeralRunnerSetTestTimeout, | ||||||
| 				ephemeralRunnerSetTestInterval).Should(BeEquivalentTo(0), "0 EphemeralRunner should be created") | 				ephemeralRunnerSetTestInterval).Should(BeEquivalentTo(0), "0 EphemeralRunner should be created") | ||||||
| 		}) | 		}) | ||||||
|  | 
 | ||||||
|  | 		It("Should update status on Ephemeral Runner state changes", func() { | ||||||
|  | 			created := new(actionsv1alpha1.EphemeralRunnerSet) | ||||||
|  | 			Eventually( | ||||||
|  | 				func() error { | ||||||
|  | 					return k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunnerSet.Name, Namespace: ephemeralRunnerSet.Namespace}, created) | ||||||
|  | 				}, | ||||||
|  | 				ephemeralRunnerSetTestTimeout, | ||||||
|  | 				ephemeralRunnerSetTestInterval, | ||||||
|  | 			).Should(Succeed(), "EphemeralRunnerSet should be created") | ||||||
|  | 
 | ||||||
|  | 			// Scale up the EphemeralRunnerSet
 | ||||||
|  | 			updated := created.DeepCopy() | ||||||
|  | 			updated.Spec.Replicas = 3 | ||||||
|  | 			err := k8sClient.Update(ctx, updated) | ||||||
|  | 			Expect(err).NotTo(HaveOccurred(), "failed to update EphemeralRunnerSet replica count") | ||||||
|  | 
 | ||||||
|  | 			runnerList := new(actionsv1alpha1.EphemeralRunnerList) | ||||||
|  | 			Eventually( | ||||||
|  | 				func() (bool, error) { | ||||||
|  | 					err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) | ||||||
|  | 					if err != nil { | ||||||
|  | 						return false, err | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if len(runnerList.Items) != 3 { | ||||||
|  | 						return false, err | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					var pendingOriginal *v1alpha1.EphemeralRunner | ||||||
|  | 					var runningOriginal *v1alpha1.EphemeralRunner | ||||||
|  | 					var failedOriginal *v1alpha1.EphemeralRunner | ||||||
|  | 					var empty []*v1alpha1.EphemeralRunner | ||||||
|  | 					for _, runner := range runnerList.Items { | ||||||
|  | 						switch runner.Status.RunnerId { | ||||||
|  | 						case 101: | ||||||
|  | 							pendingOriginal = runner.DeepCopy() | ||||||
|  | 						case 102: | ||||||
|  | 							runningOriginal = runner.DeepCopy() | ||||||
|  | 						case 103: | ||||||
|  | 							failedOriginal = runner.DeepCopy() | ||||||
|  | 						default: | ||||||
|  | 							empty = append(empty, runner.DeepCopy()) | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					refetch := false | ||||||
|  | 					if pendingOriginal == nil { // if NO pending
 | ||||||
|  | 						refetch = true | ||||||
|  | 						pendingOriginal = empty[0] | ||||||
|  | 						empty = empty[1:] | ||||||
|  | 
 | ||||||
|  | 						pending := pendingOriginal.DeepCopy() | ||||||
|  | 						pending.Status.RunnerId = 101 | ||||||
|  | 						pending.Status.Phase = corev1.PodPending | ||||||
|  | 
 | ||||||
|  | 						err = k8sClient.Status().Patch(ctx, pending, client.MergeFrom(pendingOriginal)) | ||||||
|  | 						if err != nil { | ||||||
|  | 							return false, err | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if runningOriginal == nil { // if NO running
 | ||||||
|  | 						refetch = true | ||||||
|  | 						runningOriginal = empty[0] | ||||||
|  | 						empty = empty[1:] | ||||||
|  | 						running := runningOriginal.DeepCopy() | ||||||
|  | 						running.Status.RunnerId = 102 | ||||||
|  | 						running.Status.Phase = corev1.PodRunning | ||||||
|  | 
 | ||||||
|  | 						err = k8sClient.Status().Patch(ctx, running, client.MergeFrom(runningOriginal)) | ||||||
|  | 						if err != nil { | ||||||
|  | 							return false, err | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if failedOriginal == nil { // if NO failed
 | ||||||
|  | 						refetch = true | ||||||
|  | 						failedOriginal = empty[0] | ||||||
|  | 
 | ||||||
|  | 						failed := pendingOriginal.DeepCopy() | ||||||
|  | 						failed.Status.RunnerId = 103 | ||||||
|  | 						failed.Status.Phase = corev1.PodFailed | ||||||
|  | 
 | ||||||
|  | 						err = k8sClient.Status().Patch(ctx, failed, client.MergeFrom(failedOriginal)) | ||||||
|  | 						if err != nil { | ||||||
|  | 							return false, err | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					return !refetch, nil | ||||||
|  | 				}, | ||||||
|  | 				ephemeralRunnerSetTestTimeout, | ||||||
|  | 				ephemeralRunnerSetTestInterval, | ||||||
|  | 			).Should(BeTrue(), "Failed to eventually update to one pending, one running and one failed") | ||||||
|  | 
 | ||||||
|  | 			desiredStatus := v1alpha1.EphemeralRunnerSetStatus{ | ||||||
|  | 				CurrentReplicas:         3, | ||||||
|  | 				PendingEphemeralRunners: 1, | ||||||
|  | 				RunningEphemeralRunners: 1, | ||||||
|  | 				FailedEphemeralRunners:  1, | ||||||
|  | 			} | ||||||
|  | 			Eventually( | ||||||
|  | 				func() (v1alpha1.EphemeralRunnerSetStatus, error) { | ||||||
|  | 					updated := new(v1alpha1.EphemeralRunnerSet) | ||||||
|  | 					err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunnerSet.Name, Namespace: ephemeralRunnerSet.Namespace}, updated) | ||||||
|  | 					if err != nil { | ||||||
|  | 						return v1alpha1.EphemeralRunnerSetStatus{}, err | ||||||
|  | 					} | ||||||
|  | 					return updated.Status, nil | ||||||
|  | 				}, | ||||||
|  | 				ephemeralRunnerSetTestTimeout, | ||||||
|  | 				ephemeralRunnerSetTestInterval, | ||||||
|  | 			).Should(BeEquivalentTo(desiredStatus), "Status is not eventually updated to the desired one") | ||||||
|  | 
 | ||||||
|  | 			updated = new(v1alpha1.EphemeralRunnerSet) | ||||||
|  | 			err = k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunnerSet.Name, Namespace: ephemeralRunnerSet.Namespace}, updated) | ||||||
|  | 			Expect(err).NotTo(HaveOccurred(), "Failed to fetch ephemeral runner set") | ||||||
|  | 
 | ||||||
|  | 			updatedOriginal := updated.DeepCopy() | ||||||
|  | 			updated.Spec.Replicas = 0 | ||||||
|  | 
 | ||||||
|  | 			err = k8sClient.Patch(ctx, updated, client.MergeFrom(updatedOriginal)) | ||||||
|  | 			Expect(err).NotTo(HaveOccurred(), "Failed to patch ephemeral runner set with 0 replicas") | ||||||
|  | 
 | ||||||
|  | 			Eventually( | ||||||
|  | 				func() (int, error) { | ||||||
|  | 					runnerList = new(actionsv1alpha1.EphemeralRunnerList) | ||||||
|  | 					err := k8sClient.List(ctx, runnerList, client.InNamespace(ephemeralRunnerSet.Namespace)) | ||||||
|  | 					if err != nil { | ||||||
|  | 						return -1, err | ||||||
|  | 					} | ||||||
|  | 					return len(runnerList.Items), nil | ||||||
|  | 				}, | ||||||
|  | 				ephemeralRunnerSetTestTimeout, | ||||||
|  | 				ephemeralRunnerSetTestInterval, | ||||||
|  | 			).Should(BeEquivalentTo(1), "Failed to eventually scale down") | ||||||
|  | 
 | ||||||
|  | 			desiredStatus = v1alpha1.EphemeralRunnerSetStatus{ | ||||||
|  | 				CurrentReplicas:         1, | ||||||
|  | 				PendingEphemeralRunners: 0, | ||||||
|  | 				RunningEphemeralRunners: 0, | ||||||
|  | 				FailedEphemeralRunners:  1, | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			Eventually( | ||||||
|  | 				func() (v1alpha1.EphemeralRunnerSetStatus, error) { | ||||||
|  | 					updated := new(v1alpha1.EphemeralRunnerSet) | ||||||
|  | 					err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunnerSet.Name, Namespace: ephemeralRunnerSet.Namespace}, updated) | ||||||
|  | 					if err != nil { | ||||||
|  | 						return v1alpha1.EphemeralRunnerSetStatus{}, err | ||||||
|  | 					} | ||||||
|  | 					return updated.Status, nil | ||||||
|  | 				}, | ||||||
|  | 				ephemeralRunnerSetTestTimeout, | ||||||
|  | 				ephemeralRunnerSetTestInterval, | ||||||
|  | 			).Should(BeEquivalentTo(desiredStatus), "Status is not eventually updated to the desired one") | ||||||
|  | 
 | ||||||
|  | 			err = k8sClient.Delete(ctx, &runnerList.Items[0]) | ||||||
|  | 			Expect(err).To(BeNil(), "Failed to delete failed ephemeral runner") | ||||||
|  | 
 | ||||||
|  | 			desiredStatus = v1alpha1.EphemeralRunnerSetStatus{} // empty
 | ||||||
|  | 			Eventually( | ||||||
|  | 				func() (v1alpha1.EphemeralRunnerSetStatus, error) { | ||||||
|  | 					updated := new(v1alpha1.EphemeralRunnerSet) | ||||||
|  | 					err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunnerSet.Name, Namespace: ephemeralRunnerSet.Namespace}, updated) | ||||||
|  | 					if err != nil { | ||||||
|  | 						return v1alpha1.EphemeralRunnerSetStatus{}, err | ||||||
|  | 					} | ||||||
|  | 					return updated.Status, nil | ||||||
|  | 				}, | ||||||
|  | 				ephemeralRunnerSetTestTimeout, | ||||||
|  | 				ephemeralRunnerSetTestInterval, | ||||||
|  | 			).Should(BeEquivalentTo(desiredStatus), "Status is not eventually updated to the desired one") | ||||||
|  | 		}) | ||||||
| 	}) | 	}) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
|  | @ -821,12 +996,13 @@ var _ = Describe("Test EphemeralRunnerSet controller with proxy settings", func( | ||||||
| 		err = k8sClient.Status().Patch(ctx, runner, client.MergeFrom(&runnerList.Items[0])) | 		err = k8sClient.Status().Patch(ctx, runner, client.MergeFrom(&runnerList.Items[0])) | ||||||
| 		Expect(err).NotTo(HaveOccurred(), "failed to update ephemeral runner status") | 		Expect(err).NotTo(HaveOccurred(), "failed to update ephemeral runner status") | ||||||
| 
 | 
 | ||||||
| 		updatedRunnerSet := new(actionsv1alpha1.EphemeralRunnerSet) | 		runnerSet := new(actionsv1alpha1.EphemeralRunnerSet) | ||||||
| 		err = k8sClient.Get(ctx, client.ObjectKey{Namespace: ephemeralRunnerSet.Namespace, Name: ephemeralRunnerSet.Name}, updatedRunnerSet) | 		err = k8sClient.Get(ctx, client.ObjectKey{Namespace: ephemeralRunnerSet.Namespace, Name: ephemeralRunnerSet.Name}, runnerSet) | ||||||
| 		Expect(err).NotTo(HaveOccurred(), "failed to get EphemeralRunnerSet") | 		Expect(err).NotTo(HaveOccurred(), "failed to get EphemeralRunnerSet") | ||||||
| 
 | 
 | ||||||
|  | 		updatedRunnerSet := runnerSet.DeepCopy() | ||||||
| 		updatedRunnerSet.Spec.Replicas = 0 | 		updatedRunnerSet.Spec.Replicas = 0 | ||||||
| 		err = k8sClient.Update(ctx, updatedRunnerSet) | 		err = k8sClient.Patch(ctx, updatedRunnerSet, client.MergeFrom(runnerSet)) | ||||||
| 		Expect(err).NotTo(HaveOccurred(), "failed to update EphemeralRunnerSet") | 		Expect(err).NotTo(HaveOccurred(), "failed to update EphemeralRunnerSet") | ||||||
| 
 | 
 | ||||||
| 		Eventually( | 		Eventually( | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue