diff --git a/controllers/runnerdeployment_controller.go b/controllers/runnerdeployment_controller.go index 6d4e004b..a37bbad6 100644 --- a/controllers/runnerdeployment_controller.go +++ b/controllers/runnerdeployment_controller.go @@ -48,9 +48,10 @@ const ( // RunnerDeploymentReconciler reconciles a Runner object type RunnerDeploymentReconciler struct { client.Client - Log logr.Logger - Recorder record.EventRecorder - Scheme *runtime.Scheme + Log logr.Logger + Recorder record.EventRecorder + Scheme *runtime.Scheme + CommonRunnerLabels []string } // +kubebuilder:rbac:groups=actions.summerwind.dev,resources=runnerdeployments,verbs=get;list;watch;create;update;patch;delete @@ -262,6 +263,10 @@ func (r *RunnerDeploymentReconciler) newRunnerReplicaSet(rd v1alpha1.RunnerDeplo // Add template hash label to selector. labels := CloneAndAddLabel(rd.Spec.Template.Labels, LabelKeyRunnerTemplateHash, templateHash) + for _, l := range r.CommonRunnerLabels { + newRSTemplate.Spec.Labels = append(newRSTemplate.Spec.Labels, l) + } + newRSTemplate.Labels = labels rs := v1alpha1.RunnerReplicaSet{ diff --git a/controllers/runnerdeployment_controller_test.go b/controllers/runnerdeployment_controller_test.go index 51a5656d..c25ce82c 100644 --- a/controllers/runnerdeployment_controller_test.go +++ b/controllers/runnerdeployment_controller_test.go @@ -2,6 +2,9 @@ package controllers import ( "context" + "github.com/google/go-cmp/cmp" + "k8s.io/apimachinery/pkg/runtime" + "testing" "time" corev1 "k8s.io/api/core/v1" @@ -18,6 +21,40 @@ import ( actionsv1alpha1 "github.com/summerwind/actions-runner-controller/api/v1alpha1" ) +func TestNewRunnerReplicaSet(t *testing.T) { + scheme := runtime.NewScheme() + if err := actionsv1alpha1.AddToScheme(scheme); err != nil { + t.Fatalf("%v", err) + } + + r := &RunnerDeploymentReconciler{ + CommonRunnerLabels: []string{"dev"}, + Scheme: scheme, + } + rd := actionsv1alpha1.RunnerDeployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "example", + }, + Spec: actionsv1alpha1.RunnerDeploymentSpec{ + Template: actionsv1alpha1.RunnerTemplate{ + Spec: actionsv1alpha1.RunnerSpec{ + Labels: []string{"project1"}, + }, + }, + }, + } + + rs, err := r.newRunnerReplicaSet(rd) + if err != nil { + t.Fatalf("%v", err) + } + + want := []string{"project1", "dev"} + if d := cmp.Diff(want, rs.Spec.Template.Spec.Labels); d != "" { + t.Errorf("%s", d) + } +} + // SetupDeploymentTest will set up a testing environment. // This includes: // * creating a Namespace to be used during the test diff --git a/go.mod b/go.mod index bcb81699..3d5c78d6 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/bradleyfalzon/ghinstallation v1.1.1 github.com/davecgh/go-spew v1.1.1 github.com/go-logr/logr v0.1.0 + github.com/google/go-cmp v0.3.1 github.com/google/go-github/v33 v33.0.1-0.20210204004227-319dcffb518a github.com/gorilla/mux v1.8.0 github.com/kelseyhightower/envconfig v1.4.0 diff --git a/main.go b/main.go index 7f22e752..1defb842 100644 --- a/main.go +++ b/main.go @@ -20,6 +20,7 @@ import ( "flag" "fmt" "os" + "strings" "time" "github.com/kelseyhightower/envconfig" @@ -62,6 +63,8 @@ func main() { runnerImage string dockerImage string + + commonRunnerLabels commaSeparatedStringSlice ) var c github.Config @@ -80,6 +83,7 @@ func main() { flag.Int64Var(&c.AppInstallationID, "github-app-installation-id", c.AppInstallationID, "The installation ID of GitHub App.") flag.StringVar(&c.AppPrivateKey, "github-app-private-key", c.AppPrivateKey, "The path of a private key file to authenticate as a GitHub App") flag.DurationVar(&syncPeriod, "sync-period", 10*time.Minute, "Determines the minimum frequency at which K8s resources managed by this controller are reconciled. When you use autoscaling, set to a lower value like 10 minute, because this corresponds to the minimum time to react on demand change") + flag.Var(&commonRunnerLabels, "common-runner-labels", "Runner labels in the K1=V1,K2=V2,... format that are inherited all the runners created by the controller. See https://github.com/summerwind/actions-runner-controller/issues/321 for more information") flag.Parse() logger := zap.New(func(o *zap.Options) { @@ -133,9 +137,10 @@ func main() { } runnerDeploymentReconciler := &controllers.RunnerDeploymentReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("RunnerDeployment"), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("RunnerDeployment"), + Scheme: mgr.GetScheme(), + CommonRunnerLabels: commonRunnerLabels, } if err = runnerDeploymentReconciler.SetupWithManager(mgr); err != nil { @@ -176,3 +181,20 @@ func main() { os.Exit(1) } } + +type commaSeparatedStringSlice []string + +func (s *commaSeparatedStringSlice) String() string { + return fmt.Sprintf("%v", *s) +} + +func (s *commaSeparatedStringSlice) Set(value string) error { + for _, v := range strings.Split(value, ",") { + if v == "" { + continue + } + + *s = append(*s, v) + } + return nil +}