Allow adding annotation to listener service account
This commit is contained in:
parent
02aa70a64a
commit
e37719f0c3
|
|
@ -21,6 +21,15 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// ListenerServiceAccount defines metadata to apply to the listener service account.
|
||||
type ListenerServiceAccount struct {
|
||||
// +optional
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
|
||||
// +optional
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
// AutoscalingListenerSpec defines the desired state of AutoscalingListener
|
||||
type AutoscalingListenerSpec struct {
|
||||
// Required
|
||||
|
|
@ -69,6 +78,9 @@ type AutoscalingListenerSpec struct {
|
|||
|
||||
// +optional
|
||||
Template *corev1.PodTemplateSpec `json:"template,omitempty"`
|
||||
|
||||
// +optional
|
||||
ListenerServiceAccount *ListenerServiceAccount `json:"listenerServiceAccount,omitempty"`
|
||||
}
|
||||
|
||||
// AutoscalingListenerStatus defines the observed state of AutoscalingListener
|
||||
|
|
|
|||
|
|
@ -84,6 +84,9 @@ type AutoscalingRunnerSetSpec struct {
|
|||
// +optional
|
||||
ListenerTemplate *corev1.PodTemplateSpec `json:"listenerTemplate,omitempty"`
|
||||
|
||||
// +optional
|
||||
ListenerServiceAccount *ListenerServiceAccount `json:"listenerServiceAccount,omitempty"`
|
||||
|
||||
// +optional
|
||||
// +kubebuilder:validation:Minimum:=0
|
||||
MaxRunners *int `json:"maxRunners,omitempty"`
|
||||
|
|
|
|||
|
|
@ -118,6 +118,11 @@ func (in *AutoscalingListenerSpec) DeepCopyInto(out *AutoscalingListenerSpec) {
|
|||
*out = new(v1.PodTemplateSpec)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.ListenerServiceAccount != nil {
|
||||
in, out := &in.ListenerServiceAccount, &out.ListenerServiceAccount
|
||||
*out = new(ListenerServiceAccount)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AutoscalingListenerSpec.
|
||||
|
|
@ -145,6 +150,35 @@ func (in *AutoscalingListenerStatus) DeepCopy() *AutoscalingListenerStatus {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ListenerServiceAccount) DeepCopyInto(out *ListenerServiceAccount) {
|
||||
*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 ListenerServiceAccount.
|
||||
func (in *ListenerServiceAccount) DeepCopy() *ListenerServiceAccount {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ListenerServiceAccount)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AutoscalingRunnerSet) DeepCopyInto(out *AutoscalingRunnerSet) {
|
||||
*out = *in
|
||||
|
|
@ -233,6 +267,11 @@ func (in *AutoscalingRunnerSetSpec) DeepCopyInto(out *AutoscalingRunnerSetSpec)
|
|||
*out = new(v1.PodTemplateSpec)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.ListenerServiceAccount != nil {
|
||||
in, out := &in.ListenerServiceAccount, &out.ListenerServiceAccount
|
||||
*out = new(ListenerServiceAccount)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.MaxRunners != nil {
|
||||
in, out := &in.MaxRunners, &out.MaxRunners
|
||||
*out = new(int)
|
||||
|
|
|
|||
|
|
@ -199,6 +199,18 @@ spec:
|
|||
runnerScaleSetId:
|
||||
description: Required
|
||||
type: integer
|
||||
listenerServiceAccount:
|
||||
description: ListenerServiceAccount defines metadata to apply to the listener service account.
|
||||
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
|
||||
|
|
|
|||
|
|
@ -8199,6 +8199,18 @@ spec:
|
|||
- containers
|
||||
type: object
|
||||
type: object
|
||||
listenerServiceAccount:
|
||||
description: ListenerServiceAccount defines metadata to apply to the listener service account.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
labels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
maxRunners:
|
||||
minimum: 0
|
||||
type: integer
|
||||
|
|
|
|||
|
|
@ -199,6 +199,18 @@ spec:
|
|||
runnerScaleSetId:
|
||||
description: Required
|
||||
type: integer
|
||||
listenerServiceAccount:
|
||||
description: ListenerServiceAccount defines metadata to apply to the listener service account.
|
||||
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
|
||||
|
|
|
|||
|
|
@ -8199,6 +8199,18 @@ spec:
|
|||
- containers
|
||||
type: object
|
||||
type: object
|
||||
listenerServiceAccount:
|
||||
description: ListenerServiceAccount defines metadata to apply to the listener service account.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
labels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
maxRunners:
|
||||
minimum: 0
|
||||
type: integer
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ rules:
|
|||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- actions.github.com
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ type AutoscalingListenerReconciler struct {
|
|||
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=core,resources=pods/status,verbs=get
|
||||
// +kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create;update
|
||||
// +kubebuilder:rbac:groups=core,resources=serviceaccounts,verbs=get;list;watch;create
|
||||
// +kubebuilder:rbac:groups=core,resources=serviceaccounts,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles,verbs=create;delete;get;list;watch;update
|
||||
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=create;delete;get;list;watch
|
||||
// +kubebuilder:rbac:groups=actions.github.com,resources=autoscalinglisteners,verbs=get;list;watch;create;update;patch;delete
|
||||
|
|
@ -156,7 +156,14 @@ func (r *AutoscalingListenerReconciler) Reconcile(ctx context.Context, req ctrl.
|
|||
return r.createServiceAccountForListener(ctx, autoscalingListener, log)
|
||||
}
|
||||
|
||||
// TODO: make sure the service account is up to date
|
||||
desiredServiceAccount := r.newScaleSetListenerServiceAccount(autoscalingListener)
|
||||
if listenerServiceAccountNeedsUpdate(serviceAccount, desiredServiceAccount) {
|
||||
log.Info("Updating listener service account", "namespace", serviceAccount.Namespace, "name", serviceAccount.Name)
|
||||
if err := r.updateServiceAccountForListener(ctx, serviceAccount, desiredServiceAccount); err != nil {
|
||||
log.Error(err, "Unable to update listener service account", "namespace", serviceAccount.Namespace, "name", serviceAccount.Name)
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the runner scale set listener role is created in the AutoscalingRunnerSet namespace
|
||||
listenerRole := new(rbacv1.Role)
|
||||
|
|
@ -425,6 +432,48 @@ func (r *AutoscalingListenerReconciler) createServiceAccountForListener(ctx cont
|
|||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
func listenerServiceAccountNeedsUpdate(current *corev1.ServiceAccount, desired *corev1.ServiceAccount) bool {
|
||||
if needsMetadataUpdate(current.Labels, desired.Labels) {
|
||||
return true
|
||||
}
|
||||
|
||||
return needsMetadataUpdate(current.Annotations, desired.Annotations)
|
||||
}
|
||||
|
||||
func needsMetadataUpdate(current map[string]string, desired map[string]string) bool {
|
||||
if len(desired) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for key, value := range desired {
|
||||
if current == nil || current[key] != value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *AutoscalingListenerReconciler) updateServiceAccountForListener(ctx context.Context, serviceAccount *corev1.ServiceAccount, desired *corev1.ServiceAccount) error {
|
||||
return patch(ctx, r.Client, serviceAccount, func(obj *corev1.ServiceAccount) {
|
||||
if obj.Labels == nil {
|
||||
obj.Labels = map[string]string{}
|
||||
}
|
||||
for key, value := range desired.Labels {
|
||||
obj.Labels[key] = value
|
||||
}
|
||||
|
||||
if len(desired.Annotations) > 0 {
|
||||
if obj.Annotations == nil {
|
||||
obj.Annotations = map[string]string{}
|
||||
}
|
||||
for key, value := range desired.Annotations {
|
||||
obj.Annotations[key] = value
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (r *AutoscalingListenerReconciler) createListenerPod(ctx context.Context, autoscalingRunnerSet *v1alpha1.AutoscalingRunnerSet, autoscalingListener *v1alpha1.AutoscalingListener, serviceAccount *corev1.ServiceAccount, appConfig *appconfig.AppConfig, logger logr.Logger) (ctrl.Result, error) {
|
||||
var envs []corev1.EnvVar
|
||||
if autoscalingListener.Spec.Proxy != nil {
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ func (b *ResourceBuilder) newAutoScalingListener(autoscalingRunnerSet *v1alpha1.
|
|||
GitHubServerTLS: autoscalingRunnerSet.Spec.GitHubServerTLS,
|
||||
Metrics: autoscalingRunnerSet.Spec.ListenerMetrics,
|
||||
Template: autoscalingRunnerSet.Spec.ListenerTemplate,
|
||||
ListenerServiceAccount: autoscalingRunnerSet.Spec.ListenerServiceAccount,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -425,14 +426,33 @@ func mergeListenerContainer(base, from *corev1.Container) {
|
|||
}
|
||||
|
||||
func (b *ResourceBuilder) newScaleSetListenerServiceAccount(autoscalingListener *v1alpha1.AutoscalingListener) *corev1.ServiceAccount {
|
||||
labels := b.mergeLabels(autoscalingListener.Labels, map[string]string{
|
||||
LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
||||
LabelKeyGitHubScaleSetName: autoscalingListener.Spec.AutoscalingRunnerSetName,
|
||||
})
|
||||
|
||||
var annotations map[string]string
|
||||
if autoscalingListener.Spec.ListenerServiceAccount != nil {
|
||||
if len(autoscalingListener.Spec.ListenerServiceAccount.Labels) > 0 {
|
||||
for k, v := range autoscalingListener.Spec.ListenerServiceAccount.Labels {
|
||||
if _, ok := labels[k]; !ok {
|
||||
labels[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(autoscalingListener.Spec.ListenerServiceAccount.Annotations) > 0 {
|
||||
annotations = make(map[string]string, len(autoscalingListener.Spec.ListenerServiceAccount.Annotations))
|
||||
maps.Copy(annotations, autoscalingListener.Spec.ListenerServiceAccount.Annotations)
|
||||
}
|
||||
}
|
||||
|
||||
return &corev1.ServiceAccount{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: autoscalingListener.Name,
|
||||
Namespace: autoscalingListener.Namespace,
|
||||
Labels: b.mergeLabels(autoscalingListener.Labels, map[string]string{
|
||||
LabelKeyGitHubScaleSetNamespace: autoscalingListener.Spec.AutoscalingRunnerSetNamespace,
|
||||
LabelKeyGitHubScaleSetName: autoscalingListener.Spec.AutoscalingRunnerSetName,
|
||||
}),
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,45 @@ func TestLabelPropagation(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestListenerServiceAccountMetadata(t *testing.T) {
|
||||
autoscalingRunnerSet := v1alpha1.AutoscalingRunnerSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-scale-set",
|
||||
Namespace: "test-ns",
|
||||
Labels: map[string]string{
|
||||
LabelKeyKubernetesVersion: "0.2.0",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
runnerScaleSetIDAnnotationKey: "1",
|
||||
AnnotationKeyGitHubRunnerGroupName: "test-group",
|
||||
AnnotationKeyGitHubRunnerScaleSetName: "test-scale-set",
|
||||
},
|
||||
},
|
||||
Spec: v1alpha1.AutoscalingRunnerSetSpec{
|
||||
GitHubConfigUrl: "https://github.com/org/repo",
|
||||
ListenerServiceAccount: &v1alpha1.ListenerServiceAccount{
|
||||
Annotations: map[string]string{
|
||||
"example.com/annotation": "test-value",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
"example.com/label": "label-value",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var b ResourceBuilder
|
||||
ephemeralRunnerSet, err := b.newEphemeralRunnerSet(&autoscalingRunnerSet)
|
||||
require.NoError(t, err)
|
||||
|
||||
listener, err := b.newAutoScalingListener(&autoscalingRunnerSet, ephemeralRunnerSet, autoscalingRunnerSet.Namespace, "test:latest", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
serviceAccount := b.newScaleSetListenerServiceAccount(listener)
|
||||
assert.Equal(t, "test-value", serviceAccount.Annotations["example.com/annotation"])
|
||||
assert.Equal(t, "label-value", serviceAccount.Labels["example.com/label"])
|
||||
}
|
||||
|
||||
func TestGitHubURLTrimLabelValues(t *testing.T) {
|
||||
enterprise := strings.Repeat("a", 64)
|
||||
organization := strings.Repeat("b", 64)
|
||||
|
|
|
|||
Loading…
Reference in New Issue