diff --git a/hack/tests/e2e-ansible-molecule.sh b/hack/tests/e2e-ansible-molecule.sh index 72434ddd3e1..f29daa6d721 100755 --- a/hack/tests/e2e-ansible-molecule.sh +++ b/hack/tests/e2e-ansible-molecule.sh @@ -43,7 +43,7 @@ cat "$ROOTDIR/test/ansible-memcached/watches-finalizer.yaml" >> watches.yaml header_text "Append v1 kind to watches to test watching already registered GVK" cat "$ROOTDIR/test/ansible-memcached/watches-v1-kind.yaml" >> watches.yaml echo $marker >> watches.yaml -sed -i'.bak' -e '/- secrets/a \ \ - services' config/rbac/role.yaml; rm -f config/rbac/role.yaml.bak +sed -i'.bak' -e '/- secrets/a \ \ \ \ \ \ - services' config/rbac/role.yaml; rm -f config/rbac/role.yaml.bak header_text "Test in kind" sed -i".bak" -E -e 's/(FROM quay.io\/operator-framework\/ansible-operator)(:.*)?/\1:dev/g' Dockerfile; rm -f Dockerfile.bak diff --git a/internal/plugins/ansible/v1/scaffolds/api.go b/internal/plugins/ansible/v1/scaffolds/api.go index 44f377125f5..6dd7cd27f60 100644 --- a/internal/plugins/ansible/v1/scaffolds/api.go +++ b/internal/plugins/ansible/v1/scaffolds/api.go @@ -97,8 +97,9 @@ func (s *apiScaffolder) scaffold() error { var createAPITemplates []file.Builder createAPITemplates = append(createAPITemplates, + &rbac.CRDViewerRole{}, &rbac.CRDEditorRole{}, - &rbac.KustomizeUpdater{}, + &rbac.ManagerRoleUpdater{}, &crd.CRD{CRDVersion: s.opts.CRDVersion}, &crd.Kustomization{}, diff --git a/internal/plugins/ansible/v1/scaffolds/init.go b/internal/plugins/ansible/v1/scaffolds/init.go index 718d6590230..b6631118a37 100644 --- a/internal/plugins/ansible/v1/scaffolds/init.go +++ b/internal/plugins/ansible/v1/scaffolds/init.go @@ -90,7 +90,7 @@ func (s *initScaffolder) scaffold() error { &rbac.AuthProxyService{}, &rbac.LeaderElectionRole{}, &rbac.LeaderElectionRoleBinding{}, - &rbac.Role{}, + &rbac.ManagerRole{}, &rbac.RoleBinding{}, &prometheus.Kustomization{}, diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/patch_crd_editor.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/crd_editor_rbac.go similarity index 63% rename from internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/patch_crd_editor.go rename to internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/crd_editor_rbac.go index 8e5f5e29303..44c28e88866 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/patch_crd_editor.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/crd_editor_rbac.go @@ -1,5 +1,5 @@ /* -Copyright 2020 The Operator-SDK Authors +Copyright 2018 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -33,7 +33,7 @@ type CRDEditorRole struct { // SetTemplateDefaults implements input.Template func (f *CRDEditorRole) SetTemplateDefaults() error { if f.Path == "" { - f.Path = filepath.Join("config", "rbac", "patches", "%[kind]_editor_role.yaml") + f.Path = filepath.Join("config", "rbac", "%[kind]_editor_role.yaml") } f.Path = f.Resource.Replacer().Replace(f.Path) @@ -42,31 +42,28 @@ func (f *CRDEditorRole) SetTemplateDefaults() error { return nil } -const crdRoleEditorTemplate = `--- -- op: add - path: /rules/- - value: - apiGroups: - - {{ .Resource.Domain }} - resources: - - {{ .Resource.Plural }} - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- op: add - path: /rules/- - value: - apiGroups: - - {{ .Resource.Domain }} - resources: - - {{ .Resource.Plural }}/status - verbs: - - get - - patch - - update +const crdRoleEditorTemplate = `# permissions for end users to edit {{ .Resource.Plural }}. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ lower .Resource.Kind }}-editor-role +rules: +- apiGroups: + - {{ .Resource.Domain }} + resources: + - {{ .Resource.Plural }} + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - {{ .Resource.Domain }} + resources: + - {{ .Resource.Plural }}/status + verbs: + - get ` diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/crd_viewer_rbac.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/crd_viewer_rbac.go new file mode 100644 index 00000000000..2591e509167 --- /dev/null +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/crd_viewer_rbac.go @@ -0,0 +1,65 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rbac + +import ( + "path/filepath" + + "sigs.k8s.io/kubebuilder/pkg/model/file" +) + +var _ file.Template = &CRDViewerRole{} + +// CRDViewerRole scaffolds the config/rbac/_viewer_role.yaml +type CRDViewerRole struct { + file.TemplateMixin + file.ResourceMixin +} + +// SetTemplateDefaults implements input.Template +func (f *CRDViewerRole) SetTemplateDefaults() error { + if f.Path == "" { + f.Path = filepath.Join("config", "rbac", "%[kind]_viewer_role.yaml") + } + f.Path = f.Resource.Replacer().Replace(f.Path) + + f.TemplateBody = crdRoleViewerTemplate + + return nil +} + +const crdRoleViewerTemplate = `# permissions for end users to view {{ .Resource.Plural }}. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ lower .Resource.Kind }}-viewer-role +rules: +- apiGroups: + - {{ .Resource.Domain }} + resources: + - {{ .Resource.Plural }} + verbs: + - get + - list + - watch +- apiGroups: + - {{ .Resource.Domain }} + resources: + - {{ .Resource.Plural }}/status + verbs: + - get +` diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/kustomization.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/kustomization.go index ae19ccfa544..f3de8307aa2 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/kustomization.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/kustomization.go @@ -1,6 +1,5 @@ /* Copyright 2019 The Kubernetes Authors. -Modifications copyright 2020 The Operator-SDK Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,7 +17,6 @@ limitations under the License. package rbac import ( - "fmt" "path/filepath" "sigs.k8s.io/kubebuilder/pkg/model/file" @@ -26,10 +24,6 @@ import ( var _ file.Template = &Kustomization{} -var rbacKustomizePath = filepath.Join("config", "rbac", "kustomization.yaml") - -const patch6902Marker = "patch6902" - // Kustomization scaffolds the Kustomization file in rbac folder. type Kustomization struct { file.TemplateMixin @@ -38,73 +32,26 @@ type Kustomization struct { // SetTemplateDefaults implements input.Template func (f *Kustomization) SetTemplateDefaults() error { if f.Path == "" { - f.Path = rbacKustomizePath + f.Path = filepath.Join("config", "rbac", "kustomization.yaml") } - f.TemplateBody = fmt.Sprintf(kustomizeTemplate, - file.NewMarkerFor(f.Path, patch6902Marker), - ) + f.TemplateBody = kustomizeRBACTemplate + f.IfExistsAction = file.Error return nil } -type KustomizeUpdater struct { - file.TemplateMixin - file.ResourceMixin -} - -func (*KustomizeUpdater) GetIfExistsAction() file.IfExistsAction { - return file.Overwrite -} - -func (*KustomizeUpdater) GetPath() string { - return rbacKustomizePath -} - -func (f *KustomizeUpdater) GetMarkers() []file.Marker { - return []file.Marker{ - file.NewMarkerFor(rbacKustomizePath, patch6902Marker), - } -} - -func (f *KustomizeUpdater) GetCodeFragments() file.CodeFragmentsMap { - fragments := make(file.CodeFragmentsMap, 1) - - // If resource is not being provided we are creating the file, not updating it - if f.Resource == nil { - return fragments - } - - // Generate patch6902 fragments - patches := make([]string, 0) - patches = append(patches, f.Resource.Replacer().Replace(patch6902Fragment)) - - if len(patches) != 0 { - fragments[file.NewMarkerFor(rbacKustomizePath, patch6902Marker)] = patches - } - return fragments -} - -const kustomizeTemplate = `resources: - - role.yaml - - role_binding.yaml - - leader_election_role.yaml - - leader_election_role_binding.yaml - # Comment the following 4 lines if you want to disable - # the auth proxy (https://github.com/brancz/kube-rbac-proxy) - # which protects your /metrics endpoint. - - auth_proxy_service.yaml - - auth_proxy_role.yaml - - auth_proxy_role_binding.yaml - - auth_proxy_client_clusterrole.yaml -patchesJson6902: -%s -` -const patch6902Fragment = ` - target: - group: rbac.authorization.k8s.io - version: v1 - kind: ClusterRole - name: manager-role - path: patches/%[kind]_editor_role.yaml +const kustomizeRBACTemplate = `resources: +- role.yaml +- role_binding.yaml +- leader_election_role.yaml +- leader_election_role_binding.yaml +# Comment the following 4 lines if you want to disable +# the auth proxy (https://github.com/brancz/kube-rbac-proxy) +# which protects your /metrics endpoint. +- auth_proxy_service.yaml +- auth_proxy_role.yaml +- auth_proxy_role_binding.yaml +- auth_proxy_client_clusterrole.yaml ` diff --git a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/role.go b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/role.go index 8dd8fe700a2..a285e6b473a 100644 --- a/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/role.go +++ b/internal/plugins/ansible/v1/scaffolds/internal/templates/config/rbac/role.go @@ -1,5 +1,5 @@ // Copyright 2019 The Operator-SDK Authors -// Modifications copyright 2020 The Operator-SDK Authors +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -15,63 +15,142 @@ package rbac import ( + "bytes" + "fmt" "path/filepath" + "text/template" "sigs.k8s.io/kubebuilder/pkg/model/file" ) -var _ file.Template = &Role{} +var _ file.Template = &ManagerRole{} + +var defaultRoleFile = filepath.Join("config", "rbac", "role.yaml") -// Role scaffolds the config/rbac/auth_proxy_role.yaml file -type Role struct { +// ManagerRole scaffolds the role.yaml file +type ManagerRole struct { file.TemplateMixin } // SetTemplateDefaults implements input.Template -func (f *Role) SetTemplateDefaults() error { +func (f *ManagerRole) SetTemplateDefaults() error { if f.Path == "" { - f.Path = filepath.Join("config", "rbac", "role.yaml") + f.Path = defaultRoleFile } - f.TemplateBody = roleTemplate - + f.TemplateBody = fmt.Sprintf(roleTemplate, + file.NewMarkerFor(f.Path, rulesMarker), + ) return nil } +var _ file.Inserter = &ManagerRoleUpdater{} + +type ManagerRoleUpdater struct { + file.TemplateMixin + file.ResourceMixin + + SkipDefaultRules bool +} + +func (*ManagerRoleUpdater) GetPath() string { + return defaultRoleFile +} + +func (*ManagerRoleUpdater) GetIfExistsAction() file.IfExistsAction { + return file.Overwrite +} + +const ( + rulesMarker = "rules" +) + +func (f *ManagerRoleUpdater) GetMarkers() []file.Marker { + return []file.Marker{ + file.NewMarkerFor(defaultRoleFile, rulesMarker), + } +} + +func (f *ManagerRoleUpdater) GetCodeFragments() file.CodeFragmentsMap { + fragments := make(file.CodeFragmentsMap, 1) + + // If resource is not being provided we are creating the file, not updating it + if f.Resource == nil { + return fragments + } + + buf := &bytes.Buffer{} + tmpl := template.Must(template.New("rules").Parse(rulesFragment)) + err := tmpl.Execute(buf, f) + if err != nil { + panic(err) + } + + // Generate rule fragment + rules := []string{buf.String()} + + if len(rules) != 0 { + fragments[file.NewMarkerFor(defaultRoleFile, rulesMarker)] = rules + } + return fragments +} + const roleTemplate = `--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: manager-role rules: -- apiGroups: - - "" - resources: - - secrets - - pods - - pods/exec - - pods/log - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - apps - resources: - - deployments - - daemonsets - - replicasets - - statefulsets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch + ## + ## Base operator rules + ## + - apiGroups: + - "" + resources: + - secrets + - pods + - pods/exec + - pods/log + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +%s +` + +const rulesFragment = ` ## + ## Rules for {{.Resource.Domain}}/{{.Resource.Version}}, Kind: {{.Resource.Kind}} + ## + - apiGroups: + - {{.Resource.Domain}} + resources: + - {{.Resource.Plural}} + - {{.Resource.Plural}}/status + verbs: + - create + - delete + - get + - list + - patch + - update + - watch `