diff --git a/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go b/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go index 3943c6f6..70093692 100644 --- a/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go +++ b/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go @@ -69,6 +69,18 @@ type AutoscalingListenerSpec struct { // +optional Template *corev1.PodTemplateSpec `json:"template,omitempty"` + + // +optional + ConfigSecretMetadata *ResourceMeta `json:"configSecretMetadata,omitempty"` + + // +optional + ServiceAccountMetadata *ResourceMeta `json:"serviceAccountMetadata,omitempty"` + + // +optional + RoleMetadata *ResourceMeta `json:"roleMetadata,omitempty"` + + // +optional + RoleBindingMetadata *ResourceMeta `json:"roleBindingMetadata,omitempty"` } // AutoscalingListenerStatus defines the observed state of AutoscalingListener diff --git a/apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go b/apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go index ecb01b58..90049d27 100644 --- a/apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go +++ b/apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go @@ -78,12 +78,36 @@ type AutoscalingRunnerSetSpec struct { // Required Template corev1.PodTemplateSpec `json:"template,omitempty"` + // +optional + AutoscalingListenerMetadata *ResourceMeta `json:"autoscalingListener,omitempty"` + // +optional ListenerMetrics *MetricsConfig `json:"listenerMetrics,omitempty"` // +optional ListenerTemplate *corev1.PodTemplateSpec `json:"listenerTemplate,omitempty"` + // +optional + ListenerServiceAccountMetadata *ResourceMeta `json:"listenerServiceAccountMetadata,omitempty"` + + // +optional + ListenerRoleMetadata *ResourceMeta `json:"listenerRoleMetadata,omitempty"` + + // +optional + ListenerRoleBindingMetadata *ResourceMeta `json:"listenerRoleBindingMetadata,omitempty"` + + // +optional + ListenerConfigSecretMetadata *ResourceMeta `json:"listenerConfigSecretMetadata,omitempty"` + + // +optional + EphemeralRunnerSetMetadata *ResourceMeta `json:"ephemeralRunnerSetMetadata,omitempty"` + + // +optional + EphemeralRunnerMetadata *ResourceMeta `json:"ephemeralRunnerMetadata,omitempty"` + + // +optional + EphemeralRunnerConfigSecretMetadata *ResourceMeta `json:"ephemeralRunnerConfigSecretMetadata,omitempty"` + // +optional // +kubebuilder:validation:Minimum:=0 MaxRunners *int `json:"maxRunners,omitempty"` diff --git a/apis/actions.github.com/v1alpha1/common.go b/apis/actions.github.com/v1alpha1/common.go new file mode 100644 index 00000000..6a3a5997 --- /dev/null +++ b/apis/actions.github.com/v1alpha1/common.go @@ -0,0 +1,9 @@ +package v1alpha1 + +// ResourceMeta carries metadata common to all internal resources +type ResourceMeta struct { + // +optional + Labels map[string]string `json:"labels,omitempty"` + // +optional + Annotations map[string]string `json:"annotations,omitempty"` +} diff --git a/apis/actions.github.com/v1alpha1/ephemeralrunner_types.go b/apis/actions.github.com/v1alpha1/ephemeralrunner_types.go index 28d6545c..34511083 100644 --- a/apis/actions.github.com/v1alpha1/ephemeralrunner_types.go +++ b/apis/actions.github.com/v1alpha1/ephemeralrunner_types.go @@ -122,6 +122,9 @@ type EphemeralRunnerSpec struct { // +optional VaultConfig *VaultConfig `json:"vaultConfig,omitempty"` + // +optional + EphemeralRunnerConfigSecretMetadata *ResourceMeta `json:"ephemeralRunnerConfigSecretMetadata,omitempty"` + corev1.PodTemplateSpec `json:",inline"` } diff --git a/apis/actions.github.com/v1alpha1/ephemeralrunnerset_types.go b/apis/actions.github.com/v1alpha1/ephemeralrunnerset_types.go index fc9ef2d7..a105fd4e 100644 --- a/apis/actions.github.com/v1alpha1/ephemeralrunnerset_types.go +++ b/apis/actions.github.com/v1alpha1/ephemeralrunnerset_types.go @@ -28,6 +28,8 @@ type EphemeralRunnerSetSpec struct { PatchID int `json:"patchID"` // EphemeralRunnerSpec is the spec of the ephemeral runner EphemeralRunnerSpec EphemeralRunnerSpec `json:"ephemeralRunnerSpec,omitempty"` + // +optional + EphemeralRunnerMetadata *ResourceMeta `json:"ephemeralRunnerMetadata,omitempty"` } // EphemeralRunnerSetStatus defines the observed state of EphemeralRunnerSet diff --git a/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go b/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go index f50acc08..232d6f86 100644 --- a/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go +++ b/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go @@ -118,6 +118,26 @@ func (in *AutoscalingListenerSpec) DeepCopyInto(out *AutoscalingListenerSpec) { *out = new(v1.PodTemplateSpec) (*in).DeepCopyInto(*out) } + if in.ConfigSecretMetadata != nil { + in, out := &in.ConfigSecretMetadata, &out.ConfigSecretMetadata + *out = new(ResourceMeta) + (*in).DeepCopyInto(*out) + } + if in.ServiceAccountMetadata != nil { + in, out := &in.ServiceAccountMetadata, &out.ServiceAccountMetadata + *out = new(ResourceMeta) + (*in).DeepCopyInto(*out) + } + if in.RoleMetadata != nil { + in, out := &in.RoleMetadata, &out.RoleMetadata + *out = new(ResourceMeta) + (*in).DeepCopyInto(*out) + } + if in.RoleBindingMetadata != nil { + in, out := &in.RoleBindingMetadata, &out.RoleBindingMetadata + *out = new(ResourceMeta) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AutoscalingListenerSpec. @@ -223,6 +243,11 @@ func (in *AutoscalingRunnerSetSpec) DeepCopyInto(out *AutoscalingRunnerSetSpec) (*in).DeepCopyInto(*out) } in.Template.DeepCopyInto(&out.Template) + if in.AutoscalingListenerMetadata != nil { + in, out := &in.AutoscalingListenerMetadata, &out.AutoscalingListenerMetadata + *out = new(ResourceMeta) + (*in).DeepCopyInto(*out) + } if in.ListenerMetrics != nil { in, out := &in.ListenerMetrics, &out.ListenerMetrics *out = new(MetricsConfig) @@ -233,6 +258,41 @@ func (in *AutoscalingRunnerSetSpec) DeepCopyInto(out *AutoscalingRunnerSetSpec) *out = new(v1.PodTemplateSpec) (*in).DeepCopyInto(*out) } + if in.ListenerServiceAccountMetadata != nil { + in, out := &in.ListenerServiceAccountMetadata, &out.ListenerServiceAccountMetadata + *out = new(ResourceMeta) + (*in).DeepCopyInto(*out) + } + if in.ListenerRoleMetadata != nil { + in, out := &in.ListenerRoleMetadata, &out.ListenerRoleMetadata + *out = new(ResourceMeta) + (*in).DeepCopyInto(*out) + } + if in.ListenerRoleBindingMetadata != nil { + in, out := &in.ListenerRoleBindingMetadata, &out.ListenerRoleBindingMetadata + *out = new(ResourceMeta) + (*in).DeepCopyInto(*out) + } + if in.ListenerConfigSecretMetadata != nil { + in, out := &in.ListenerConfigSecretMetadata, &out.ListenerConfigSecretMetadata + *out = new(ResourceMeta) + (*in).DeepCopyInto(*out) + } + if in.EphemeralRunnerSetMetadata != nil { + in, out := &in.EphemeralRunnerSetMetadata, &out.EphemeralRunnerSetMetadata + *out = new(ResourceMeta) + (*in).DeepCopyInto(*out) + } + if in.EphemeralRunnerMetadata != nil { + in, out := &in.EphemeralRunnerMetadata, &out.EphemeralRunnerMetadata + *out = new(ResourceMeta) + (*in).DeepCopyInto(*out) + } + if in.EphemeralRunnerConfigSecretMetadata != nil { + in, out := &in.EphemeralRunnerConfigSecretMetadata, &out.EphemeralRunnerConfigSecretMetadata + *out = new(ResourceMeta) + (*in).DeepCopyInto(*out) + } if in.MaxRunners != nil { in, out := &in.MaxRunners, &out.MaxRunners *out = new(int) @@ -427,6 +487,11 @@ func (in *EphemeralRunnerSetList) DeepCopyObject() runtime.Object { func (in *EphemeralRunnerSetSpec) DeepCopyInto(out *EphemeralRunnerSetSpec) { *out = *in in.EphemeralRunnerSpec.DeepCopyInto(&out.EphemeralRunnerSpec) + if in.EphemeralRunnerMetadata != nil { + in, out := &in.EphemeralRunnerMetadata, &out.EphemeralRunnerMetadata + *out = new(ResourceMeta) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EphemeralRunnerSetSpec. @@ -472,6 +537,11 @@ func (in *EphemeralRunnerSpec) DeepCopyInto(out *EphemeralRunnerSpec) { *out = new(VaultConfig) (*in).DeepCopyInto(*out) } + if in.EphemeralRunnerConfigSecretMetadata != nil { + in, out := &in.EphemeralRunnerConfigSecretMetadata, &out.EphemeralRunnerConfigSecretMetadata + *out = new(ResourceMeta) + (*in).DeepCopyInto(*out) + } in.PodTemplateSpec.DeepCopyInto(&out.PodTemplateSpec) } @@ -660,6 +730,35 @@ func (in *ProxyServerConfig) DeepCopy() *ProxyServerConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceMeta) DeepCopyInto(out *ResourceMeta) { + *out = *in + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceMeta. +func (in *ResourceMeta) DeepCopy() *ResourceMeta { + if in == nil { + return nil + } + out := new(ResourceMeta) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TLSCertificateSource) DeepCopyInto(out *TLSCertificateSource) { *out = *in diff --git a/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalinglisteners.yaml b/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalinglisteners.yaml index 47ece783..5700aa81 100644 --- a/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalinglisteners.yaml +++ b/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalinglisteners.yaml @@ -56,6 +56,19 @@ spec: autoscalingRunnerSetNamespace: description: Required type: string + configSecretMetadata: + description: ResourceMeta carries metadata common to all internal + resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object ephemeralRunnerSetName: description: Required type: string @@ -196,9 +209,48 @@ spec: type: string type: array type: object + roleBindingMetadata: + description: ResourceMeta carries metadata common to all internal + resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + roleMetadata: + description: ResourceMeta carries metadata common to all internal + resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object runnerScaleSetId: description: Required type: integer + serviceAccountMetadata: + description: ResourceMeta carries metadata common to all internal + resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object template: description: PodTemplateSpec describes the data a pod should have when created from a template diff --git a/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalingrunnersets.yaml b/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalingrunnersets.yaml index 55b44f1e..2668c19b 100644 --- a/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalingrunnersets.yaml +++ b/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalingrunnersets.yaml @@ -64,6 +64,54 @@ spec: spec: description: AutoscalingRunnerSetSpec defines the desired state of AutoscalingRunnerSet properties: + autoscalingListener: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + ephemeralRunnerConfigSecretMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + ephemeralRunnerMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + ephemeralRunnerSetMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object githubConfigSecret: description: Required type: string @@ -99,6 +147,18 @@ spec: x-kubernetes-map-type: atomic type: object type: object + listenerConfigSecretMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object listenerMetrics: description: MetricsConfig holds configuration parameters for each metric type properties: @@ -143,6 +203,42 @@ spec: type: object type: object type: object + listenerRoleBindingMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + listenerRoleMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + listenerServiceAccountMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object listenerTemplate: description: PodTemplateSpec describes the data a pod should have when created from a template properties: diff --git a/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunners.yaml b/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunners.yaml index f40bc35b..7a360574 100644 --- a/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunners.yaml +++ b/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunners.yaml @@ -70,6 +70,18 @@ spec: spec: description: EphemeralRunnerSpec defines the desired state of EphemeralRunner properties: + ephemeralRunnerConfigSecretMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object githubConfigSecret: type: string githubConfigUrl: diff --git a/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunnersets.yaml b/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunnersets.yaml index b9ad3581..97da48e9 100644 --- a/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunnersets.yaml +++ b/charts/gha-runner-scale-set-controller/crds/actions.github.com_ephemeralrunnersets.yaml @@ -58,9 +58,33 @@ spec: spec: description: EphemeralRunnerSetSpec defines the desired state of EphemeralRunnerSet properties: + ephemeralRunnerMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object ephemeralRunnerSpec: description: EphemeralRunnerSpec is the spec of the ephemeral runner properties: + ephemeralRunnerConfigSecretMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object githubConfigSecret: type: string githubConfigUrl: diff --git a/config/crd/bases/actions.github.com_autoscalinglisteners.yaml b/config/crd/bases/actions.github.com_autoscalinglisteners.yaml index 47ece783..5700aa81 100644 --- a/config/crd/bases/actions.github.com_autoscalinglisteners.yaml +++ b/config/crd/bases/actions.github.com_autoscalinglisteners.yaml @@ -56,6 +56,19 @@ spec: autoscalingRunnerSetNamespace: description: Required type: string + configSecretMetadata: + description: ResourceMeta carries metadata common to all internal + resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object ephemeralRunnerSetName: description: Required type: string @@ -196,9 +209,48 @@ spec: type: string type: array type: object + roleBindingMetadata: + description: ResourceMeta carries metadata common to all internal + resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + roleMetadata: + description: ResourceMeta carries metadata common to all internal + resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object runnerScaleSetId: description: Required type: integer + serviceAccountMetadata: + description: ResourceMeta carries metadata common to all internal + resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object template: description: PodTemplateSpec describes the data a pod should have when created from a template diff --git a/config/crd/bases/actions.github.com_autoscalingrunnersets.yaml b/config/crd/bases/actions.github.com_autoscalingrunnersets.yaml index 55b44f1e..2668c19b 100644 --- a/config/crd/bases/actions.github.com_autoscalingrunnersets.yaml +++ b/config/crd/bases/actions.github.com_autoscalingrunnersets.yaml @@ -64,6 +64,54 @@ spec: spec: description: AutoscalingRunnerSetSpec defines the desired state of AutoscalingRunnerSet properties: + autoscalingListener: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + ephemeralRunnerConfigSecretMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + ephemeralRunnerMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + ephemeralRunnerSetMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object githubConfigSecret: description: Required type: string @@ -99,6 +147,18 @@ spec: x-kubernetes-map-type: atomic type: object type: object + listenerConfigSecretMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object listenerMetrics: description: MetricsConfig holds configuration parameters for each metric type properties: @@ -143,6 +203,42 @@ spec: type: object type: object type: object + listenerRoleBindingMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + listenerRoleMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + listenerServiceAccountMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object listenerTemplate: description: PodTemplateSpec describes the data a pod should have when created from a template properties: diff --git a/config/crd/bases/actions.github.com_ephemeralrunners.yaml b/config/crd/bases/actions.github.com_ephemeralrunners.yaml index f40bc35b..7a360574 100644 --- a/config/crd/bases/actions.github.com_ephemeralrunners.yaml +++ b/config/crd/bases/actions.github.com_ephemeralrunners.yaml @@ -70,6 +70,18 @@ spec: spec: description: EphemeralRunnerSpec defines the desired state of EphemeralRunner properties: + ephemeralRunnerConfigSecretMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object githubConfigSecret: type: string githubConfigUrl: diff --git a/config/crd/bases/actions.github.com_ephemeralrunnersets.yaml b/config/crd/bases/actions.github.com_ephemeralrunnersets.yaml index b9ad3581..97da48e9 100644 --- a/config/crd/bases/actions.github.com_ephemeralrunnersets.yaml +++ b/config/crd/bases/actions.github.com_ephemeralrunnersets.yaml @@ -58,9 +58,33 @@ spec: spec: description: EphemeralRunnerSetSpec defines the desired state of EphemeralRunnerSet properties: + ephemeralRunnerMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object ephemeralRunnerSpec: description: EphemeralRunnerSpec is the spec of the ephemeral runner properties: + ephemeralRunnerConfigSecretMetadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object githubConfigSecret: type: string githubConfigUrl: diff --git a/controllers/actions.github.com/resourcebuilder.go b/controllers/actions.github.com/resourcebuilder.go index dee3f483..c79dac68 100644 --- a/controllers/actions.github.com/resourcebuilder.go +++ b/controllers/actions.github.com/resourcebuilder.go @@ -96,7 +96,7 @@ func (b *ResourceBuilder) newAutoScalingListener(autoscalingRunnerSet *v1alpha1. effectiveMinRunners = *autoscalingRunnerSet.Spec.MinRunners } - labels := b.mergeLabels(autoscalingRunnerSet.Labels, map[string]string{ + labels := b.filterAndMergeLabels(autoscalingRunnerSet.Labels, map[string]string{ LabelKeyGitHubScaleSetNamespace: autoscalingRunnerSet.Namespace, LabelKeyGitHubScaleSetName: autoscalingRunnerSet.Name, LabelKeyKubernetesPartOf: labelValueKubernetesPartOf, @@ -104,13 +104,18 @@ func (b *ResourceBuilder) newAutoScalingListener(autoscalingRunnerSet *v1alpha1. LabelKeyKubernetesVersion: autoscalingRunnerSet.Labels[LabelKeyKubernetesVersion], }) + if err := applyGitHubURLLabels(autoscalingRunnerSet.Spec.GitHubConfigUrl, labels); err != nil { + return nil, fmt.Errorf("failed to apply GitHub URL labels: %v", err) + } + annotations := map[string]string{ annotationKeyRunnerSpecHash: autoscalingRunnerSet.ListenerSpecHash(), annotationKeyValuesHash: autoscalingRunnerSet.Annotations[annotationKeyValuesHash], } - if err := applyGitHubURLLabels(autoscalingRunnerSet.Spec.GitHubConfigUrl, labels); err != nil { - return nil, fmt.Errorf("failed to apply GitHub URL labels: %v", err) + if autoscalingRunnerSet.Spec.AutoscalingListenerMetadata != nil { + labels = b.filterAndMergeLabels(autoscalingRunnerSet.Spec.AutoscalingListenerMetadata.Labels, labels) + annotations = b.mergeAnnotations(autoscalingRunnerSet.Spec.AutoscalingListenerMetadata.Annotations, annotations) } autoscalingListener := &v1alpha1.AutoscalingListener{ @@ -136,6 +141,10 @@ func (b *ResourceBuilder) newAutoScalingListener(autoscalingRunnerSet *v1alpha1. GitHubServerTLS: autoscalingRunnerSet.Spec.GitHubServerTLS, Metrics: autoscalingRunnerSet.Spec.ListenerMetrics, Template: autoscalingRunnerSet.Spec.ListenerTemplate, + ServiceAccountMetadata: autoscalingRunnerSet.Spec.ListenerServiceAccountMetadata, + RoleMetadata: autoscalingRunnerSet.Spec.ListenerRoleMetadata, + RoleBindingMetadata: autoscalingRunnerSet.Spec.ListenerRoleBindingMetadata, + ConfigSecretMetadata: autoscalingRunnerSet.Spec.ListenerConfigSecretMetadata, }, } @@ -212,10 +221,22 @@ func (b *ResourceBuilder) newScaleSetListenerConfig(autoscalingListener *v1alpha return nil, fmt.Errorf("failed to encode config: %w", err) } + var labels map[string]string + if autoscalingListener.Spec.ConfigSecretMetadata != nil && len(autoscalingListener.Spec.ConfigSecretMetadata.Labels) > 0 { + labels = b.filterAndMergeLabels(autoscalingListener.Spec.ConfigSecretMetadata.Labels, nil) + } + + var annotations map[string]string + if autoscalingListener.Spec.ConfigSecretMetadata != nil && len(autoscalingListener.Spec.ConfigSecretMetadata.Annotations) > 0 { + annotations = autoscalingListener.Spec.ConfigSecretMetadata.Annotations + } + return &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: scaleSetListenerConfigName(autoscalingListener), - Namespace: autoscalingListener.Namespace, + Name: scaleSetListenerConfigName(autoscalingListener), + Namespace: autoscalingListener.Namespace, + Labels: labels, + Annotations: annotations, }, Data: map[string][]byte{ "config.json": buf.Bytes(), @@ -431,32 +452,49 @@ func mergeListenerContainer(base, from *corev1.Container) { } func (b *ResourceBuilder) newScaleSetListenerServiceAccount(autoscalingListener *v1alpha1.AutoscalingListener) *corev1.ServiceAccount { - return &corev1.ServiceAccount{ + base := &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: autoscalingListener.Name, Namespace: autoscalingListener.Namespace, - Labels: b.mergeLabels(autoscalingListener.Labels, map[string]string{ + Labels: b.filterAndMergeLabels(autoscalingListener.Labels, map[string]string{ LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, LabelKeyGitHubScaleSetName: autoscalingListener.Spec.AutoscalingRunnerSetName, }), }, } + + if autoscalingListener.Spec.ServiceAccountMetadata != nil { + base.Labels = b.filterAndMergeLabels(autoscalingListener.Spec.ServiceAccountMetadata.Labels, base.Labels) + base.Annotations = b.mergeAnnotations(autoscalingListener.Spec.ServiceAccountMetadata.Annotations, base.Annotations) + } + + return base } func (b *ResourceBuilder) newScaleSetListenerRole(autoscalingListener *v1alpha1.AutoscalingListener) *rbacv1.Role { rules := rulesForListenerRole([]string{autoscalingListener.Spec.EphemeralRunnerSetName}) rulesHash := hash.ComputeTemplateHash(&rules) + + labels := b.filterAndMergeLabels(autoscalingListener.Labels, map[string]string{ + LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, + LabelKeyGitHubScaleSetName: autoscalingListener.Spec.AutoscalingRunnerSetName, + labelKeyListenerNamespace: autoscalingListener.Namespace, + labelKeyListenerName: autoscalingListener.Name, + "role-policy-rules-hash": rulesHash, + }) + + var annotations map[string]string + if autoscalingListener.Spec.RoleMetadata != nil { + labels = b.filterAndMergeLabels(autoscalingListener.Spec.RoleMetadata.Labels, labels) + annotations = b.mergeAnnotations(autoscalingListener.Spec.RoleMetadata.Annotations, nil) + } + newRole := &rbacv1.Role{ ObjectMeta: metav1.ObjectMeta{ - Name: autoscalingListener.Name, - Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, - Labels: b.mergeLabels(autoscalingListener.Labels, map[string]string{ - LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, - LabelKeyGitHubScaleSetName: autoscalingListener.Spec.AutoscalingRunnerSetName, - labelKeyListenerNamespace: autoscalingListener.Namespace, - labelKeyListenerName: autoscalingListener.Name, - "role-policy-rules-hash": rulesHash, - }), + Name: autoscalingListener.Name, + Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, + Labels: labels, + Annotations: annotations, }, Rules: rules, } @@ -480,18 +518,28 @@ func (b *ResourceBuilder) newScaleSetListenerRoleBinding(autoscalingListener *v1 } subjectHash := hash.ComputeTemplateHash(&subjects) + labels := b.filterAndMergeLabels(autoscalingListener.Labels, map[string]string{ + LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, + LabelKeyGitHubScaleSetName: autoscalingListener.Spec.AutoscalingRunnerSetName, + labelKeyListenerNamespace: autoscalingListener.Namespace, + labelKeyListenerName: autoscalingListener.Name, + "role-binding-role-ref-hash": roleRefHash, + "role-binding-subject-hash": subjectHash, + }) + + var annotations map[string]string + + if autoscalingListener.Spec.RoleBindingMetadata != nil { + labels = b.filterAndMergeLabels(autoscalingListener.Spec.RoleBindingMetadata.Labels, labels) + annotations = autoscalingListener.Spec.RoleBindingMetadata.Annotations + } + newRoleBinding := &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ - Name: autoscalingListener.Name, - Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, - Labels: b.mergeLabels(autoscalingListener.Labels, map[string]string{ - LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, - LabelKeyGitHubScaleSetName: autoscalingListener.Spec.AutoscalingRunnerSetName, - labelKeyListenerNamespace: autoscalingListener.Namespace, - labelKeyListenerName: autoscalingListener.Name, - "role-binding-role-ref-hash": roleRefHash, - "role-binding-subject-hash": subjectHash, - }), + Name: autoscalingListener.Name, + Namespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace, + Labels: labels, + Annotations: annotations, }, RoleRef: roleRef, Subjects: subjects, @@ -507,7 +555,7 @@ func (b *ResourceBuilder) newEphemeralRunnerSet(autoscalingRunnerSet *v1alpha1.A } runnerSpecHash := autoscalingRunnerSet.RunnerSetSpecHash() - labels := b.mergeLabels(autoscalingRunnerSet.Labels, map[string]string{ + labels := b.filterAndMergeLabels(autoscalingRunnerSet.Labels, map[string]string{ LabelKeyKubernetesPartOf: labelValueKubernetesPartOf, LabelKeyKubernetesComponent: "runner-set", LabelKeyKubernetesVersion: autoscalingRunnerSet.Labels[LabelKeyKubernetesVersion], @@ -519,19 +567,24 @@ func (b *ResourceBuilder) newEphemeralRunnerSet(autoscalingRunnerSet *v1alpha1.A return nil, fmt.Errorf("failed to apply GitHub URL labels: %v", err) } - newAnnotations := map[string]string{ + annotations := map[string]string{ AnnotationKeyGitHubRunnerGroupName: autoscalingRunnerSet.Annotations[AnnotationKeyGitHubRunnerGroupName], AnnotationKeyGitHubRunnerScaleSetName: autoscalingRunnerSet.Annotations[AnnotationKeyGitHubRunnerScaleSetName], annotationKeyRunnerSpecHash: runnerSpecHash, } + if autoscalingRunnerSet.Spec.EphemeralRunnerSetMetadata != nil { + labels = b.filterAndMergeLabels(autoscalingRunnerSet.Spec.EphemeralRunnerSetMetadata.Labels, labels) + annotations = b.mergeAnnotations(autoscalingRunnerSet.Spec.EphemeralRunnerSetMetadata.Annotations, annotations) + } + newEphemeralRunnerSet := &v1alpha1.EphemeralRunnerSet{ TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{ GenerateName: autoscalingRunnerSet.Name + "-", Namespace: autoscalingRunnerSet.Namespace, Labels: labels, - Annotations: newAnnotations, + Annotations: annotations, OwnerReferences: []metav1.OwnerReference{ { APIVersion: autoscalingRunnerSet.GetObjectKind().GroupVersionKind().GroupVersion().String(), @@ -546,14 +599,16 @@ func (b *ResourceBuilder) newEphemeralRunnerSet(autoscalingRunnerSet *v1alpha1.A Spec: v1alpha1.EphemeralRunnerSetSpec{ Replicas: 0, EphemeralRunnerSpec: v1alpha1.EphemeralRunnerSpec{ - RunnerScaleSetId: runnerScaleSetID, - GitHubConfigUrl: autoscalingRunnerSet.Spec.GitHubConfigUrl, - GitHubConfigSecret: autoscalingRunnerSet.Spec.GitHubConfigSecret, - Proxy: autoscalingRunnerSet.Spec.Proxy, - GitHubServerTLS: autoscalingRunnerSet.Spec.GitHubServerTLS, - PodTemplateSpec: autoscalingRunnerSet.Spec.Template, - VaultConfig: autoscalingRunnerSet.VaultConfig(), + RunnerScaleSetId: runnerScaleSetID, + GitHubConfigUrl: autoscalingRunnerSet.Spec.GitHubConfigUrl, + GitHubConfigSecret: autoscalingRunnerSet.Spec.GitHubConfigSecret, + Proxy: autoscalingRunnerSet.Spec.Proxy, + GitHubServerTLS: autoscalingRunnerSet.Spec.GitHubServerTLS, + PodTemplateSpec: autoscalingRunnerSet.Spec.Template, + VaultConfig: autoscalingRunnerSet.VaultConfig(), + EphemeralRunnerConfigSecretMetadata: autoscalingRunnerSet.Spec.EphemeralRunnerConfigSecretMetadata, }, + EphemeralRunnerMetadata: autoscalingRunnerSet.Spec.EphemeralRunnerMetadata, }, } @@ -568,6 +623,12 @@ func (b *ResourceBuilder) newEphemeralRunner(ephemeralRunnerSet *v1alpha1.Epheme annotations := make(map[string]string, len(ephemeralRunnerSet.Annotations)+1) maps.Copy(annotations, ephemeralRunnerSet.Annotations) annotations[AnnotationKeyPatchID] = strconv.Itoa(ephemeralRunnerSet.Spec.PatchID) + + if ephemeralRunnerSet.Spec.EphemeralRunnerMetadata != nil { + labels = b.filterAndMergeLabels(ephemeralRunnerSet.Spec.EphemeralRunnerMetadata.Labels, labels) + annotations = b.mergeAnnotations(ephemeralRunnerSet.Spec.EphemeralRunnerMetadata.Annotations, annotations) + } + return &v1alpha1.EphemeralRunner{ ObjectMeta: metav1.ObjectMeta{ GenerateName: ephemeralRunnerSet.Name + "-runner-", @@ -662,10 +723,22 @@ func (b *ResourceBuilder) newEphemeralRunnerPod(runner *v1alpha1.EphemeralRunner } func (b *ResourceBuilder) newEphemeralRunnerJitSecret(ephemeralRunner *v1alpha1.EphemeralRunner, jitConfig *actions.RunnerScaleSetJitRunnerConfig) *corev1.Secret { + var ( + labels map[string]string + annotations map[string]string + ) + + if ephemeralRunner.Spec.EphemeralRunnerConfigSecretMetadata != nil { + labels = b.filterAndMergeLabels(ephemeralRunner.Spec.EphemeralRunnerConfigSecretMetadata.Labels, nil) + annotations = ephemeralRunner.Spec.EphemeralRunnerConfigSecretMetadata.Annotations + } + return &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: ephemeralRunner.Name, - Namespace: ephemeralRunner.Namespace, + Name: ephemeralRunner.Name, + Namespace: ephemeralRunner.Namespace, + Labels: labels, + Annotations: annotations, }, Data: map[string][]byte{ jitTokenKey: []byte(jitConfig.EncodedJITConfig), @@ -756,9 +829,12 @@ func trimLabelValue(val string) string { return strings.Trim(val, "-_.") } -func (b *ResourceBuilder) mergeLabels(base, overwrite map[string]string) map[string]string { - mergedLabels := make(map[string]string, len(base)) +func (b *ResourceBuilder) filterAndMergeLabels(base, overwrite map[string]string) map[string]string { + if base == nil && overwrite == nil { + return nil + } + mergedLabels := make(map[string]string, len(base)) base: for k, v := range base { for _, prefix := range b.ExcludeLabelPropagationPrefixes { @@ -781,3 +857,12 @@ overwrite: return mergedLabels } + +func (b *ResourceBuilder) mergeAnnotations(base, overwrite map[string]string) map[string]string { + if base == nil && overwrite == nil { + return nil + } + base = maps.Clone(base) + maps.Copy(base, overwrite) + return base +} diff --git a/controllers/actions.github.com/resourcebuilder_test.go b/controllers/actions.github.com/resourcebuilder_test.go index 24af4ca5..aa77d138 100644 --- a/controllers/actions.github.com/resourcebuilder_test.go +++ b/controllers/actions.github.com/resourcebuilder_test.go @@ -6,13 +6,14 @@ import ( "testing" "github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1" + "github.com/actions/actions-runner-controller/github/actions" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func TestLabelPropagation(t *testing.T) { +func TestMetadataPropagation(t *testing.T) { autoscalingRunnerSet := v1alpha1.AutoscalingRunnerSet{ ObjectMeta: metav1.ObjectMeta{ Name: "test-scale-set", @@ -34,6 +35,70 @@ func TestLabelPropagation(t *testing.T) { }, Spec: v1alpha1.AutoscalingRunnerSetSpec{ GitHubConfigUrl: "https://github.com/org/repo", + AutoscalingListenerMetadata: &v1alpha1.ResourceMeta{ + Labels: map[string]string{ + "test.com/autoscaling-listener-label": "autoscaling-listener-label", + }, + Annotations: map[string]string{ + "test.com/autoscaling-listener-annotation": "autoscaling-listener-annotation", + }, + }, + ListenerServiceAccountMetadata: &v1alpha1.ResourceMeta{ + Labels: map[string]string{ + "test.com/listener-service-account-label": "listener-service-account-label", + }, + Annotations: map[string]string{ + "test.com/listener-service-account-annotation": "listener-service-account-annotation", + }, + }, + ListenerRoleMetadata: &v1alpha1.ResourceMeta{ + Labels: map[string]string{ + "test.com/listener-role-label": "listener-role-label", + }, + Annotations: map[string]string{ + "test.com/listener-role-annotation": "listener-role-annotation", + }, + }, + ListenerRoleBindingMetadata: &v1alpha1.ResourceMeta{ + Labels: map[string]string{ + "test.com/listener-role-binding-label": "listener-role-binding-label", + }, + Annotations: map[string]string{ + "test.com/listener-role-binding-annotation": "listener-role-binding-annotation", + }, + }, + ListenerConfigSecretMetadata: &v1alpha1.ResourceMeta{ + Labels: map[string]string{ + "test.com/listener-config-secret-label": "listener-config-secret-label", + }, + Annotations: map[string]string{ + "test.com/listener-config-secret-annotation": "listener-config-secret-annotation", + }, + }, + EphemeralRunnerSetMetadata: &v1alpha1.ResourceMeta{ + Labels: map[string]string{ + "test.com/ephemeral-runner-set-label": "ephemeral-runner-set-label", + }, + Annotations: map[string]string{ + "test.com/ephemeral-runner-set-annotation": "ephemeral-runner-set-annotation", + }, + }, + EphemeralRunnerMetadata: &v1alpha1.ResourceMeta{ + Labels: map[string]string{ + "test.com/ephemeral-runner-label": "ephemeral-runner-label", + }, + Annotations: map[string]string{ + "test.com/ephemeral-runner-annotation": "ephemeral-runner-annotation", + }, + }, + EphemeralRunnerConfigSecretMetadata: &v1alpha1.ResourceMeta{ + Labels: map[string]string{ + "test.com/ephemeral-runner-config-secret-label": "ephemeral-runner-config-secret-label", + }, + Annotations: map[string]string{ + "test.com/ephemeral-runner-config-secret-annotation": "ephemeral-runner-config-secret-annotation", + }, + }, }, } @@ -57,6 +122,8 @@ func TestLabelPropagation(t *testing.T) { assert.Equal(t, autoscalingRunnerSet.Annotations[AnnotationKeyGitHubRunnerGroupName], ephemeralRunnerSet.Annotations[AnnotationKeyGitHubRunnerGroupName]) assert.Equal(t, autoscalingRunnerSet.Annotations[AnnotationKeyGitHubRunnerScaleSetName], ephemeralRunnerSet.Annotations[AnnotationKeyGitHubRunnerScaleSetName]) assert.Equal(t, autoscalingRunnerSet.Labels["arbitrary-label"], ephemeralRunnerSet.Labels["arbitrary-label"]) + assert.Equal(t, "ephemeral-runner-set-label", ephemeralRunnerSet.Labels["test.com/ephemeral-runner-set-label"]) + assert.Equal(t, "ephemeral-runner-set-annotation", ephemeralRunnerSet.Annotations["test.com/ephemeral-runner-set-annotation"]) listener, err := b.newAutoScalingListener(&autoscalingRunnerSet, ephemeralRunnerSet, autoscalingRunnerSet.Namespace, "test:latest", nil) require.NoError(t, err) @@ -70,17 +137,26 @@ func TestLabelPropagation(t *testing.T) { assert.Equal(t, "org", listener.Labels[LabelKeyGitHubOrganization]) assert.Equal(t, "repo", listener.Labels[LabelKeyGitHubRepository]) assert.Equal(t, autoscalingRunnerSet.Labels["arbitrary-label"], listener.Labels["arbitrary-label"]) + assert.Equal(t, "autoscaling-listener-label", listener.Labels["test.com/autoscaling-listener-label"]) + assert.Equal(t, "autoscaling-listener-annotation", listener.Annotations["test.com/autoscaling-listener-annotation"]) assert.NotContains(t, listener.Labels, "example.com/label") assert.NotContains(t, listener.Labels, "example.com/example") assert.NotContains(t, listener.Labels, "directly.excluded.org/label") assert.Equal(t, "not-excluded-value", listener.Labels["directly.excluded.org/arbitrary"]) - listenerServiceAccount := &corev1.ServiceAccount{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - }, - } + listenerServiceAccount := b.newScaleSetListenerServiceAccount(listener) + assert.Equal(t, "listener-service-account-label", listenerServiceAccount.Labels["test.com/listener-service-account-label"]) + assert.Equal(t, "listener-service-account-annotation", listenerServiceAccount.Annotations["test.com/listener-service-account-annotation"]) + + listenerRole := b.newScaleSetListenerRole(listener) + assert.Equal(t, "listener-role-label", listenerRole.Labels["test.com/listener-role-label"]) + assert.Equal(t, "listener-role-annotation", listenerRole.Annotations["test.com/listener-role-annotation"]) + + listenerRoleBinding := b.newScaleSetListenerRoleBinding(listener, listenerRole, listenerServiceAccount) + assert.Equal(t, "listener-role-binding-label", listenerRoleBinding.Labels["test.com/listener-role-binding-label"]) + assert.Equal(t, "listener-role-binding-annotation", listenerRoleBinding.Annotations["test.com/listener-role-binding-annotation"]) + listenerPod, err := b.newScaleSetListenerPod(listener, &corev1.Secret{}, listenerServiceAccount, nil) require.NoError(t, err) assert.Equal(t, listenerPod.Labels, listener.Labels) @@ -97,12 +173,20 @@ func TestLabelPropagation(t *testing.T) { assert.Equal(t, "runner", ephemeralRunner.Labels[LabelKeyKubernetesComponent]) assert.Equal(t, autoscalingRunnerSet.Annotations[AnnotationKeyGitHubRunnerGroupName], ephemeralRunner.Annotations[AnnotationKeyGitHubRunnerGroupName]) assert.Equal(t, autoscalingRunnerSet.Annotations[AnnotationKeyGitHubRunnerScaleSetName], ephemeralRunnerSet.Annotations[AnnotationKeyGitHubRunnerScaleSetName]) + assert.Equal(t, "ephemeral-runner-label", ephemeralRunner.Labels["test.com/ephemeral-runner-label"]) + assert.Equal(t, "ephemeral-runner-annotation", ephemeralRunner.Annotations["test.com/ephemeral-runner-annotation"]) - runnerSecret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", + runnerSecret := b.newEphemeralRunnerJitSecret(ephemeralRunner, &actions.RunnerScaleSetJitRunnerConfig{ + Runner: &actions.RunnerReference{ + Id: 1, + Name: "test", + RunnerScaleSetId: 1, }, - } + EncodedJITConfig: "", + }) + assert.Equal(t, "ephemeral-runner-config-secret-label", runnerSecret.Labels["test.com/ephemeral-runner-config-secret-label"]) + assert.Equal(t, "ephemeral-runner-config-secret-annotation", runnerSecret.Annotations["test.com/ephemeral-runner-config-secret-annotation"]) + pod := b.newEphemeralRunnerPod(ephemeralRunner, runnerSecret) for key := range ephemeralRunner.Labels { assert.Equal(t, ephemeralRunner.Labels[key], pod.Labels[key])