diff --git a/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go b/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go index 3943c6f6..bc190378 100644 --- a/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go +++ b/apis/actions.github.com/v1alpha1/autoscalinglistener_types.go @@ -69,6 +69,15 @@ type AutoscalingListenerSpec struct { // +optional Template *corev1.PodTemplateSpec `json:"template,omitempty"` + + // +optional + ServiceAccountMetadata *ResourceMeta `json:"service_account_metadata,omitempty"` + + // +optional + RoleMetadata *ResourceMeta `json:"role_metadata,omitempty"` + + // +optional + RoleBindingMetadata *ResourceMeta `json:"role_binding_metadata,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..a5b80941 100644 --- a/apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go +++ b/apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go @@ -84,6 +84,15 @@ type AutoscalingRunnerSetSpec struct { // +optional ListenerTemplate *corev1.PodTemplateSpec `json:"listenerTemplate,omitempty"` + // +optional + ListenerServiceAccountMetadata *ResourceMeta `json:"listener_service_account_metadata,omitempty"` + + // +optional + ListenerRoleMetadata *ResourceMeta `json:"listener_role_metadata,omitempty"` + + // +optional + ListenerRoleBindingMetadata *ResourceMeta `json:"listener_role_binding_metadata,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..e10edf0b --- /dev/null +++ b/apis/actions.github.com/v1alpha1/common.go @@ -0,0 +1,7 @@ +package v1alpha1 + +// ResourceMeta carries metadata common to all internal resources +type ResourceMeta struct { + Labels map[string]string `json:"labels"` + Annotations map[string]string `json:"annotations"` +} diff --git a/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go b/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go index f50acc08..a424a728 100644 --- a/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go +++ b/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go @@ -118,6 +118,21 @@ func (in *AutoscalingListenerSpec) DeepCopyInto(out *AutoscalingListenerSpec) { *out = new(v1.PodTemplateSpec) (*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. @@ -233,6 +248,21 @@ 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.MaxRunners != nil { in, out := &in.MaxRunners, &out.MaxRunners *out = new(int) @@ -660,6 +690,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..36d50d9b 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 @@ -196,9 +196,57 @@ spec: type: string type: array type: object + role_binding_metadata: + description: ResourceMeta carries metadata common to all internal + resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + required: + - annotations + - labels + type: object + role_metadata: + description: ResourceMeta carries metadata common to all internal + resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + required: + - annotations + - labels + type: object runnerScaleSetId: description: Required type: integer + service_account_metadata: + description: ResourceMeta carries metadata common to all internal + resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + required: + - annotations + - labels + 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..a13c9b23 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 @@ -99,6 +99,51 @@ spec: x-kubernetes-map-type: atomic type: object type: object + listener_role_binding_metadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + required: + - annotations + - labels + type: object + listener_role_metadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + required: + - annotations + - labels + type: object + listener_service_account_metadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + required: + - annotations + - labels + type: object listenerMetrics: description: MetricsConfig holds configuration parameters for each metric type properties: diff --git a/config/crd/bases/actions.github.com_autoscalinglisteners.yaml b/config/crd/bases/actions.github.com_autoscalinglisteners.yaml index 47ece783..36d50d9b 100644 --- a/config/crd/bases/actions.github.com_autoscalinglisteners.yaml +++ b/config/crd/bases/actions.github.com_autoscalinglisteners.yaml @@ -196,9 +196,57 @@ spec: type: string type: array type: object + role_binding_metadata: + description: ResourceMeta carries metadata common to all internal + resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + required: + - annotations + - labels + type: object + role_metadata: + description: ResourceMeta carries metadata common to all internal + resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + required: + - annotations + - labels + type: object runnerScaleSetId: description: Required type: integer + service_account_metadata: + description: ResourceMeta carries metadata common to all internal + resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + required: + - annotations + - labels + 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..a13c9b23 100644 --- a/config/crd/bases/actions.github.com_autoscalingrunnersets.yaml +++ b/config/crd/bases/actions.github.com_autoscalingrunnersets.yaml @@ -99,6 +99,51 @@ spec: x-kubernetes-map-type: atomic type: object type: object + listener_role_binding_metadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + required: + - annotations + - labels + type: object + listener_role_metadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + required: + - annotations + - labels + type: object + listener_service_account_metadata: + description: ResourceMeta carries metadata common to all internal resources + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + required: + - annotations + - labels + type: object listenerMetrics: description: MetricsConfig holds configuration parameters for each metric type properties: diff --git a/controllers/actions.github.com/resourcebuilder.go b/controllers/actions.github.com/resourcebuilder.go index 98b894a6..80e9f32d 100644 --- a/controllers/actions.github.com/resourcebuilder.go +++ b/controllers/actions.github.com/resourcebuilder.go @@ -136,6 +136,9 @@ 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.ListenerRoleMetadata, }, } @@ -425,7 +428,7 @@ 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, @@ -435,6 +438,13 @@ func (b *ResourceBuilder) newScaleSetListenerServiceAccount(autoscalingListener }), }, } + + if autoscalingListener.Spec.ServiceAccountMetadata != nil { + base.Labels = b.mergeLabels(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 { @@ -455,6 +465,11 @@ func (b *ResourceBuilder) newScaleSetListenerRole(autoscalingListener *v1alpha1. Rules: rules, } + for autoscalingListener.Spec.RoleMetadata != nil { + newRole.Labels = b.mergeLabels(autoscalingListener.Spec.RoleMetadata.Labels, newRole.Labels) + newRole.Annotations = b.mergeAnnotations(autoscalingListener.Spec.RoleMetadata.Annotations, newRole.Annotations) + } + return newRole } @@ -491,6 +506,11 @@ func (b *ResourceBuilder) newScaleSetListenerRoleBinding(autoscalingListener *v1 Subjects: subjects, } + for autoscalingListener.Spec.RoleBindingMetadata != nil { + newRoleBinding.Labels = b.mergeLabels(autoscalingListener.Spec.RoleBindingMetadata.Labels, newRoleBinding.Labels) + newRoleBinding.Annotations = b.mergeAnnotations(autoscalingListener.Spec.RoleBindingMetadata.Annotations, newRoleBinding.Annotations) + } + return newRoleBinding } @@ -751,8 +771,11 @@ func trimLabelValue(val string) string { } func (b *ResourceBuilder) mergeLabels(base, overwrite map[string]string) map[string]string { - mergedLabels := make(map[string]string, len(base)) + if len(overwrite) == 0 { + return maps.Clone(base) + } + mergedLabels := make(map[string]string, len(base)) base: for k, v := range base { for _, prefix := range b.ExcludeLabelPropagationPrefixes { @@ -775,3 +798,11 @@ overwrite: return mergedLabels } + +func (b *ResourceBuilder) mergeAnnotations(base, overwrite map[string]string) map[string]string { + base = maps.Clone(base) + for k, v := range overwrite { + base[k] = v + } + return base +}