Use metrics to display runner statuses instead of status field for EphemeralRunnerSet and AutoscalingRunnerSet (#4557)
This commit is contained in:
parent
368e2f28b8
commit
f6a3d738de
|
|
@ -42,11 +42,11 @@ type AutoscalingListenerSpec struct {
|
||||||
// +optional
|
// +optional
|
||||||
EphemeralRunnerSetName string `json:"ephemeralRunnerSetName,omitempty"`
|
EphemeralRunnerSetName string `json:"ephemeralRunnerSetName,omitempty"`
|
||||||
|
|
||||||
// +kubebuilder:validation:Minimum:=0
|
// +kubebuilder:validation:Minimum=0
|
||||||
// +optional
|
// +optional
|
||||||
MaxRunners int `json:"maxRunners,omitempty"`
|
MaxRunners int `json:"maxRunners,omitempty"`
|
||||||
|
|
||||||
// +kubebuilder:validation:Minimum:=0
|
// +kubebuilder:validation:Minimum=0
|
||||||
// +optional
|
// +optional
|
||||||
MinRunners int `json:"minRunners,omitempty"`
|
MinRunners int `json:"minRunners,omitempty"`
|
||||||
|
|
||||||
|
|
@ -109,6 +109,7 @@ type AutoscalingListener struct {
|
||||||
Status AutoscalingListenerStatus `json:"status,omitempty"`
|
Status AutoscalingListenerStatus `json:"status,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AutoscalingListenerList is a list of AutoscalingListener resources
|
||||||
// +kubebuilder:object:root=true
|
// +kubebuilder:object:root=true
|
||||||
// AutoscalingListenerList contains a list of AutoscalingListener
|
// AutoscalingListenerList contains a list of AutoscalingListener
|
||||||
type AutoscalingListenerList struct {
|
type AutoscalingListenerList struct {
|
||||||
|
|
|
||||||
|
|
@ -317,20 +317,8 @@ type HistogramMetric struct {
|
||||||
|
|
||||||
// AutoscalingRunnerSetStatus defines the observed state of AutoscalingRunnerSet
|
// AutoscalingRunnerSetStatus defines the observed state of AutoscalingRunnerSet
|
||||||
type AutoscalingRunnerSetStatus struct {
|
type AutoscalingRunnerSetStatus struct {
|
||||||
// +optional
|
|
||||||
CurrentRunners int `json:"currentRunners"`
|
|
||||||
|
|
||||||
// +optional
|
// +optional
|
||||||
Phase AutoscalingRunnerSetPhase `json:"phase"`
|
Phase AutoscalingRunnerSetPhase `json:"phase"`
|
||||||
|
|
||||||
// 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"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type AutoscalingRunnerSetPhase string
|
type AutoscalingRunnerSetPhase string
|
||||||
|
|
|
||||||
|
|
@ -40,15 +40,6 @@ 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.
|
|
||||||
// +optional
|
|
||||||
CurrentReplicas int `json:"currentReplicas"`
|
|
||||||
// +optional
|
|
||||||
PendingEphemeralRunners int `json:"pendingEphemeralRunners"`
|
|
||||||
// +optional
|
|
||||||
RunningEphemeralRunners int `json:"runningEphemeralRunners"`
|
|
||||||
// +optional
|
|
||||||
FailedEphemeralRunners int `json:"failedEphemeralRunners"`
|
|
||||||
// +optional
|
// +optional
|
||||||
Phase EphemeralRunnerSetPhase `json:"phase"`
|
Phase EphemeralRunnerSetPhase `json:"phase"`
|
||||||
}
|
}
|
||||||
|
|
@ -66,11 +57,6 @@ const (
|
||||||
// +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.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
|
|
||||||
// +kubebuilder:printcolumn:JSONPath=".status.phase",name=Phase,type=string
|
// +kubebuilder:printcolumn:JSONPath=".status.phase",name=Phase,type=string
|
||||||
|
|
||||||
// EphemeralRunnerSet is the Schema for the ephemeralrunnersets API
|
// EphemeralRunnerSet is the Schema for the ephemeralrunnersets API
|
||||||
|
|
|
||||||
|
|
@ -16541,16 +16541,8 @@ spec:
|
||||||
status:
|
status:
|
||||||
description: AutoscalingRunnerSetStatus defines the observed state of AutoscalingRunnerSet
|
description: AutoscalingRunnerSetStatus defines the observed state of AutoscalingRunnerSet
|
||||||
properties:
|
properties:
|
||||||
currentRunners:
|
|
||||||
type: integer
|
|
||||||
failedEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
pendingEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
phase:
|
phase:
|
||||||
type: string
|
type: string
|
||||||
runningEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
served: true
|
served: true
|
||||||
|
|
|
||||||
|
|
@ -18,21 +18,6 @@ spec:
|
||||||
- jsonPath: .spec.replicas
|
- jsonPath: .spec.replicas
|
||||||
name: DesiredReplicas
|
name: DesiredReplicas
|
||||||
type: integer
|
type: integer
|
||||||
- jsonPath: .status.currentReplicas
|
|
||||||
name: CurrentReplicas
|
|
||||||
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
|
|
||||||
- jsonPath: .status.phase
|
- jsonPath: .status.phase
|
||||||
name: Phase
|
name: Phase
|
||||||
type: string
|
type: string
|
||||||
|
|
@ -8310,18 +8295,9 @@ spec:
|
||||||
status:
|
status:
|
||||||
description: EphemeralRunnerSetStatus defines the observed state of EphemeralRunnerSet
|
description: EphemeralRunnerSetStatus defines the observed state of EphemeralRunnerSet
|
||||||
properties:
|
properties:
|
||||||
currentReplicas:
|
|
||||||
description: CurrentReplicas is the number of currently running EphemeralRunner resources being managed by this EphemeralRunnerSet.
|
|
||||||
type: integer
|
|
||||||
failedEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
pendingEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
phase:
|
phase:
|
||||||
description: EphemeralRunnerSetPhase is the phase of the ephemeral runner set resource
|
description: EphemeralRunnerSetPhase is the phase of the ephemeral runner set resource
|
||||||
type: string
|
type: string
|
||||||
runningEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
served: true
|
served: true
|
||||||
|
|
|
||||||
|
|
@ -16541,16 +16541,8 @@ spec:
|
||||||
status:
|
status:
|
||||||
description: AutoscalingRunnerSetStatus defines the observed state of AutoscalingRunnerSet
|
description: AutoscalingRunnerSetStatus defines the observed state of AutoscalingRunnerSet
|
||||||
properties:
|
properties:
|
||||||
currentRunners:
|
|
||||||
type: integer
|
|
||||||
failedEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
pendingEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
phase:
|
phase:
|
||||||
type: string
|
type: string
|
||||||
runningEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
served: true
|
served: true
|
||||||
|
|
|
||||||
|
|
@ -18,21 +18,6 @@ spec:
|
||||||
- jsonPath: .spec.replicas
|
- jsonPath: .spec.replicas
|
||||||
name: DesiredReplicas
|
name: DesiredReplicas
|
||||||
type: integer
|
type: integer
|
||||||
- jsonPath: .status.currentReplicas
|
|
||||||
name: CurrentReplicas
|
|
||||||
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
|
|
||||||
- jsonPath: .status.phase
|
- jsonPath: .status.phase
|
||||||
name: Phase
|
name: Phase
|
||||||
type: string
|
type: string
|
||||||
|
|
@ -8310,18 +8295,9 @@ spec:
|
||||||
status:
|
status:
|
||||||
description: EphemeralRunnerSetStatus defines the observed state of EphemeralRunnerSet
|
description: EphemeralRunnerSetStatus defines the observed state of EphemeralRunnerSet
|
||||||
properties:
|
properties:
|
||||||
currentReplicas:
|
|
||||||
description: CurrentReplicas is the number of currently running EphemeralRunner resources being managed by this EphemeralRunnerSet.
|
|
||||||
type: integer
|
|
||||||
failedEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
pendingEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
phase:
|
phase:
|
||||||
description: EphemeralRunnerSetPhase is the phase of the ephemeral runner set resource
|
description: EphemeralRunnerSetPhase is the phase of the ephemeral runner set resource
|
||||||
type: string
|
type: string
|
||||||
runningEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
served: true
|
served: true
|
||||||
|
|
|
||||||
|
|
@ -16541,16 +16541,8 @@ spec:
|
||||||
status:
|
status:
|
||||||
description: AutoscalingRunnerSetStatus defines the observed state of AutoscalingRunnerSet
|
description: AutoscalingRunnerSetStatus defines the observed state of AutoscalingRunnerSet
|
||||||
properties:
|
properties:
|
||||||
currentRunners:
|
|
||||||
type: integer
|
|
||||||
failedEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
pendingEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
phase:
|
phase:
|
||||||
type: string
|
type: string
|
||||||
runningEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
served: true
|
served: true
|
||||||
|
|
|
||||||
|
|
@ -18,21 +18,6 @@ spec:
|
||||||
- jsonPath: .spec.replicas
|
- jsonPath: .spec.replicas
|
||||||
name: DesiredReplicas
|
name: DesiredReplicas
|
||||||
type: integer
|
type: integer
|
||||||
- jsonPath: .status.currentReplicas
|
|
||||||
name: CurrentReplicas
|
|
||||||
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
|
|
||||||
- jsonPath: .status.phase
|
- jsonPath: .status.phase
|
||||||
name: Phase
|
name: Phase
|
||||||
type: string
|
type: string
|
||||||
|
|
@ -8310,18 +8295,9 @@ spec:
|
||||||
status:
|
status:
|
||||||
description: EphemeralRunnerSetStatus defines the observed state of EphemeralRunnerSet
|
description: EphemeralRunnerSetStatus defines the observed state of EphemeralRunnerSet
|
||||||
properties:
|
properties:
|
||||||
currentReplicas:
|
|
||||||
description: CurrentReplicas is the number of currently running EphemeralRunner resources being managed by this EphemeralRunnerSet.
|
|
||||||
type: integer
|
|
||||||
failedEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
pendingEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
phase:
|
phase:
|
||||||
description: EphemeralRunnerSetPhase is the phase of the ephemeral runner set resource
|
description: EphemeralRunnerSetPhase is the phase of the ephemeral runner set resource
|
||||||
type: string
|
type: string
|
||||||
runningEphemeralRunners:
|
|
||||||
type: integer
|
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
served: true
|
served: true
|
||||||
|
|
|
||||||
|
|
@ -292,18 +292,6 @@ func (r *AutoscalingRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl
|
||||||
}
|
}
|
||||||
|
|
||||||
if ephemeralRunnerSet.Annotations[annotationKeyIntegrityHash] != desired.Annotations[annotationKeyIntegrityHash] {
|
if ephemeralRunnerSet.Annotations[annotationKeyIntegrityHash] != desired.Annotations[annotationKeyIntegrityHash] {
|
||||||
// When runners are actively processing jobs, defer the spec update:
|
|
||||||
// delete the listener to stop accepting new jobs, but leave the ERS
|
|
||||||
// (and its running pods) untouched until all jobs have drained.
|
|
||||||
if ephemeralRunnerSet.Status.RunningEphemeralRunners+ephemeralRunnerSet.Status.PendingEphemeralRunners > 0 {
|
|
||||||
log.Info("Ephemeral runner set spec changed but runners are still active; deleting listener to stop new jobs")
|
|
||||||
if _, err := r.cleanupListener(ctx, &autoscalingRunnerSet, log); err != nil {
|
|
||||||
log.Error(err, "Failed to clean up listener while waiting for runners to drain")
|
|
||||||
return ctrl.Result{}, err
|
|
||||||
}
|
|
||||||
return ctrl.Result{RequeueAfter: 1 * time.Second}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
original := ephemeralRunnerSet.DeepCopy()
|
original := ephemeralRunnerSet.DeepCopy()
|
||||||
ephemeralRunnerSet.Spec.EphemeralRunnerMetadata = desired.Spec.EphemeralRunnerMetadata
|
ephemeralRunnerSet.Spec.EphemeralRunnerMetadata = desired.Spec.EphemeralRunnerMetadata
|
||||||
ephemeralRunnerSet.Spec.EphemeralRunnerSpec = desired.Spec.EphemeralRunnerSpec
|
ephemeralRunnerSet.Spec.EphemeralRunnerSpec = desired.Spec.EphemeralRunnerSpec
|
||||||
|
|
@ -386,7 +374,6 @@ func (r *AutoscalingRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl
|
||||||
if err := r.updateStatus(
|
if err := r.updateStatus(
|
||||||
ctx,
|
ctx,
|
||||||
&autoscalingRunnerSet,
|
&autoscalingRunnerSet,
|
||||||
&ephemeralRunnerSet,
|
|
||||||
v1alpha1.AutoscalingRunnerSetPhaseRunning,
|
v1alpha1.AutoscalingRunnerSetPhaseRunning,
|
||||||
log,
|
log,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
|
@ -432,24 +419,14 @@ func (r *AutoscalingRunnerSetReconciler) cleanUpResources(ctx context.Context, a
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the status of autoscaling runner set if necessary
|
// Update the status of autoscaling runner set if necessary
|
||||||
func (r *AutoscalingRunnerSetReconciler) updateStatus(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, ephemeralRunnerSet *v1alpha1.EphemeralRunnerSet, phase v1alpha1.AutoscalingRunnerSetPhase, log logr.Logger) error {
|
func (r *AutoscalingRunnerSetReconciler) updateStatus(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, phase v1alpha1.AutoscalingRunnerSetPhase, log logr.Logger) error {
|
||||||
countDiff := ephemeralRunnerSet != nil && ephemeralRunnerSet.Status.CurrentReplicas != autoscalingRunnerSet.Status.CurrentRunners
|
|
||||||
phaseDiff := phase != autoscalingRunnerSet.Status.Phase
|
phaseDiff := phase != autoscalingRunnerSet.Status.Phase
|
||||||
if !countDiff && !phaseDiff {
|
if !phaseDiff {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
original := autoscalingRunnerSet.DeepCopy()
|
original := autoscalingRunnerSet.DeepCopy()
|
||||||
if phaseDiff {
|
autoscalingRunnerSet.Status.Phase = phase
|
||||||
autoscalingRunnerSet.Status.Phase = phase
|
|
||||||
}
|
|
||||||
|
|
||||||
if countDiff && ephemeralRunnerSet != nil {
|
|
||||||
autoscalingRunnerSet.Status.CurrentRunners = ephemeralRunnerSet.Status.CurrentReplicas
|
|
||||||
autoscalingRunnerSet.Status.PendingEphemeralRunners = ephemeralRunnerSet.Status.PendingEphemeralRunners
|
|
||||||
autoscalingRunnerSet.Status.RunningEphemeralRunners = ephemeralRunnerSet.Status.RunningEphemeralRunners
|
|
||||||
autoscalingRunnerSet.Status.FailedEphemeralRunners = ephemeralRunnerSet.Status.FailedEphemeralRunners
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := r.Status().Patch(ctx, autoscalingRunnerSet, client.MergeFrom(original)); err != nil {
|
if err := r.Status().Patch(ctx, autoscalingRunnerSet, client.MergeFrom(original)); err != nil {
|
||||||
log.Error(err, "Failed to patch autoscaling runner set status")
|
log.Error(err, "Failed to patch autoscaling runner set status")
|
||||||
|
|
|
||||||
|
|
@ -837,111 +837,6 @@ var _ = Describe("Test AutoScalingRunnerSet controller", Ordered, func() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Context("When updating an AutoscalingRunnerSet with running or pending jobs", func() {
|
|
||||||
It("It should wait for running and pending jobs to finish before applying the update.", func() {
|
|
||||||
// Wait till the listener is created
|
|
||||||
listener := new(v1alpha1.AutoscalingListener)
|
|
||||||
Eventually(
|
|
||||||
func() error {
|
|
||||||
return k8sClient.Get(ctx, client.ObjectKey{Name: scaleSetListenerName(autoscalingRunnerSet), Namespace: autoscalingRunnerSet.Namespace}, listener)
|
|
||||||
},
|
|
||||||
autoscalingRunnerSetTestTimeout,
|
|
||||||
autoscalingRunnerSetTestInterval,
|
|
||||||
).Should(Succeed(), "Listener should be created")
|
|
||||||
|
|
||||||
// Wait till the ephemeral runner set is created
|
|
||||||
Eventually(
|
|
||||||
func() (int, error) {
|
|
||||||
runnerSetList := new(v1alpha1.EphemeralRunnerSetList)
|
|
||||||
err := k8sClient.List(ctx, runnerSetList, client.InNamespace(autoscalingRunnerSet.Namespace))
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return len(runnerSetList.Items), nil
|
|
||||||
},
|
|
||||||
autoscalingRunnerSetTestTimeout,
|
|
||||||
autoscalingRunnerSetTestInterval,
|
|
||||||
).Should(BeEquivalentTo(1), "Only one EphemeralRunnerSet should be created")
|
|
||||||
|
|
||||||
runnerSetList := new(v1alpha1.EphemeralRunnerSetList)
|
|
||||||
err := k8sClient.List(ctx, runnerSetList, client.InNamespace(autoscalingRunnerSet.Namespace))
|
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to list EphemeralRunnerSet")
|
|
||||||
|
|
||||||
// Emulate running and pending jobs
|
|
||||||
runnerSet := runnerSetList.Items[0]
|
|
||||||
activeRunnerSet := runnerSet.DeepCopy()
|
|
||||||
activeRunnerSet.Status.CurrentReplicas = 6
|
|
||||||
activeRunnerSet.Status.FailedEphemeralRunners = 1
|
|
||||||
activeRunnerSet.Status.RunningEphemeralRunners = 2
|
|
||||||
activeRunnerSet.Status.PendingEphemeralRunners = 3
|
|
||||||
|
|
||||||
desiredStatus := v1alpha1.AutoscalingRunnerSetStatus{
|
|
||||||
CurrentRunners: activeRunnerSet.Status.CurrentReplicas,
|
|
||||||
Phase: v1alpha1.AutoscalingRunnerSetPhaseRunning,
|
|
||||||
PendingEphemeralRunners: activeRunnerSet.Status.PendingEphemeralRunners,
|
|
||||||
RunningEphemeralRunners: activeRunnerSet.Status.RunningEphemeralRunners,
|
|
||||||
FailedEphemeralRunners: activeRunnerSet.Status.FailedEphemeralRunners,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = k8sClient.Status().Patch(ctx, activeRunnerSet, 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")
|
|
||||||
|
|
||||||
// Patch the AutoScalingRunnerSet image which should trigger
|
|
||||||
// the recreation of the Listener and EphemeralRunnerSet
|
|
||||||
patched := autoscalingRunnerSet.DeepCopy()
|
|
||||||
if patched.Annotations == nil {
|
|
||||||
patched.Annotations = make(map[string]string)
|
|
||||||
}
|
|
||||||
patched.Annotations[annotationKeyIntegrityHash] = "testgroup2"
|
|
||||||
patched.Spec.Template.Spec = corev1.PodSpec{
|
|
||||||
Containers: []corev1.Container{
|
|
||||||
{
|
|
||||||
Name: "runner",
|
|
||||||
Image: "ghcr.io/actions/abcd:1.1.1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err = k8sClient.Patch(ctx, patched, client.MergeFrom(autoscalingRunnerSet))
|
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to patch AutoScalingRunnerSet")
|
|
||||||
autoscalingRunnerSet = patched.DeepCopy()
|
|
||||||
|
|
||||||
// The EphemeralRunnerSet should not be recreated
|
|
||||||
Consistently(
|
|
||||||
func() (string, error) {
|
|
||||||
runnerSetList := new(v1alpha1.EphemeralRunnerSetList)
|
|
||||||
err := k8sClient.List(ctx, runnerSetList, client.InNamespace(autoscalingRunnerSet.Namespace))
|
|
||||||
Expect(err).NotTo(HaveOccurred(), "failed to fetch AutoScalingRunnerSet")
|
|
||||||
return runnerSetList.Items[0].Name, nil
|
|
||||||
},
|
|
||||||
autoscalingRunnerSetTestTimeout,
|
|
||||||
autoscalingRunnerSetTestInterval,
|
|
||||||
).Should(Equal(activeRunnerSet.Name), "The EphemeralRunnerSet should not be recreated")
|
|
||||||
|
|
||||||
// The listener should not be recreated
|
|
||||||
Consistently(
|
|
||||||
func() error {
|
|
||||||
return k8sClient.Get(ctx, client.ObjectKey{Name: scaleSetListenerName(autoscalingRunnerSet), Namespace: autoscalingRunnerSet.Namespace}, listener)
|
|
||||||
},
|
|
||||||
autoscalingRunnerSetTestTimeout,
|
|
||||||
autoscalingRunnerSetTestInterval,
|
|
||||||
).ShouldNot(Succeed(), "Listener should not be recreated")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
It("Should update Status on EphemeralRunnerSet status Update", func() {
|
It("Should update Status on EphemeralRunnerSet status Update", func() {
|
||||||
ars := new(v1alpha1.AutoscalingRunnerSet)
|
ars := new(v1alpha1.AutoscalingRunnerSet)
|
||||||
Eventually(
|
Eventually(
|
||||||
|
|
@ -978,17 +873,10 @@ var _ = Describe("Test AutoScalingRunnerSet controller", Ordered, func() {
|
||||||
|
|
||||||
runnerSet := runnerSetList.Items[0]
|
runnerSet := runnerSetList.Items[0]
|
||||||
statusUpdate := runnerSet.DeepCopy()
|
statusUpdate := runnerSet.DeepCopy()
|
||||||
statusUpdate.Status.CurrentReplicas = 6
|
statusUpdate.Status.Phase = v1alpha1.EphemeralRunnerSetPhaseRunning
|
||||||
statusUpdate.Status.FailedEphemeralRunners = 1
|
|
||||||
statusUpdate.Status.RunningEphemeralRunners = 2
|
|
||||||
statusUpdate.Status.PendingEphemeralRunners = 3
|
|
||||||
|
|
||||||
desiredStatus := v1alpha1.AutoscalingRunnerSetStatus{
|
desiredStatus := v1alpha1.AutoscalingRunnerSetStatus{
|
||||||
CurrentRunners: statusUpdate.Status.CurrentReplicas,
|
Phase: v1alpha1.AutoscalingRunnerSetPhaseRunning,
|
||||||
Phase: v1alpha1.AutoscalingRunnerSetPhaseRunning,
|
|
||||||
PendingEphemeralRunners: statusUpdate.Status.PendingEphemeralRunners,
|
|
||||||
RunningEphemeralRunners: statusUpdate.Status.RunningEphemeralRunners,
|
|
||||||
FailedEphemeralRunners: statusUpdate.Status.FailedEphemeralRunners,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := k8sClient.Status().Patch(ctx, statusUpdate, client.MergeFrom(&runnerSet))
|
err := k8sClient.Status().Patch(ctx, statusUpdate, client.MergeFrom(&runnerSet))
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
||||||
|
"github.com/actions/actions-runner-controller/controllers/actions.github.com/metrics"
|
||||||
|
"github.com/actions/actions-runner-controller/github/actions"
|
||||||
"github.com/actions/scaleset"
|
"github.com/actions/scaleset"
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
|
@ -46,11 +49,19 @@ const (
|
||||||
// EphemeralRunnerReconciler reconciles a EphemeralRunner object
|
// EphemeralRunnerReconciler reconciles a EphemeralRunner object
|
||||||
type EphemeralRunnerReconciler struct {
|
type EphemeralRunnerReconciler struct {
|
||||||
client.Client
|
client.Client
|
||||||
Log logr.Logger
|
Log logr.Logger
|
||||||
Scheme *runtime.Scheme
|
Scheme *runtime.Scheme
|
||||||
|
PublishMetrics bool
|
||||||
ResourceBuilder
|
ResourceBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ephemeralRunnerPhaseMetrics = struct {
|
||||||
|
sync.Mutex
|
||||||
|
phases map[types.NamespacedName]v1alpha1.EphemeralRunnerPhase
|
||||||
|
}{
|
||||||
|
phases: map[types.NamespacedName]v1alpha1.EphemeralRunnerPhase{},
|
||||||
|
}
|
||||||
|
|
||||||
// precompute backoff durations for failed ephemeral runners
|
// precompute backoff durations for failed ephemeral runners
|
||||||
// the len(failedRunnerBackoff) must be equal to maxFailures + 1
|
// the len(failedRunnerBackoff) must be equal to maxFailures + 1
|
||||||
var failedRunnerBackoff = []time.Duration{
|
var failedRunnerBackoff = []time.Duration{
|
||||||
|
|
@ -86,6 +97,8 @@ func (r *EphemeralRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||||
original := ephemeralRunner.DeepCopy()
|
original := ephemeralRunner.DeepCopy()
|
||||||
|
|
||||||
if !ephemeralRunner.DeletionTimestamp.IsZero() {
|
if !ephemeralRunner.DeletionTimestamp.IsZero() {
|
||||||
|
r.publishEphemeralRunnerPhaseMetric(&ephemeralRunner, "", log)
|
||||||
|
|
||||||
if !controllerutil.ContainsFinalizer(&ephemeralRunner, ephemeralRunnerFinalizerName) {
|
if !controllerutil.ContainsFinalizer(&ephemeralRunner, ephemeralRunnerFinalizerName) {
|
||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -142,6 +155,8 @@ func (r *EphemeralRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.publishEphemeralRunnerPhaseMetric(&ephemeralRunner, ephemeralRunner.Status.Phase, log)
|
||||||
|
|
||||||
if ephemeralRunner.IsDone() {
|
if ephemeralRunner.IsDone() {
|
||||||
log.Info("Cleaning up resources after after ephemeral runner termination", "phase", ephemeralRunner.Status.Phase)
|
log.Info("Cleaning up resources after after ephemeral runner termination", "phase", ephemeralRunner.Status.Phase)
|
||||||
err := r.cleanupResources(ctx, &ephemeralRunner, log)
|
err := r.cleanupResources(ctx, &ephemeralRunner, log)
|
||||||
|
|
@ -337,6 +352,10 @@ func (r *EphemeralRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||||
// If the runner container exits with 0, we assume that the runner has finished successfully.
|
// If the runner container exits with 0, we assume that the runner has finished successfully.
|
||||||
// If side-car container exits with non-zero, it shouldn't affect the runner. Runner exit code
|
// If side-car container exits with non-zero, it shouldn't affect the runner. Runner exit code
|
||||||
// drives the controller's inference of whether the job has succeeded or failed.
|
// drives the controller's inference of whether the job has succeeded or failed.
|
||||||
|
if err := r.markAsSucceeded(ctx, &ephemeralRunner, pod, log); err != nil {
|
||||||
|
log.Error(err, "Failed to set ephemeral runner to phase Succeeded")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
if err := r.Delete(ctx, &ephemeralRunner); err != nil {
|
if err := r.Delete(ctx, &ephemeralRunner); err != nil {
|
||||||
log.Error(err, "Failed to delete ephemeral runner after successful completion")
|
log.Error(err, "Failed to delete ephemeral runner after successful completion")
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
|
|
@ -390,6 +409,10 @@ func (r *EphemeralRunnerReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||||
|
|
||||||
default: // succeeded
|
default: // succeeded
|
||||||
log.Info("Ephemeral runner has finished successfully, deleting ephemeral runner", "exitCode", cs.State.Terminated.ExitCode)
|
log.Info("Ephemeral runner has finished successfully, deleting ephemeral runner", "exitCode", cs.State.Terminated.ExitCode)
|
||||||
|
if err := r.markAsSucceeded(ctx, &ephemeralRunner, pod, log); err != nil {
|
||||||
|
log.Error(err, "Failed to set ephemeral runner to phase Succeeded")
|
||||||
|
return ctrl.Result{}, err
|
||||||
|
}
|
||||||
if err := r.Delete(ctx, &ephemeralRunner); err != nil {
|
if err := r.Delete(ctx, &ephemeralRunner); err != nil {
|
||||||
log.Error(err, "Failed to delete ephemeral runner after successful completion")
|
log.Error(err, "Failed to delete ephemeral runner after successful completion")
|
||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
|
|
@ -583,6 +606,7 @@ func (r *EphemeralRunnerReconciler) markAsFailed(ctx context.Context, ephemeralR
|
||||||
if err := r.Status().Patch(ctx, ephemeralRunner, client.MergeFrom(original)); err != nil {
|
if err := r.Status().Patch(ctx, ephemeralRunner, client.MergeFrom(original)); err != nil {
|
||||||
return fmt.Errorf("failed to update ephemeral runner status Phase/Message: %w", err)
|
return fmt.Errorf("failed to update ephemeral runner status Phase/Message: %w", err)
|
||||||
}
|
}
|
||||||
|
r.publishEphemeralRunnerPhaseMetric(ephemeralRunner, ephemeralRunner.Status.Phase, log)
|
||||||
|
|
||||||
log.Info("Removing the runner from the service")
|
log.Info("Removing the runner from the service")
|
||||||
if err := r.deleteRunnerFromService(ctx, ephemeralRunner, log); err != nil {
|
if err := r.deleteRunnerFromService(ctx, ephemeralRunner, log); err != nil {
|
||||||
|
|
@ -604,6 +628,7 @@ func (r *EphemeralRunnerReconciler) markAsOutdated(ctx context.Context, ephemera
|
||||||
if err := r.Status().Patch(ctx, ephemeralRunner, client.MergeFrom(original)); err != nil {
|
if err := r.Status().Patch(ctx, ephemeralRunner, client.MergeFrom(original)); err != nil {
|
||||||
return fmt.Errorf("failed to update ephemeral runner status Phase/Message: %w", err)
|
return fmt.Errorf("failed to update ephemeral runner status Phase/Message: %w", err)
|
||||||
}
|
}
|
||||||
|
r.publishEphemeralRunnerPhaseMetric(ephemeralRunner, ephemeralRunner.Status.Phase, log)
|
||||||
|
|
||||||
log.Info("Removing the runner from the service")
|
log.Info("Removing the runner from the service")
|
||||||
if err := r.deleteRunnerFromService(ctx, ephemeralRunner, log); err != nil {
|
if err := r.deleteRunnerFromService(ctx, ephemeralRunner, log); err != nil {
|
||||||
|
|
@ -612,6 +637,23 @@ func (r *EphemeralRunnerReconciler) markAsOutdated(ctx context.Context, ephemera
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *EphemeralRunnerReconciler) markAsSucceeded(ctx context.Context, ephemeralRunner *v1alpha1.EphemeralRunner, pod *corev1.Pod, log logr.Logger) error {
|
||||||
|
log.Info("Updating ephemeral runner status to Succeeded")
|
||||||
|
|
||||||
|
original := ephemeralRunner.DeepCopy()
|
||||||
|
ephemeralRunner.Status.Phase = v1alpha1.EphemeralRunnerPhaseSucceeded
|
||||||
|
ephemeralRunner.Status.Ready = false
|
||||||
|
ephemeralRunner.Status.Reason = pod.Status.Reason
|
||||||
|
ephemeralRunner.Status.Message = pod.Status.Message
|
||||||
|
if err := r.Status().Patch(ctx, ephemeralRunner, client.MergeFrom(original)); err != nil {
|
||||||
|
return fmt.Errorf("failed to update ephemeral runner status Phase/Message: %w", err)
|
||||||
|
}
|
||||||
|
r.publishEphemeralRunnerPhaseMetric(ephemeralRunner, ephemeralRunner.Status.Phase, log)
|
||||||
|
|
||||||
|
log.Info("EphemeralRunner is marked as Succeeded")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// deletePodAsFailed is responsible for deleting the pod and updating the .Status.Failures for tracking failure count.
|
// deletePodAsFailed is responsible for deleting the pod and updating the .Status.Failures for tracking failure count.
|
||||||
// It should not be responsible for setting the status to Failed.
|
// It should not be responsible for setting the status to Failed.
|
||||||
//
|
//
|
||||||
|
|
@ -835,11 +877,61 @@ func (r *EphemeralRunnerReconciler) updateRunStatusFromPod(ctx context.Context,
|
||||||
if err := r.Status().Patch(ctx, ephemeralRunner, client.MergeFrom(original)); err != nil {
|
if err := r.Status().Patch(ctx, ephemeralRunner, client.MergeFrom(original)); err != nil {
|
||||||
return fmt.Errorf("failed to update runner status for Phase/Reason/Message/Ready: %w", err)
|
return fmt.Errorf("failed to update runner status for Phase/Reason/Message/Ready: %w", err)
|
||||||
}
|
}
|
||||||
|
r.publishEphemeralRunnerPhaseMetric(ephemeralRunner, ephemeralRunner.Status.Phase, log)
|
||||||
|
|
||||||
log.Info("Updated ephemeral runner status")
|
log.Info("Updated ephemeral runner status")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *EphemeralRunnerReconciler) publishEphemeralRunnerPhaseMetric(ephemeralRunner *v1alpha1.EphemeralRunner, phase v1alpha1.EphemeralRunnerPhase, log logr.Logger) {
|
||||||
|
if !r.PublishMetrics {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
commonLabels, err := ephemeralRunnerMetricLabels(ephemeralRunner)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err, "Failed to build ephemeral runner metric labels")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
key := types.NamespacedName{Namespace: ephemeralRunner.Namespace, Name: ephemeralRunner.Name}
|
||||||
|
|
||||||
|
ephemeralRunnerPhaseMetrics.Lock()
|
||||||
|
defer ephemeralRunnerPhaseMetrics.Unlock()
|
||||||
|
|
||||||
|
previousPhase, ok := ephemeralRunnerPhaseMetrics.phases[key]
|
||||||
|
if ok && previousPhase == phase {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
metrics.SubEphemeralRunner(commonLabels, previousPhase)
|
||||||
|
}
|
||||||
|
|
||||||
|
if phase == "" {
|
||||||
|
delete(ephemeralRunnerPhaseMetrics.phases, key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
metrics.AddEphemeralRunner(commonLabels, phase)
|
||||||
|
ephemeralRunnerPhaseMetrics.phases[key] = phase
|
||||||
|
}
|
||||||
|
|
||||||
|
func ephemeralRunnerMetricLabels(ephemeralRunner *v1alpha1.EphemeralRunner) (metrics.CommonLabels, error) {
|
||||||
|
parsedURL, err := actions.ParseGitHubConfigFromURL(ephemeralRunner.Spec.GitHubConfigURL)
|
||||||
|
if err != nil {
|
||||||
|
return metrics.CommonLabels{}, fmt.Errorf("github config URL is invalid: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return metrics.CommonLabels{
|
||||||
|
Name: ephemeralRunner.Labels[LabelKeyGitHubScaleSetName],
|
||||||
|
Namespace: ephemeralRunner.Labels[LabelKeyGitHubScaleSetNamespace],
|
||||||
|
Repository: parsedURL.Repository,
|
||||||
|
Organization: parsedURL.Organization,
|
||||||
|
Enterprise: parsedURL.Enterprise,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *EphemeralRunnerReconciler) deleteRunnerFromService(ctx context.Context, ephemeralRunner *v1alpha1.EphemeralRunner, log logr.Logger) error {
|
func (r *EphemeralRunnerReconciler) deleteRunnerFromService(ctx context.Context, ephemeralRunner *v1alpha1.EphemeralRunner, log logr.Logger) error {
|
||||||
client, err := r.GetActionsService(ctx, ephemeralRunner)
|
client, err := r.GetActionsService(ctx, ephemeralRunner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
||||||
"github.com/actions/actions-runner-controller/controllers/actions.github.com/metrics"
|
|
||||||
"github.com/actions/actions-runner-controller/controllers/actions.github.com/multiclient"
|
"github.com/actions/actions-runner-controller/controllers/actions.github.com/multiclient"
|
||||||
"github.com/actions/actions-runner-controller/github/actions"
|
|
||||||
"github.com/actions/scaleset"
|
"github.com/actions/scaleset"
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
"go.uber.org/multierr"
|
"go.uber.org/multierr"
|
||||||
|
|
@ -51,9 +49,8 @@ const (
|
||||||
// EphemeralRunnerSetReconciler reconciles a EphemeralRunnerSet object
|
// EphemeralRunnerSetReconciler reconciles a EphemeralRunnerSet object
|
||||||
type EphemeralRunnerSetReconciler struct {
|
type EphemeralRunnerSetReconciler struct {
|
||||||
client.Client
|
client.Client
|
||||||
Log logr.Logger
|
Log logr.Logger
|
||||||
Scheme *runtime.Scheme
|
Scheme *runtime.Scheme
|
||||||
PublishMetrics bool
|
|
||||||
ResourceBuilder
|
ResourceBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,29 +202,6 @@ func (r *EphemeralRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl.R
|
||||||
"deleting", len(ephemeralRunnersByState.deleting),
|
"deleting", len(ephemeralRunnersByState.deleting),
|
||||||
)
|
)
|
||||||
|
|
||||||
if r.PublishMetrics {
|
|
||||||
githubConfigURL := ephemeralRunnerSet.Spec.EphemeralRunnerSpec.GitHubConfigURL
|
|
||||||
parsedURL, err := actions.ParseGitHubConfigFromURL(githubConfigURL)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err, "Github Config URL is invalid", "URL", githubConfigURL)
|
|
||||||
// stop reconciling on this object
|
|
||||||
return ctrl.Result{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
metrics.SetEphemeralRunnerCountsByStatus(
|
|
||||||
metrics.CommonLabels{
|
|
||||||
Name: ephemeralRunnerSet.Labels[LabelKeyGitHubScaleSetName],
|
|
||||||
Namespace: ephemeralRunnerSet.Labels[LabelKeyGitHubScaleSetNamespace],
|
|
||||||
Repository: parsedURL.Repository,
|
|
||||||
Organization: parsedURL.Organization,
|
|
||||||
Enterprise: parsedURL.Enterprise,
|
|
||||||
},
|
|
||||||
len(ephemeralRunnersByState.pending),
|
|
||||||
len(ephemeralRunnersByState.running),
|
|
||||||
len(ephemeralRunnersByState.failed),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
total := ephemeralRunnersByState.scaleTotal()
|
total := ephemeralRunnersByState.scaleTotal()
|
||||||
if ephemeralRunnerSet.Spec.PatchID == 0 || ephemeralRunnerSet.Spec.PatchID != ephemeralRunnersByState.latestPatchID {
|
if ephemeralRunnerSet.Spec.PatchID == 0 || ephemeralRunnerSet.Spec.PatchID != ephemeralRunnersByState.latestPatchID {
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
@ -272,7 +246,6 @@ func (r *EphemeralRunnerSetReconciler) Reconcile(ctx context.Context, req ctrl.R
|
||||||
|
|
||||||
func (r *EphemeralRunnerSetReconciler) updateStatus(ctx context.Context, ephemeralRunnerSet *v1alpha1.EphemeralRunnerSet, state *ephemeralRunnersByState, log logr.Logger) error {
|
func (r *EphemeralRunnerSetReconciler) updateStatus(ctx context.Context, ephemeralRunnerSet *v1alpha1.EphemeralRunnerSet, state *ephemeralRunnersByState, log logr.Logger) error {
|
||||||
original := ephemeralRunnerSet.DeepCopy()
|
original := ephemeralRunnerSet.DeepCopy()
|
||||||
total := state.scaleTotal()
|
|
||||||
var phase v1alpha1.EphemeralRunnerSetPhase
|
var phase v1alpha1.EphemeralRunnerSetPhase
|
||||||
switch {
|
switch {
|
||||||
case len(state.outdated) > 0:
|
case len(state.outdated) > 0:
|
||||||
|
|
@ -283,11 +256,7 @@ func (r *EphemeralRunnerSetReconciler) updateStatus(ctx context.Context, ephemer
|
||||||
phase = ephemeralRunnerSet.Status.Phase
|
phase = ephemeralRunnerSet.Status.Phase
|
||||||
}
|
}
|
||||||
desiredStatus := v1alpha1.EphemeralRunnerSetStatus{
|
desiredStatus := v1alpha1.EphemeralRunnerSetStatus{
|
||||||
CurrentReplicas: total,
|
Phase: phase,
|
||||||
Phase: phase,
|
|
||||||
PendingEphemeralRunners: len(state.pending),
|
|
||||||
RunningEphemeralRunners: len(state.running),
|
|
||||||
FailedEphemeralRunners: len(state.failed),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the status if needed.
|
// Update the status if needed.
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,21 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/actions/actions-runner-controller/controllers/actions.github.com/metrics"
|
||||||
|
"github.com/actions/actions-runner-controller/github/actions"
|
||||||
|
"github.com/actions/scaleset"
|
||||||
|
prometheusdto "github.com/prometheus/client_model/go"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
controllerMetrics "sigs.k8s.io/controller-runtime/pkg/metrics"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
@ -34,10 +41,92 @@ const (
|
||||||
ephemeralRunnerSetTestInterval = time.Millisecond * 250
|
ephemeralRunnerSetTestInterval = time.Millisecond * 250
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var registerActionsGithubMetricsForTest sync.Once
|
||||||
|
|
||||||
func TestPrecomputedConstants(t *testing.T) {
|
func TestPrecomputedConstants(t *testing.T) {
|
||||||
require.Equal(t, len(failedRunnerBackoff), maxFailures+1)
|
require.Equal(t, len(failedRunnerBackoff), maxFailures+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func expectEphemeralRunnerPhase(ctx context.Context, ephemeralRunner *v1alpha1.EphemeralRunner, phase v1alpha1.EphemeralRunnerPhase) {
|
||||||
|
updated := new(v1alpha1.EphemeralRunner)
|
||||||
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, updated)
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "failed to get ephemeral runner")
|
||||||
|
Expect(updated.Status.Phase).To(Equal(phase))
|
||||||
|
}
|
||||||
|
|
||||||
|
func expectEphemeralRunnerPhaseMetric(ephemeralRunner *v1alpha1.EphemeralRunner, phase v1alpha1.EphemeralRunnerPhase, expected float64) {
|
||||||
|
metricName := ephemeralRunnerPhaseMetricName(phase)
|
||||||
|
Expect(metricName).NotTo(BeEmpty(), "unexpected ephemeral runner phase")
|
||||||
|
|
||||||
|
parsedURL, err := actions.ParseGitHubConfigFromURL(ephemeralRunner.Spec.GitHubConfigURL)
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "failed to parse GitHub config URL")
|
||||||
|
|
||||||
|
value, err := ephemeralRunnerPhaseMetricValue(metricName, map[string]string{
|
||||||
|
"name": ephemeralRunner.Labels[LabelKeyGitHubScaleSetName],
|
||||||
|
"namespace": ephemeralRunner.Labels[LabelKeyGitHubScaleSetNamespace],
|
||||||
|
"repository": parsedURL.Repository,
|
||||||
|
"organization": parsedURL.Organization,
|
||||||
|
"enterprise": parsedURL.Enterprise,
|
||||||
|
})
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "failed to gather ephemeral runner phase metrics")
|
||||||
|
Expect(value).To(Equal(expected))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ephemeralRunnerPhaseMetricName(phase v1alpha1.EphemeralRunnerPhase) string {
|
||||||
|
switch phase {
|
||||||
|
case v1alpha1.EphemeralRunnerPhasePending:
|
||||||
|
return "gha_controller_pending_ephemeral_runners"
|
||||||
|
case v1alpha1.EphemeralRunnerPhaseRunning:
|
||||||
|
return "gha_controller_running_ephemeral_runners"
|
||||||
|
case v1alpha1.EphemeralRunnerPhaseSucceeded:
|
||||||
|
return "gha_controller_succeeded_ephemeral_runners"
|
||||||
|
case v1alpha1.EphemeralRunnerPhaseFailed:
|
||||||
|
return "gha_controller_failed_ephemeral_runners"
|
||||||
|
case v1alpha1.EphemeralRunnerPhaseOutdated:
|
||||||
|
return "gha_controller_outdated_ephemeral_runners"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ephemeralRunnerPhaseMetricValue(metricName string, labels map[string]string) (float64, error) {
|
||||||
|
metricFamilies, err := controllerMetrics.Registry.Gather()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, metricFamily := range metricFamilies {
|
||||||
|
if metricFamily.GetName() != metricName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, metric := range metricFamily.GetMetric() {
|
||||||
|
if metricHasLabels(metric, labels) {
|
||||||
|
if metric.GetGauge() == nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return metric.GetGauge().GetValue(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func metricHasLabels(metric *prometheusdto.Metric, labels map[string]string) bool {
|
||||||
|
metricLabels := map[string]string{}
|
||||||
|
for _, label := range metric.GetLabel() {
|
||||||
|
metricLabels[label.GetName()] = label.GetValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, value := range labels {
|
||||||
|
if metricLabels[name] != value {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
||||||
var ctx context.Context
|
var ctx context.Context
|
||||||
var mgr ctrl.Manager
|
var mgr ctrl.Manager
|
||||||
|
|
@ -133,20 +222,20 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
||||||
ephemeralRunnerSetTestInterval,
|
ephemeralRunnerSetTestInterval,
|
||||||
).Should(BeEquivalentTo(0), "No EphemeralRunner should be created")
|
).Should(BeEquivalentTo(0), "No EphemeralRunner should be created")
|
||||||
|
|
||||||
// Check if the status stay 0
|
// Check if the status is initialized
|
||||||
Consistently(
|
Consistently(
|
||||||
func() (int, error) {
|
func() (v1alpha1.EphemeralRunnerSetPhase, error) {
|
||||||
runnerSet := new(v1alpha1.EphemeralRunnerSet)
|
runnerSet := new(v1alpha1.EphemeralRunnerSet)
|
||||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunnerSet.Name, Namespace: ephemeralRunnerSet.Namespace}, runnerSet)
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunnerSet.Name, Namespace: ephemeralRunnerSet.Namespace}, runnerSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return int(runnerSet.Status.CurrentReplicas), nil
|
return runnerSet.Status.Phase, nil
|
||||||
},
|
},
|
||||||
ephemeralRunnerSetTestTimeout,
|
ephemeralRunnerSetTestTimeout,
|
||||||
ephemeralRunnerSetTestInterval,
|
ephemeralRunnerSetTestInterval,
|
||||||
).Should(BeEquivalentTo(0), "EphemeralRunnerSet status should be 0")
|
).Should(BeEquivalentTo(v1alpha1.EphemeralRunnerSetPhaseRunning), "EphemeralRunnerSet status should be running")
|
||||||
|
|
||||||
// Scaling up the EphemeralRunnerSet
|
// Scaling up the EphemeralRunnerSet
|
||||||
updated := created.DeepCopy()
|
updated := created.DeepCopy()
|
||||||
|
|
@ -187,20 +276,20 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
||||||
ephemeralRunnerSetTestInterval,
|
ephemeralRunnerSetTestInterval,
|
||||||
).Should(BeEquivalentTo(5), "5 EphemeralRunner should be created")
|
).Should(BeEquivalentTo(5), "5 EphemeralRunner should be created")
|
||||||
|
|
||||||
// Check if the status is updated
|
// Check if the status stays running
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (int, error) {
|
func() (v1alpha1.EphemeralRunnerSetPhase, error) {
|
||||||
runnerSet := new(v1alpha1.EphemeralRunnerSet)
|
runnerSet := new(v1alpha1.EphemeralRunnerSet)
|
||||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunnerSet.Name, Namespace: ephemeralRunnerSet.Namespace}, runnerSet)
|
err := k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunnerSet.Name, Namespace: ephemeralRunnerSet.Namespace}, runnerSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return int(runnerSet.Status.CurrentReplicas), nil
|
return runnerSet.Status.Phase, nil
|
||||||
},
|
},
|
||||||
ephemeralRunnerSetTestTimeout,
|
ephemeralRunnerSetTestTimeout,
|
||||||
ephemeralRunnerSetTestInterval,
|
ephemeralRunnerSetTestInterval,
|
||||||
).Should(BeEquivalentTo(5), "EphemeralRunnerSet status should be 5")
|
).Should(BeEquivalentTo(v1alpha1.EphemeralRunnerSetPhaseRunning), "EphemeralRunnerSet status should be running")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -1184,11 +1273,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
||||||
).Should(BeTrue(), "Failed to eventually update to one pending, one running and one failed")
|
).Should(BeTrue(), "Failed to eventually update to one pending, one running and one failed")
|
||||||
|
|
||||||
desiredStatus := v1alpha1.EphemeralRunnerSetStatus{
|
desiredStatus := v1alpha1.EphemeralRunnerSetStatus{
|
||||||
Phase: v1alpha1.EphemeralRunnerSetPhaseRunning,
|
Phase: v1alpha1.EphemeralRunnerSetPhaseRunning,
|
||||||
CurrentReplicas: 3,
|
|
||||||
PendingEphemeralRunners: 1,
|
|
||||||
RunningEphemeralRunners: 1,
|
|
||||||
FailedEphemeralRunners: 1,
|
|
||||||
}
|
}
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (v1alpha1.EphemeralRunnerSetStatus, error) {
|
func() (v1alpha1.EphemeralRunnerSetStatus, error) {
|
||||||
|
|
@ -1227,11 +1312,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
||||||
).Should(BeEquivalentTo(1), "Failed to eventually scale down")
|
).Should(BeEquivalentTo(1), "Failed to eventually scale down")
|
||||||
|
|
||||||
desiredStatus = v1alpha1.EphemeralRunnerSetStatus{
|
desiredStatus = v1alpha1.EphemeralRunnerSetStatus{
|
||||||
CurrentReplicas: 1,
|
Phase: v1alpha1.EphemeralRunnerSetPhaseRunning,
|
||||||
PendingEphemeralRunners: 0,
|
|
||||||
RunningEphemeralRunners: 0,
|
|
||||||
FailedEphemeralRunners: 1,
|
|
||||||
Phase: v1alpha1.EphemeralRunnerSetPhaseRunning,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Eventually(
|
Eventually(
|
||||||
|
|
@ -1251,11 +1332,7 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
||||||
Expect(err).To(BeNil(), "Failed to delete failed ephemeral runner")
|
Expect(err).To(BeNil(), "Failed to delete failed ephemeral runner")
|
||||||
|
|
||||||
desiredStatus = v1alpha1.EphemeralRunnerSetStatus{
|
desiredStatus = v1alpha1.EphemeralRunnerSetStatus{
|
||||||
CurrentReplicas: 0,
|
Phase: v1alpha1.EphemeralRunnerSetPhaseRunning,
|
||||||
PendingEphemeralRunners: 0,
|
|
||||||
RunningEphemeralRunners: 0,
|
|
||||||
FailedEphemeralRunners: 0,
|
|
||||||
Phase: v1alpha1.EphemeralRunnerSetPhaseRunning,
|
|
||||||
}
|
}
|
||||||
Eventually(
|
Eventually(
|
||||||
func() (v1alpha1.EphemeralRunnerSetStatus, error) {
|
func() (v1alpha1.EphemeralRunnerSetStatus, error) {
|
||||||
|
|
@ -1273,6 +1350,148 @@ var _ = Describe("Test EphemeralRunnerSet controller", func() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var _ = Describe("EphemeralRunner phase metrics", func() {
|
||||||
|
var ctx context.Context
|
||||||
|
var autoscalingNS *corev1.Namespace
|
||||||
|
var mgr ctrl.Manager
|
||||||
|
var configSecret *corev1.Secret
|
||||||
|
var controller *EphemeralRunnerReconciler
|
||||||
|
var ephemeralRunner *v1alpha1.EphemeralRunner
|
||||||
|
var request ctrl.Request
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
registerActionsGithubMetricsForTest.Do(func() {
|
||||||
|
metrics.RegisterMetrics()
|
||||||
|
})
|
||||||
|
|
||||||
|
ephemeralRunnerPhaseMetrics.Lock()
|
||||||
|
ephemeralRunnerPhaseMetrics.phases = map[types.NamespacedName]v1alpha1.EphemeralRunnerPhase{}
|
||||||
|
ephemeralRunnerPhaseMetrics.Unlock()
|
||||||
|
|
||||||
|
ctx = context.Background()
|
||||||
|
autoscalingNS, mgr = createNamespace(GinkgoT(), k8sClient)
|
||||||
|
configSecret = createDefaultSecret(GinkgoT(), k8sClient, autoscalingNS.Name)
|
||||||
|
|
||||||
|
controller = &EphemeralRunnerReconciler{
|
||||||
|
Client: k8sClient,
|
||||||
|
Scheme: mgr.GetScheme(),
|
||||||
|
Log: logf.Log,
|
||||||
|
PublishMetrics: true,
|
||||||
|
ResourceBuilder: ResourceBuilder{
|
||||||
|
SecretResolver: secretresolver.New(k8sClient, fake.NewMultiClient(
|
||||||
|
fake.WithClient(
|
||||||
|
fake.NewClient(
|
||||||
|
fake.WithGenerateJitRunnerConfig(
|
||||||
|
&scaleset.RunnerScaleSetJitRunnerConfig{
|
||||||
|
Runner: &scaleset.RunnerReference{ID: 100, Name: "test-runner"},
|
||||||
|
EncodedJITConfig: "fake-jit-config",
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ephemeralRunner = &v1alpha1.EphemeralRunner{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-runner",
|
||||||
|
Namespace: autoscalingNS.Name,
|
||||||
|
Labels: map[string]string{
|
||||||
|
LabelKeyGitHubScaleSetName: "test-scale-set",
|
||||||
|
LabelKeyGitHubScaleSetNamespace: autoscalingNS.Name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: v1alpha1.EphemeralRunnerSpec{
|
||||||
|
GitHubConfigURL: "https://github.com/owner/repo",
|
||||||
|
GitHubConfigSecret: configSecret.Name,
|
||||||
|
RunnerScaleSetID: 100,
|
||||||
|
PodTemplateSpec: corev1.PodTemplateSpec{
|
||||||
|
Spec: corev1.PodSpec{
|
||||||
|
Containers: []corev1.Container{
|
||||||
|
{
|
||||||
|
Name: v1alpha1.EphemeralRunnerContainerName,
|
||||||
|
Image: "ghcr.io/actions/runner",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := k8sClient.Create(ctx, ephemeralRunner)
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "failed to create ephemeral runner")
|
||||||
|
|
||||||
|
request = ctrl.Request{NamespacedName: types.NamespacedName{Namespace: ephemeralRunner.Namespace, Name: ephemeralRunner.Name}}
|
||||||
|
})
|
||||||
|
|
||||||
|
It("publishes pending, running, and succeeded phase transitions", func() {
|
||||||
|
_, err := controller.Reconcile(ctx, request)
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "failed to reconcile ephemeral runner")
|
||||||
|
|
||||||
|
pod := new(corev1.Pod)
|
||||||
|
Eventually(func() error {
|
||||||
|
return k8sClient.Get(ctx, client.ObjectKey{Name: ephemeralRunner.Name, Namespace: ephemeralRunner.Namespace}, pod)
|
||||||
|
}, ephemeralRunnerSetTestTimeout, ephemeralRunnerSetTestInterval).Should(Succeed(), "expected ephemeral runner pod to be created")
|
||||||
|
|
||||||
|
podPending := pod.DeepCopy()
|
||||||
|
podPending.Status.Phase = corev1.PodPending
|
||||||
|
podPending.Status.ContainerStatuses = []corev1.ContainerStatus{
|
||||||
|
{
|
||||||
|
Name: v1alpha1.EphemeralRunnerContainerName,
|
||||||
|
State: corev1.ContainerState{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = k8sClient.Status().Patch(ctx, podPending, client.MergeFrom(pod))
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "failed to patch pod to pending")
|
||||||
|
|
||||||
|
_, err = controller.Reconcile(ctx, request)
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "failed to reconcile pending pod")
|
||||||
|
expectEphemeralRunnerPhase(ctx, ephemeralRunner, v1alpha1.EphemeralRunnerPhasePending)
|
||||||
|
expectEphemeralRunnerPhaseMetric(ephemeralRunner, v1alpha1.EphemeralRunnerPhasePending, 1)
|
||||||
|
expectEphemeralRunnerPhaseMetric(ephemeralRunner, v1alpha1.EphemeralRunnerPhaseRunning, 0)
|
||||||
|
|
||||||
|
podRunning := podPending.DeepCopy()
|
||||||
|
podRunning.Status.Phase = corev1.PodRunning
|
||||||
|
podRunning.Status.ContainerStatuses = []corev1.ContainerStatus{
|
||||||
|
{
|
||||||
|
Name: v1alpha1.EphemeralRunnerContainerName,
|
||||||
|
State: corev1.ContainerState{
|
||||||
|
Running: &corev1.ContainerStateRunning{StartedAt: metav1.Now()},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = k8sClient.Status().Patch(ctx, podRunning, client.MergeFrom(podPending))
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "failed to patch pod to running")
|
||||||
|
|
||||||
|
_, err = controller.Reconcile(ctx, request)
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "failed to reconcile running pod")
|
||||||
|
expectEphemeralRunnerPhase(ctx, ephemeralRunner, v1alpha1.EphemeralRunnerPhaseRunning)
|
||||||
|
expectEphemeralRunnerPhaseMetric(ephemeralRunner, v1alpha1.EphemeralRunnerPhasePending, 0)
|
||||||
|
expectEphemeralRunnerPhaseMetric(ephemeralRunner, v1alpha1.EphemeralRunnerPhaseRunning, 1)
|
||||||
|
|
||||||
|
podSucceeded := podRunning.DeepCopy()
|
||||||
|
podSucceeded.Status.Phase = corev1.PodSucceeded
|
||||||
|
podSucceeded.Status.ContainerStatuses = []corev1.ContainerStatus{
|
||||||
|
{
|
||||||
|
Name: v1alpha1.EphemeralRunnerContainerName,
|
||||||
|
State: corev1.ContainerState{
|
||||||
|
Terminated: &corev1.ContainerStateTerminated{ExitCode: 0},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = k8sClient.Status().Patch(ctx, podSucceeded, client.MergeFrom(podRunning))
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "failed to patch pod to succeeded")
|
||||||
|
|
||||||
|
_, err = controller.Reconcile(ctx, request)
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "failed to reconcile succeeded pod")
|
||||||
|
expectEphemeralRunnerPhase(ctx, ephemeralRunner, v1alpha1.EphemeralRunnerPhaseSucceeded)
|
||||||
|
expectEphemeralRunnerPhaseMetric(ephemeralRunner, v1alpha1.EphemeralRunnerPhaseRunning, 0)
|
||||||
|
expectEphemeralRunnerPhaseMetric(ephemeralRunner, v1alpha1.EphemeralRunnerPhaseSucceeded, 1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
var _ = Describe("Test EphemeralRunnerSet controller with proxy settings", func() {
|
var _ = Describe("Test EphemeralRunnerSet controller with proxy settings", func() {
|
||||||
var ctx context.Context
|
var ctx context.Context
|
||||||
var mgr ctrl.Manager
|
var mgr ctrl.Manager
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
||||||
)
|
)
|
||||||
|
|
@ -50,6 +51,14 @@ var (
|
||||||
},
|
},
|
||||||
labels,
|
labels,
|
||||||
)
|
)
|
||||||
|
succeededEphemeralRunners = prometheus.NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Subsystem: githubScaleSetControllerSubsystem,
|
||||||
|
Name: "succeeded_ephemeral_runners",
|
||||||
|
Help: "Number of ephemeral runners in a succeeded state.",
|
||||||
|
},
|
||||||
|
labels,
|
||||||
|
)
|
||||||
failedEphemeralRunners = prometheus.NewGaugeVec(
|
failedEphemeralRunners = prometheus.NewGaugeVec(
|
||||||
prometheus.GaugeOpts{
|
prometheus.GaugeOpts{
|
||||||
Subsystem: githubScaleSetControllerSubsystem,
|
Subsystem: githubScaleSetControllerSubsystem,
|
||||||
|
|
@ -58,6 +67,14 @@ var (
|
||||||
},
|
},
|
||||||
labels,
|
labels,
|
||||||
)
|
)
|
||||||
|
outdatedEphemeralRunners = prometheus.NewGaugeVec(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Subsystem: githubScaleSetControllerSubsystem,
|
||||||
|
Name: "outdated_ephemeral_runners",
|
||||||
|
Help: "Number of ephemeral runners in an outdated state.",
|
||||||
|
},
|
||||||
|
labels,
|
||||||
|
)
|
||||||
runningListeners = prometheus.NewGaugeVec(
|
runningListeners = prometheus.NewGaugeVec(
|
||||||
prometheus.GaugeOpts{
|
prometheus.GaugeOpts{
|
||||||
Subsystem: githubScaleSetControllerSubsystem,
|
Subsystem: githubScaleSetControllerSubsystem,
|
||||||
|
|
@ -72,15 +89,34 @@ func RegisterMetrics() {
|
||||||
metrics.Registry.MustRegister(
|
metrics.Registry.MustRegister(
|
||||||
pendingEphemeralRunners,
|
pendingEphemeralRunners,
|
||||||
runningEphemeralRunners,
|
runningEphemeralRunners,
|
||||||
|
succeededEphemeralRunners,
|
||||||
failedEphemeralRunners,
|
failedEphemeralRunners,
|
||||||
|
outdatedEphemeralRunners,
|
||||||
runningListeners,
|
runningListeners,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetEphemeralRunnerCountsByStatus(commonLabels CommonLabels, pending, running, failed int) {
|
func AddEphemeralRunner(commonLabels CommonLabels, phase v1alpha1.EphemeralRunnerPhase) {
|
||||||
pendingEphemeralRunners.With(commonLabels.labels()).Set(float64(pending))
|
updateEphemeralRunner(commonLabels, phase, 1)
|
||||||
runningEphemeralRunners.With(commonLabels.labels()).Set(float64(running))
|
}
|
||||||
failedEphemeralRunners.With(commonLabels.labels()).Set(float64(failed))
|
|
||||||
|
func SubEphemeralRunner(commonLabels CommonLabels, phase v1alpha1.EphemeralRunnerPhase) {
|
||||||
|
updateEphemeralRunner(commonLabels, phase, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateEphemeralRunner(commonLabels CommonLabels, phase v1alpha1.EphemeralRunnerPhase, delta float64) {
|
||||||
|
switch phase {
|
||||||
|
case v1alpha1.EphemeralRunnerPhasePending:
|
||||||
|
pendingEphemeralRunners.With(commonLabels.labels()).Add(delta)
|
||||||
|
case v1alpha1.EphemeralRunnerPhaseRunning:
|
||||||
|
runningEphemeralRunners.With(commonLabels.labels()).Add(delta)
|
||||||
|
case v1alpha1.EphemeralRunnerPhaseSucceeded:
|
||||||
|
succeededEphemeralRunners.With(commonLabels.labels()).Add(delta)
|
||||||
|
case v1alpha1.EphemeralRunnerPhaseFailed:
|
||||||
|
failedEphemeralRunners.With(commonLabels.labels()).Add(delta)
|
||||||
|
case v1alpha1.EphemeralRunnerPhaseOutdated:
|
||||||
|
outdatedEphemeralRunners.With(commonLabels.labels()).Add(delta)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddRunningListener(commonLabels CommonLabels) {
|
func AddRunningListener(commonLabels CommonLabels) {
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIDKjCCAhKgAwIBAgIUQr7R8yN5+2and6ucUOPF6oIbD44wDQYJKoZIhvcNAQEL
|
MIIDKjCCAhKgAwIBAgIUVy/UETGamzkzSYS3TortnzNWCekwDQYJKoZIhvcNAQEL
|
||||||
BQAwFzEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTI1MDIyODEyMDEzMFoXDTI3
|
BQAwFzEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTI2MDcxMzEzMjQwN1oXDTI5
|
||||||
MTEyNTEyMDEzMFowHzEdMBsGA1UEAwwUVGVzdCBJbnRlcm1lZGlhdGUgQ0EwggEi
|
MDQwODEzMjQwN1owHzEdMBsGA1UEAwwUVGVzdCBJbnRlcm1lZGlhdGUgQ0EwggEi
|
||||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDOGvN95wCkYO35qyJnf/RwTiDb
|
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDzbccB7wpLODrRW3IePtAmKk63
|
||||||
oEVaefKnZZny1JrO34MFjlAz8C/P5WwxNUzzbQLTPh5iTqFRU+vis6HPvV0HJEoI
|
8pVYb9yZZL5KjLjli+xpWURvS1N8X44NyU67nkArsO3UG3kq8KGYU03Dy5iCQmlT
|
||||||
wTfgBCZxcdY8fEIY96FGHLju3PzfxeJaVHyi+2cTtzU+oNp4OFF8huApjYXjaV4y
|
hXddmpNIAc56CF/vYBh7hzklrF1qFMgwHl48LsemiYfn+vizonzd+UmrKqhghDRy
|
||||||
pAirPbiiP/cgtcT4L5WErQi0aGZkq+1YqY2duNFNIGPTEcXV4iN4IhuD9dpqdKFg
|
SwNLnzSCWBgWwaJPyKlp9pUXpxmSjU+1ByRaLl5E2tmCA3ghdJPXayQeZz+nWcxv
|
||||||
H0wmZDgH+VE/5ACXovU8j5cxCKOJGxTVMKVZlvxPH3w69Z85x3o5AAnyxwo8E2zo
|
PWzo5EyD5SVm45WYxPKuFalAmmwMnSZxcTBvl/SlHhSR5o40bQ/KOqkBHq/rpEAK
|
||||||
TC1FJ1eFLsmYLZki6cGBzSkIl5QlLGHakWYh+JLu/pkfTL8t+AkY3hZJM96ZAgMB
|
ps7W9pnn2xgq3KOTf554ymIqTyfdInlOkh+2b2joVIS2/fVVDuTpeGn4NE7DAgMB
|
||||||
AAGjZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1Ud
|
AAGjZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1Ud
|
||||||
DgQWBBSmAyntm95+KoyL3ffLBXZKSpk1VTAfBgNVHSMEGDAWgBR93+rQFjh+RUFX
|
DgQWBBTjYR9enoN6IY3lzzq7hF4R3Pxr7jAfBgNVHSMEGDAWgBS92jtC5lTGLF1Y
|
||||||
df4dbNcfS2hbTzANBgkqhkiG9w0BAQsFAAOCAQEABopVFLGQf/LFH+OKVCOT8FCC
|
ZRVMVU7lo4qtbDANBgkqhkiG9w0BAQsFAAOCAQEAlFifQlOXNpUQxbSXmjZj40dW
|
||||||
y/+o1B/U5jXVvbfwlSGScaiJGQ94FsuH59XJCGySQj77ZVTeElBtntoLXmOCFjyF
|
kXhm3s7rBfv6jLm7ebGkbKQ9SPqM94hi9nFX2BWD9DKltHJgmv6mvwWYj0/YO5ij
|
||||||
jKHCDfUpB4nzeqNMvTDzuoYyPS8DhoGfEnaCgJyKf6GU4p41502gH8mQRB7azzL7
|
/A7ckNy3Xf7vu1L3h9CUViZM8d9HMCAnneQihF8X0W+yUwHVhZTFDedl4JMWcttL
|
||||||
5jW0aFatCA6G6T1oogHZpHf0ice80C2JkFbWHSE9JxqARbTc06wCDBiSBFTGZQDO
|
zHMtwlhbaFZhPolkvkNksZRvAOak2O6LUOURvw/alt3tVI/zOyomH5DYi7uxMXXj
|
||||||
JaBIbn6FL3zSkKcpwgJEqDRavVuoDUlJPDqtTzjf/fMQGGR2LUFkceJpsQqf1jrF
|
H7/61rLDdE5cLWIgpcCDDKQi1ORP6w5/HaQ5+1G/IA2PMN0jS903hvxJqTki3XLi
|
||||||
1yTtEZ8gjR2g2Vj6IszUAgbc87xR0AgyGDVckiUdhlX2Y6KCqo2cl9LfSVpqtw==
|
uygYXVa4HETKowgXWXLsNHnMHExpE6kPPtU9v/1t3Lah5H/D3qgicZ1DvMNMaA==
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIDQjCCAiqgAwIBAgIUHT3JtqsYKs7NHv1LNyS9RYC7vsAwDQYJKoZIhvcNAQEL
|
MIIDQjCCAiqgAwIBAgIUbiA5aoS2wqoRlN7qlS1CUrQRrZIwDQYJKoZIhvcNAQEL
|
||||||
BQAwHzEdMBsGA1UEAwwUVGVzdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMjUwMjI4MTIw
|
BQAwHzEdMBsGA1UEAwwUVGVzdCBJbnRlcm1lZGlhdGUgQ0EwHhcNMjYwNzEzMTMy
|
||||||
MTMwWhcNMjYwNzEzMTIwMTMwWjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0G
|
NDA3WhcNMjcxMTI1MTMyNDA3WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0G
|
||||||
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHwI/xSLgCuQrx+WsvupA8w4eMdSef
|
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDf2xz5c/Kts7iYFbznIBqnos0OZw1m
|
||||||
WGw523OJYPJkDYJGgSGsjVb9htba6vXYbGNohuluEAZIyT7GvmPezTokeVMkuSYT
|
XqQRfd8Ub7mcRcNu5LAS+QXaMCQrtSS8HaiOWrnmXVnY0Dtm9BYYgxCLbffBjPgv
|
||||||
lSV8xplFEtDlQhTzaI/cofbi7qtT91/5zS/w0JSaNosThGtZg/M4ZOiMj04m0NGK
|
CjMURftuI0fvFfFHhNOeuO1Y6N3z4YFY9UHldiqBIKmzrEKl6ZzibbHhIWlOFdMC
|
||||||
Zz56l9Lpe/yM7fPda++D9xYEGSSdwK9CqqwF+cXN09d6IK1VINIIjT3Sdb9Sssok
|
IHosnO+9LgXgEcr242yrBczl2SWycXG4OGag4yp2FrsvrKtdqyErJBuyIQHv51k6
|
||||||
GWmD7UUPLvwZ5379+HRs1K8AFXqvbkeWVYtrJwJMxJGVnNSeiqKGSmMEpP7tVNHl
|
Eo5vz42UxZCcjBciSe/X2Tf+KDLzslZDfnY+8PWU2Dx5DaMZAxNVa78jRDhKact9
|
||||||
s4V7oyQXd8KX+HpziiayjGy9giVteJJi/bAmUp+0+hTHBes5fOWI5JyDAgMBAAGj
|
jOunKd1JRj/GZkV5EKL/lIJJQPgcNCl0s8swKlicEYpqEdS4Ayj0fF7DAgMBAAGj
|
||||||
gYAwfjAfBgNVHSMEGDAWgBSmAyntm95+KoyL3ffLBXZKSpk1VTAJBgNVHRMEAjAA
|
gYAwfjAfBgNVHSMEGDAWgBTjYR9enoN6IY3lzzq7hF4R3Pxr7jAJBgNVHRMEAjAA
|
||||||
MAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHREECDAGhwR/
|
MAsGA1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHREECDAGhwR/
|
||||||
AAABMB0GA1UdDgQWBBTVdJE2lkGsNIU3LlEf3rN5fyaRkjANBgkqhkiG9w0BAQsF
|
AAABMB0GA1UdDgQWBBQtvGpvrghOSrZI4B1ieqKJc69RVDANBgkqhkiG9w0BAQsF
|
||||||
AAOCAQEAo1klH9WMsPWTN9qN3tdud07eatulEKo/0okaph6MJ59ozseOzxrfpwL0
|
AAOCAQEAm33hxRyoocCNH2OUhzogkSbi59+an4bLV07uTm3thrdhNKefsPlt1D6Q
|
||||||
67Nr8yl+VwZqrRTBurp0n6G+n0j8UHfWjSrAqN4yUHl+heT0HpnLR2FE9YgZEmxR
|
11QTafhH8RAjlnn/PavLgk3WpTvuC4imlPfhxjf1gRg0zJXW3y0GC2wizSm5cXdK
|
||||||
bPfVbPBef/eJeE7/U6imfBYzzMajua+hg05sVHUNNdPaFOP+Xj47x8uQmf9w5/kf
|
L1ikKpLd17Gys4kGwMLqxCZunpGQnoJpEWBrg3kc7RPp6rgLRMAuj/ZwUzV9nNiU
|
||||||
MrylRUSgH5RRge4+2T5hmNM9tHfF6OfDHitrXnl+X6h/x/tkBvDcUXtKa5xuEcSg
|
YUA64FYY4ISIZigYGCkJUpqgyUQYsD+lYWZl2QlVje1riXIPReIBxd4kcMLqng0l
|
||||||
WpmJKl3pKfXvdmCIrj9Vca+UD2Bntkk2jgDTLEPJAxMgrsQRhnUJclaunnd1NQbc
|
IysTAnZ+vNMWVLjhthGlOfs0yDaIoDa2HHskdaGtlz97SPfIUlDJ/20QLDMZEv0M
|
||||||
FmjFW7iaNvDVKt+vYqH8ff8U9iCB2g==
|
uSjtuu8PGy+iMI5+SfBE9D4cF1tn0w==
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,28 @@
|
||||||
-----BEGIN PRIVATE KEY-----
|
-----BEGIN PRIVATE KEY-----
|
||||||
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
|
||||||
LG1OvFTywkxBuOUKsNsErQ==
|
PEj26Z+E4YTsviOuWu7EkYQ=
|
||||||
-----END PRIVATE KEY-----
|
-----END PRIVATE KEY-----
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
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
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
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
|
||||||
e7KoqGzWXvWLqJ13a9U=
|
IzEG5rEh7Ypi6s+ic8s=
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,28 @@
|
||||||
-----BEGIN PRIVATE KEY-----
|
-----BEGIN PRIVATE KEY-----
|
||||||
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
|
||||||
xfbmGepRVWXw2dLmxhA9/zM=
|
8aUFUg2z34K+VpDf4D9qWd4=
|
||||||
-----END PRIVATE KEY-----
|
-----END PRIVATE KEY-----
|
||||||
|
|
|
||||||
2
main.go
2
main.go
|
|
@ -340,6 +340,7 @@ func main() {
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Log: log.WithName("EphemeralRunner").WithValues("version", build.Version),
|
Log: log.WithName("EphemeralRunner").WithValues("version", build.Version),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
|
PublishMetrics: metricsAddr != "0",
|
||||||
ResourceBuilder: rb,
|
ResourceBuilder: rb,
|
||||||
}).SetupWithManager(mgr, runnerOpts...); err != nil {
|
}).SetupWithManager(mgr, runnerOpts...); err != nil {
|
||||||
log.Error(err, "unable to create controller", "controller", "EphemeralRunner")
|
log.Error(err, "unable to create controller", "controller", "EphemeralRunner")
|
||||||
|
|
@ -350,7 +351,6 @@ func main() {
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
Log: log.WithName("EphemeralRunnerSet").WithValues("version", build.Version),
|
Log: log.WithName("EphemeralRunnerSet").WithValues("version", build.Version),
|
||||||
Scheme: mgr.GetScheme(),
|
Scheme: mgr.GetScheme(),
|
||||||
PublishMetrics: metricsAddr != "0",
|
|
||||||
ResourceBuilder: rb,
|
ResourceBuilder: rb,
|
||||||
}).SetupWithManager(mgr, controllerOpts...); err != nil {
|
}).SetupWithManager(mgr, controllerOpts...); err != nil {
|
||||||
log.Error(err, "unable to create controller", "controller", "EphemeralRunnerSet")
|
log.Error(err, "unable to create controller", "controller", "EphemeralRunnerSet")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue