diff --git a/deploy/role.yaml b/deploy/role.yaml index 550c2878..9cc4e612 100644 --- a/deploy/role.yaml +++ b/deploy/role.yaml @@ -1,41 +1,64 @@ --- -apiVersion: rbac.authorization.k8s.io/v1 kind: Role +apiVersion: rbac.authorization.k8s.io/v1 metadata: - creationTimestamp: null name: jenkins-operator rules: -- apiGroups: - - "" - resources: - - pods - - services - - endpoints - - persistentvolumeclaims - - events - - configmaps - - secrets - verbs: - - '*' -- apiGroups: - - apps - resources: - - deployments - - daemonsets - - replicasets - - statefulsets - verbs: - - '*' -- apiGroups: - - monitoring.coreos.com - resources: - - servicemonitors - verbs: - - get - - create -- apiGroups: - - virtuslab.com - resources: - - '*' - verbs: - - '*' + - apiGroups: + - aurora.tescocloud.com + resources: + - jenkinses + verbs: + - "*" + - apiGroups: + - "" + resources: + - services + - configmaps + - secrets + verbs: + - get + - create + - update + - apiGroups: + - "extensions" + resources: + - ingresses + verbs: + - create + - update + - apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - create + - apiGroups: + - rbac.authorization.k8s.io + resources: + - roles + - rolebindings + verbs: + - create + - update + - apiGroups: + - "" + resources: + - pods/portforward + verbs: + - create + - apiGroups: + - "" + resources: + - pods/log + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - pods + - pods/exec + verbs: + - "*" diff --git a/pkg/controller/jenkins/configuration/base/reconcile.go b/pkg/controller/jenkins/configuration/base/reconcile.go index 142a18f5..db677eb6 100644 --- a/pkg/controller/jenkins/configuration/base/reconcile.go +++ b/pkg/controller/jenkins/configuration/base/reconcile.go @@ -2,14 +2,16 @@ package base import ( "context" + "crypto/sha256" + "encoding/base64" "fmt" "reflect" + "sort" "time" virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" jenkinsclient "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/client" "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/base/resources" - "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/configuration/user/theme" "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/constants" "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/groovy" "github.com/VirtusLab/jenkins-operator/pkg/controller/jenkins/plugin" @@ -82,6 +84,11 @@ func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (*reconcile.Result, jenk } r.logger.V(log.VDebug).Info("User configuration config map is present") + if err := r.createRBAC(metaObject); err != nil { + return &reconcile.Result{}, nil, err + } + r.logger.V(log.VDebug).Info("User configuration config map is present") + if err := r.createService(metaObject); err != nil { return &reconcile.Result{}, nil, err } @@ -226,6 +233,28 @@ func (r *ReconcileJenkinsBaseConfiguration) createUserConfigurationConfigMap(met return nil } +func (r *ReconcileJenkinsBaseConfiguration) createRBAC(meta metav1.ObjectMeta) error { + serviceAccount := resources.NewServiceAccount(meta) + err := r.createOrUpdateResource(serviceAccount) + if err != nil { + return err + } + + role := resources.NewRole(meta) + err = r.createOrUpdateResource(role) + if err != nil { + return err + } + + roleBinding := resources.NewRoleBinding(meta) + err = r.createOrUpdateResource(roleBinding) + if err != nil { + return err + } + + return nil +} + func (r *ReconcileJenkinsBaseConfiguration) createService(meta metav1.ObjectMeta) error { err := r.createResource(resources.NewService(&meta, r.minikube)) if err != nil && !apierrors.IsAlreadyExists(err) { @@ -399,7 +428,27 @@ func (r *ReconcileJenkinsBaseConfiguration) baseConfiguration(jenkinsClient jenk return &reconcile.Result{}, err } - done, err := groovyClient.EnsureGroovyJob(theme.SetThemeGroovyScript, r.jenkins) + configuration := &corev1.ConfigMap{} + namespaceName := types.NamespacedName{Namespace: r.jenkins.Namespace, Name: resources.GetUserConfigurationConfigMapName(r.jenkins)} + err = r.client.Get(context.TODO(), namespaceName, configuration) + if err != nil { + return &reconcile.Result{}, err + } + hash := sha256.New() + + var keys []string + for key, _ := range configuration.Data { + keys = append(keys, key) + } + sort.Strings(keys) + for _, key := range keys { + hash.Write([]byte(key)) + hash.Write([]byte(configuration.Data[key])) + } + + encodedHash := base64.URLEncoding.EncodeToString(hash.Sum(nil)) + + done, err := groovyClient.EnsureGroovyJob(encodedHash, r.jenkins) if err != nil { return &reconcile.Result{}, err } diff --git a/pkg/controller/jenkins/configuration/base/resources/pod.go b/pkg/controller/jenkins/configuration/base/resources/pod.go index 6741014f..ffbfe17d 100644 --- a/pkg/controller/jenkins/configuration/base/resources/pod.go +++ b/pkg/controller/jenkins/configuration/base/resources/pod.go @@ -64,6 +64,7 @@ func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *virtuslabv1alpha TypeMeta: buildPodTypeMeta(), ObjectMeta: objectMeta, Spec: corev1.PodSpec{ + ServiceAccountName: objectMeta.Name, RestartPolicy: corev1.RestartPolicyNever, SecurityContext: &corev1.PodSecurityContext{ RunAsUser: &runAsUser, diff --git a/pkg/controller/jenkins/configuration/base/resources/rbac.go b/pkg/controller/jenkins/configuration/base/resources/rbac.go new file mode 100644 index 00000000..845be317 --- /dev/null +++ b/pkg/controller/jenkins/configuration/base/resources/rbac.go @@ -0,0 +1,71 @@ +package resources + +import ( + "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + createVerb = "create" + deleteVerb = "delete" + getVerb = "get" + listVerb = "list" + watchVerb = "watch" + patchVerb = "patch" + updateVerb = "update" +) + +func NewRole(meta metav1.ObjectMeta) *v1.Role { + return &v1.Role{ + TypeMeta: metav1.TypeMeta{ + Kind: "Role", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: meta, + Rules: []v1.PolicyRule{ + { + APIGroups: []string{""}, + Resources: []string{"pods/portforward"}, + Verbs: []string{createVerb}, + }, + { + APIGroups: []string{""}, + Resources: []string{"pods"}, + Verbs: []string{createVerb, deleteVerb, getVerb, listVerb, patchVerb, updateVerb, watchVerb}, + }, + { + APIGroups: []string{""}, + Resources: []string{"pods/exec"}, + Verbs: []string{createVerb, deleteVerb, getVerb, listVerb, patchVerb, updateVerb, watchVerb}, + }, + { + APIGroups: []string{""}, + Resources: []string{"pods/log"}, + Verbs: []string{getVerb, listVerb, watchVerb}, + }, + //TODO get secrets ??? + }, + } +} + +func NewRoleBinding(meta metav1.ObjectMeta) *v1.RoleBinding { + return &v1.RoleBinding{ + TypeMeta: metav1.TypeMeta{ + Kind: "RoleBinding", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: meta, + RoleRef: v1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: meta.Name, + }, + Subjects: []v1.Subject{ + { + Kind: "ServiceAccount", + Name: meta.Name, + Namespace: meta.Namespace, + }, + }, + } +} diff --git a/pkg/controller/jenkins/configuration/base/resources/service_account.go b/pkg/controller/jenkins/configuration/base/resources/service_account.go new file mode 100644 index 00000000..e84e3f52 --- /dev/null +++ b/pkg/controller/jenkins/configuration/base/resources/service_account.go @@ -0,0 +1,16 @@ +package resources + +import ( + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func NewServiceAccount(meta metav1.ObjectMeta) *v1.ServiceAccount { + return &v1.ServiceAccount{ + TypeMeta: metav1.TypeMeta{ + Kind: "ServiceAccount", + APIVersion: "v1", + }, + ObjectMeta: meta, + } +} diff --git a/pkg/controller/jenkins/groovy/groovy.go b/pkg/controller/jenkins/groovy/groovy.go index 433db96b..fda2c0c4 100644 --- a/pkg/controller/jenkins/groovy/groovy.go +++ b/pkg/controller/jenkins/groovy/groovy.go @@ -1,8 +1,6 @@ package groovy import ( - "crypto/sha256" - "encoding/base64" "fmt" virtuslabv1alpha1 "github.com/VirtusLab/jenkins-operator/pkg/apis/virtuslab/v1alpha1" @@ -44,14 +42,10 @@ func (g *Groovy) ConfigureGroovyJob() error { // EnsureGroovyJob executes groovy script and verifies jenkins job status according to reconciliation loop lifecycle // see https://wiki.jenkins.io/display/JENKINS/Jenkins+Script+Console -func (g *Groovy) EnsureGroovyJob(groovyScript string, jenkins *virtuslabv1alpha1.Jenkins) (bool, error) { +func (g *Groovy) EnsureGroovyJob(hash string, jenkins *virtuslabv1alpha1.Jenkins) (bool, error) { jobsClient := jobs.New(g.jenkinsClient, g.k8sClient, g.logger) - hash := sha256.New() - hash.Write([]byte(groovyScript)) - encodedHash := base64.URLEncoding.EncodeToString(hash.Sum(nil)) - - done, err := jobsClient.EnsureBuildJob(g.jobName, encodedHash, map[string]string{}, jenkins, true) + done, err := jobsClient.EnsureBuildJob(g.jobName, hash, map[string]string{}, jenkins, true) if err != nil { return false, err }