Commit 9d14009e authored by Edmund Ochieng's avatar Edmund Ochieng

Merge branch 'runner-enhancements' into 'master'

Runner enhancements

See merge request !27
parents ff4b13a1 6d3ea839
Pipeline #193470316 passed with stages
in 18 minutes and 35 seconds
......@@ -29,10 +29,19 @@ type RunnerSpec struct {
//Name of secret containing the runner-registration-token key used to register the runner
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Registration Token",xDescriptors="urn:alm:descriptor:com.tectonic.ui:selector:core:v1:Secret"
RegistrationToken string `json:"token,omitempty"`
// List of comma separated tags to be applied to the runner
// +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Tags",xDescriptors="urn:alm:descriptor:com.tectonic.ui:text"
Tags string `json:"tags,omitempty"`
// Concurrent limits the number of jobs globally that can run concurrently
// +operator-sdk:csv:customresourcedefinitions:type=status,displayName="Concurrent",xDescriptors="urn:alm:descriptor:com.tectonic.ui:text"
Concurrent *int32 `json:"concurrent,omitempty"`
// CheckInterval defines the number of seconds between checks for new jobs
// +operator-sdk:csv:customresourcedefinitions:type=status,displayName="Check Interval",xDescriptors="urn:alm:descriptor:com.tectonic.ui:text"
CheckInterval *int32 `json:"interval,omitempty"`
// Cache defines an S3 compatible object store
Cache *RunnerCacheSpec `json:"cache,omitempty"`
}
......
......@@ -454,6 +454,16 @@ func (in *RunnerList) DeepCopyObject() runtime.Object {
func (in *RunnerSpec) DeepCopyInto(out *RunnerSpec) {
*out = *in
out.Gitlab = in.Gitlab
if in.Concurrent != nil {
in, out := &in.Concurrent, &out.Concurrent
*out = new(int32)
**out = **in
}
if in.CheckInterval != nil {
in, out := &in.CheckInterval, &out.CheckInterval
*out = new(int32)
**out = **in
}
if in.Cache != nil {
in, out := &in.Cache, &out.Cache
*out = new(RunnerCacheSpec)
......
......@@ -52,6 +52,10 @@ spec:
description: S3 cache server URL
type: string
type: object
concurrent:
description: Concurrent limits the number of jobs globally that can run concurrently
format: int32
type: integer
gitlab:
description: GitlabResource represents a Gitlab custom resource. Should only be used to reference Gitlab instance created by the operator
properties:
......@@ -62,6 +66,10 @@ spec:
description: URL of GitLab instance
type: string
type: object
interval:
description: CheckInterval defines the number of seconds between checks for new jobs
format: int32
type: integer
tags:
description: List of comma separated tags to be applied to the runner
type: string
......
......@@ -384,6 +384,14 @@ spec:
- patch
- update
- watch
- apiGroups:
- apps.gitlab.com
resources:
- runners/finalizers
verbs:
- delete
- patch
- update
- apiGroups:
- apps.gitlab.com
resources:
......
......@@ -58,6 +58,11 @@ spec:
description: S3 cache server URL
type: string
type: object
concurrent:
description: Concurrent limits the number of jobs globally that can
run concurrently
format: int32
type: integer
gitlab:
description: GitlabResource represents a Gitlab custom resource. Should
only be used to reference Gitlab instance created by the operator
......@@ -69,6 +74,11 @@ spec:
description: URL of GitLab instance
type: string
type: object
interval:
description: CheckInterval defines the number of seconds between checks
for new jobs
format: int32
type: integer
tags:
description: List of comma separated tags to be applied to the runner
type: string
......
......@@ -37,6 +37,7 @@ import (
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
certmanagerv1beta1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1beta1"
nginxv1alpha1 "github.com/nginxinc/nginx-ingress-operator/pkg/apis/k8s/v1alpha1"
routev1 "github.com/openshift/api/route/v1"
gitlabv1beta1 "gitlab.com/gitlab-org/gl-openshift/gitlab-operator/api/v1beta1"
gitlabctl "gitlab.com/gitlab-org/gl-openshift/gitlab-operator/controllers/gitlab"
......@@ -80,7 +81,7 @@ func (r *GitLabReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
ctx := context.Background()
log := r.Log.WithValues("gitlab", req.NamespacedName)
log.Info("Reconciling GitLab object", "Name", req.NamespacedName.Name)
log.Info("Reconciling GitLab", "name", req.NamespacedName.Name, "namespace", req.NamespacedName.Namespace)
gitlab := &gitlabv1beta1.GitLab{}
if err := r.Get(ctx, req.NamespacedName, gitlab); err != nil {
if errors.IsNotFound(err) {
......@@ -172,7 +173,7 @@ func (r *GitLabReconciler) SetupWithManager(mgr ctrl.Manager) error {
Owns(&monitoringv1.ServiceMonitor{}).
Owns(&certmanagerv1beta1.Issuer{}).
Owns(&certmanagerv1beta1.Certificate{}).
// Owns(&nginxv1alpha1.NginxIngressController{}).
Owns(&nginxv1alpha1.NginxIngressController{}).
Complete(r)
}
......
package runner
import (
"bytes"
"fmt"
"text/template"
gitlabv1beta1 "gitlab.com/gitlab-org/gl-openshift/gitlab-operator/api/v1beta1"
gitlabutils "gitlab.com/gitlab-org/gl-openshift/gitlab-operator/controllers/utils"
corev1 "k8s.io/api/core/v1"
)
// Config struct holds the values used to
// configure Runner Global options
type Config struct {
Concurrent int32
CheckInterval int32
}
func userOptions(cr *gitlabv1beta1.Runner) Config {
options := Config{Concurrent: 10, CheckInterval: 30}
if cr.Spec.Concurrent != nil {
options.Concurrent = *cr.Spec.Concurrent
}
if cr.Spec.CheckInterval != nil {
options.CheckInterval = *cr.Spec.CheckInterval
}
return options
}
// GetConfigMap returns the runner configmap object
func GetConfigMap(cr *gitlabv1beta1.Runner) *corev1.ConfigMap {
labels := gitlabutils.Label(cr.Name, "runner", gitlabutils.RunnerType)
var gitlabURL string
configToml := gitlabutils.ReadConfig("/templates/gitlab-runner/config.toml")
var configToml bytes.Buffer
configTemplate := template.Must(template.ParseFiles("/templates/gitlab-runner/config.toml"))
configTemplate.Execute(&configToml, userOptions(cr))
entrypointScript := gitlabutils.ReadConfig("/templates/gitlab-runner/entrypoint.sh")
configureScript := gitlabutils.ReadConfig("/templates/gitlab-runner/configure.sh")
registrationScript := gitlabutils.ReadConfig("/templates/gitlab-runner/registration.sh")
......@@ -36,7 +63,7 @@ func GetConfigMap(cr *gitlabv1beta1.Runner) *corev1.ConfigMap {
runnerConfigMap := gitlabutils.GenericConfigMap(labels["app.kubernetes.io/instance"]+"-config", cr.Namespace, labels)
runnerConfigMap.Data = map[string]string{
"ci_server_url": gitlabURL,
"config.toml": configToml,
"config.toml": configToml.String(),
"entrypoint": entrypointScript,
"check-live": aliveScript,
"register-runner": registrationScript,
......
......@@ -205,7 +205,7 @@ func GetDeployment(cr *gitlabv1beta1.Runner) *appsv1.Deployment {
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: cr.Name + "-runner-secret",
Name: RegistrationTokenSecretName(cr),
},
Key: "runner-token",
},
......@@ -216,7 +216,7 @@ func GetDeployment(cr *gitlabv1beta1.Runner) *appsv1.Deployment {
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: cr.Name + "-runner-secret",
Name: RegistrationTokenSecretName(cr),
},
Key: "runner-registration-token",
},
......@@ -445,7 +445,7 @@ func runnerSecretsVolume(cr *gitlabv1beta1.Runner) []corev1.VolumeProjection {
{
Secret: &corev1.SecretProjection{
LocalObjectReference: corev1.LocalObjectReference{
Name: cr.Name + "-runner-secret",
Name: RegistrationTokenSecretName(cr),
},
Items: []corev1.KeyToPath{
{
......@@ -514,3 +514,21 @@ func runnerConfig(cr *gitlabv1beta1.Runner) (options runnerOptions) {
return
}
// RegistrationTokenSecretName returns name of secret containing the
// runner-registration-token and runner-token keys
func RegistrationTokenSecretName(cr *gitlabv1beta1.Runner) string {
var tokenSecretName string
if cr.Spec.Gitlab.Name != "" {
tokenSecretName = cr.Spec.Gitlab.Name + "-runner-token-secret"
}
if cr.Spec.RegistrationToken != "" {
// If user provides a secret with registration token
// set it to the gitlab secret
tokenSecretName = cr.Spec.RegistrationToken
}
return tokenSecretName
}
package runner
import (
gitlabv1beta1 "gitlab.com/gitlab-org/gl-openshift/gitlab-operator/api/v1beta1"
gitlabutils "gitlab.com/gitlab-org/gl-openshift/gitlab-operator/controllers/utils"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// GetSecret returns the runners secret object
func GetSecret(client client.Client, cr *gitlabv1beta1.Runner) (*corev1.Secret, error) {
labels := gitlabutils.Label(cr.Name, "runner", gitlabutils.RunnerType)
var gitlabSecret, token string
var err error
if cr.Spec.Gitlab.Name != "" {
gitlabSecret = cr.Spec.Gitlab.Name + "-runner-token-secret"
}
if cr.Spec.RegistrationToken != "" {
// If user provides a secret with registration token
// set it to the gitlab secret
gitlabSecret = cr.Spec.RegistrationToken
}
token, err = gitlabutils.GetSecretValue(client, cr.Namespace, gitlabSecret, "runner-registration-token")
if err != nil {
return nil, err
}
runnerSecret := gitlabutils.GenericSecret(labels["app.kubernetes.io/instance"]+"-secret", cr.Namespace, labels)
runnerSecret.StringData = map[string]string{
"runner-registration-token": token,
"runner-token": "",
}
return runnerSecret, nil
}
......@@ -18,6 +18,7 @@ package controllers
import (
"context"
"fmt"
"reflect"
"github.com/go-logr/logr"
......@@ -26,6 +27,7 @@ import (
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
monitoringv1 "github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1"
gitlabv1beta1 "gitlab.com/gitlab-org/gl-openshift/gitlab-operator/api/v1beta1"
......@@ -65,7 +67,7 @@ func (r *RunnerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
return ctrl.Result{}, err
}
if err := r.reconcileSecrets(ctx, runner); err != nil {
if err := r.validateRegistrationTokenSecret(ctx, runner); err != nil {
return ctrl.Result{}, err
}
......@@ -73,7 +75,7 @@ func (r *RunnerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
return ctrl.Result{}, err
}
if err := r.reconcileStatus(runner); err != nil {
if err := r.reconcileStatus(ctx, runner); err != nil {
return ctrl.Result{}, err
}
......@@ -99,30 +101,6 @@ func (r *RunnerReconciler) SetupWithManager(mgr ctrl.Manager) error {
Complete(r)
}
func (r *RunnerReconciler) reconcileSecrets(ctx context.Context, cr *gitlabv1beta1.Runner) error {
tokens, err := runnerctl.GetSecret(r, cr)
if err != nil {
return err
}
found := &corev1.Secret{}
err = r.Get(ctx, types.NamespacedName{Name: tokens.Name, Namespace: cr.Namespace}, found)
if err != nil {
if errors.IsNotFound(err) {
return r.Create(ctx, tokens)
}
return err
}
if reflect.DeepEqual(tokens.Data, found.Data) {
found.Data = tokens.Data
return r.Update(ctx, found)
}
return nil
}
func (r *RunnerReconciler) reconcileConfigMaps(ctx context.Context, cr *gitlabv1beta1.Runner) error {
configs := runnerctl.GetConfigMap(cr)
......@@ -130,13 +108,17 @@ func (r *RunnerReconciler) reconcileConfigMaps(ctx context.Context, cr *gitlabv1
err := r.Get(ctx, types.NamespacedName{Name: configs.Name, Namespace: cr.Namespace}, found)
if err != nil {
if errors.IsNotFound(err) {
if err := controllerutil.SetControllerReference(cr, configs, r.Scheme); err != nil {
return err
}
return r.Create(ctx, configs)
}
return err
}
if reflect.DeepEqual(configs.Data, found.Data) {
if !reflect.DeepEqual(configs.Data, found.Data) {
found.Data = configs.Data
return r.Update(ctx, found)
}
......@@ -151,13 +133,17 @@ func (r *RunnerReconciler) reconcileDeployments(ctx context.Context, cr *gitlabv
err := r.Get(ctx, types.NamespacedName{Name: runner.Name, Namespace: cr.Namespace}, found)
if err != nil {
if errors.IsNotFound(err) {
if err := controllerutil.SetControllerReference(cr, runner, r.Scheme); err != nil {
return err
}
return r.Create(ctx, runner)
}
return err
}
if reflect.DeepEqual(runner.Spec, found.Spec) {
if !reflect.DeepEqual(runner.Spec, found.Spec) {
found.Spec = runner.Spec
return r.Update(ctx, found)
}
......@@ -165,9 +151,9 @@ func (r *RunnerReconciler) reconcileDeployments(ctx context.Context, cr *gitlabv
return nil
}
func (r *RunnerReconciler) updateRunnerStatus(cr *gitlabv1beta1.Runner, consoleLog string) error {
func (r *RunnerReconciler) updateRunnerStatus(ctx context.Context, cr *gitlabv1beta1.Runner, consoleLog string) error {
runner := &gitlabv1beta1.Runner{}
err := r.Get(context.TODO(), types.NamespacedName{Name: cr.Name, Namespace: cr.Namespace}, runner)
err := r.Get(ctx, types.NamespacedName{Name: cr.Name, Namespace: cr.Namespace}, runner)
if err != nil {
return err
}
......@@ -179,10 +165,10 @@ func (r *RunnerReconciler) updateRunnerStatus(cr *gitlabv1beta1.Runner, consoleL
runner.Status.Phase = "Initializing"
}
return r.Status().Update(context.TODO(), runner)
return r.Status().Update(ctx, runner)
}
func (r *RunnerReconciler) reconcileStatus(cr *gitlabv1beta1.Runner) error {
func (r *RunnerReconciler) reconcileStatus(ctx context.Context, cr *gitlabv1beta1.Runner) error {
client, err := gitlabutils.KubernetesConfig().NewKubernetesClient()
if err != nil {
......@@ -202,7 +188,7 @@ func (r *RunnerReconciler) reconcileStatus(cr *gitlabv1beta1.Runner) error {
}
}
if err := r.updateRunnerStatus(cr, log); err != nil {
if err := r.updateRunnerStatus(ctx, cr, log); err != nil {
return err
}
......@@ -216,15 +202,20 @@ func (r *RunnerReconciler) reconcileMetrics(ctx context.Context, cr *gitlabv1bet
err := r.Get(ctx, types.NamespacedName{Name: svc.Name, Namespace: cr.Namespace}, found)
if err != nil {
if errors.IsNotFound(err) {
if err := controllerutil.SetControllerReference(cr, svc, r.Scheme); err != nil {
return err
}
return r.Create(ctx, svc)
}
return err
}
if reflect.DeepEqual(svc.Spec, found.Spec) {
found.Spec = svc.Spec
return r.Update(ctx, found)
if !reflect.DeepEqual(svc.Spec, found.Spec) {
// besides ClusterIP, not much is expected to change
// return r.Update(ctx, found)
return nil
}
return nil
......@@ -239,13 +230,17 @@ func (r *RunnerReconciler) reconcileServiceMonitor(ctx context.Context, cr *gitl
err := r.Get(ctx, types.NamespacedName{Name: sm.Name, Namespace: cr.Namespace}, found)
if err != nil {
if errors.IsNotFound(err) {
if err := controllerutil.SetControllerReference(cr, sm, r.Scheme); err != nil {
return err
}
return r.Create(ctx, sm)
}
return err
}
if reflect.DeepEqual(sm.Spec, found.Spec) {
if !reflect.DeepEqual(sm.Spec, found.Spec) {
found.Spec = sm.Spec
return r.Update(ctx, found)
}
......@@ -253,3 +248,30 @@ func (r *RunnerReconciler) reconcileServiceMonitor(ctx context.Context, cr *gitl
return nil
}
func (r *RunnerReconciler) validateRegistrationTokenSecret(ctx context.Context, cr *gitlabv1beta1.Runner) error {
tokenSecretName := runnerctl.RegistrationTokenSecretName(cr)
found := &corev1.Secret{}
err := r.Get(ctx, types.NamespacedName{Name: tokenSecretName, Namespace: cr.Namespace}, found)
if err != nil {
return err
}
registrationToken, ok := found.Data["runner-registration-token"]
if !ok {
return fmt.Errorf("runner-registration-token key not found in %s secret", tokenSecretName)
}
tokenStr := string(registrationToken)
if tokenStr == "" {
return fmt.Errorf("runner-registration-token can not be empty")
}
if _, ok := found.StringData["runner-token"]; !ok {
found.Data["runner-token"] = []byte("")
return r.Update(ctx, found)
}
return nil
}
concurrent = 10
check_interval = 30
concurrent = {{ .Concurrent }}
check_interval = {{ .CheckInterval }}
log_level = "info"
listen_address = '[::]:9252'
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment