15
15
package scaffold
16
16
17
17
import (
18
+ "encoding/json"
19
+ "errors"
20
+ "fmt"
21
+ "io/ioutil"
22
+ "log"
18
23
"path/filepath"
19
24
25
+ "github.com/operator-framework/operator-sdk/internal/util/fileutil"
20
26
"github.com/operator-framework/operator-sdk/pkg/scaffold/input"
27
+
28
+ yaml "gopkg.in/yaml.v2"
29
+ rbacv1 "k8s.io/api/rbac/v1"
30
+ cgoscheme "k8s.io/client-go/kubernetes/scheme"
21
31
)
22
32
23
33
const RoleYamlFile = "role.yaml"
@@ -34,6 +44,110 @@ func (s *Role) GetInput() (input.Input, error) {
34
44
return s .Input , nil
35
45
}
36
46
47
+ func UpdateRoleForResource (r * Resource , absProjectPath string ) error {
48
+ // append rbac rule to deploy/role.yaml
49
+ roleFilePath := filepath .Join (absProjectPath , DeployDir , RoleYamlFile )
50
+ roleYAML , err := ioutil .ReadFile (roleFilePath )
51
+ if err != nil {
52
+ return fmt .Errorf ("failed to read role manifest %v: %v" , roleFilePath , err )
53
+ }
54
+ obj , _ , err := cgoscheme .Codecs .UniversalDeserializer ().Decode (roleYAML , nil , nil )
55
+ if err != nil {
56
+ return fmt .Errorf ("failed to decode role manifest %v: %v" , roleFilePath , err )
57
+ }
58
+ switch role := obj .(type ) {
59
+ // TODO: use rbac/v1.
60
+ case * rbacv1.Role :
61
+ pr := & rbacv1.PolicyRule {}
62
+ apiGroupFound := false
63
+ for i := range role .Rules {
64
+ if role .Rules [i ].APIGroups [0 ] == r .FullGroup {
65
+ apiGroupFound = true
66
+ pr = & role .Rules [i ]
67
+ break
68
+ }
69
+ }
70
+ // check if the resource already exists
71
+ for _ , resource := range pr .Resources {
72
+ if resource == r .Resource {
73
+ log .Printf ("deploy/role.yaml RBAC rules already up to date for the resource (%v, %v)" , r .APIVersion , r .Kind )
74
+ return nil
75
+ }
76
+ }
77
+
78
+ pr .Resources = append (pr .Resources , r .Resource )
79
+ // create a new apiGroup if not found.
80
+ if ! apiGroupFound {
81
+ pr .APIGroups = []string {r .FullGroup }
82
+ // Using "*" to allow access to the resource and all its subresources e.g "memcacheds" and "memcacheds/finalizers"
83
+ // https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#ownerreferencespermissionenforcement
84
+ pr .Resources = []string {"*" }
85
+ pr .Verbs = []string {"*" }
86
+ role .Rules = append (role .Rules , * pr )
87
+ }
88
+ // update role.yaml
89
+ d , err := json .Marshal (& role )
90
+ if err != nil {
91
+ return fmt .Errorf ("failed to marshal role(%+v): %v" , role , err )
92
+ }
93
+ m := & map [string ]interface {}{}
94
+ err = yaml .Unmarshal (d , m )
95
+ data , err := yaml .Marshal (m )
96
+ if err != nil {
97
+ return fmt .Errorf ("failed to marshal role(%+v): %v" , role , err )
98
+ }
99
+ if err := ioutil .WriteFile (roleFilePath , data , fileutil .DefaultFileMode ); err != nil {
100
+ return fmt .Errorf ("failed to update %v: %v" , roleFilePath , err )
101
+ }
102
+ case * rbacv1.ClusterRole :
103
+ pr := & rbacv1.PolicyRule {}
104
+ apiGroupFound := false
105
+ for i := range role .Rules {
106
+ if role .Rules [i ].APIGroups [0 ] == r .FullGroup {
107
+ apiGroupFound = true
108
+ pr = & role .Rules [i ]
109
+ break
110
+ }
111
+ }
112
+ // check if the resource already exists
113
+ for _ , resource := range pr .Resources {
114
+ if resource == r .Resource {
115
+ log .Printf ("deploy/role.yaml RBAC rules already up to date for the resource (%v, %v)" , r .APIVersion , r .Kind )
116
+ return nil
117
+ }
118
+ }
119
+
120
+ pr .Resources = append (pr .Resources , r .Resource )
121
+ // create a new apiGroup if not found.
122
+ if ! apiGroupFound {
123
+ pr .APIGroups = []string {r .FullGroup }
124
+ // Using "*" to allow access to the resource and all its subresources e.g "memcacheds" and "memcacheds/finalizers"
125
+ // https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#ownerreferencespermissionenforcement
126
+ pr .Resources = []string {"*" }
127
+ pr .Verbs = []string {"*" }
128
+ role .Rules = append (role .Rules , * pr )
129
+ }
130
+ // update role.yaml
131
+ d , err := json .Marshal (& role )
132
+ if err != nil {
133
+ return fmt .Errorf ("failed to marshal role(%+v): %v" , role , err )
134
+ }
135
+ m := & map [string ]interface {}{}
136
+ err = yaml .Unmarshal (d , m )
137
+ data , err := yaml .Marshal (m )
138
+ if err != nil {
139
+ return fmt .Errorf ("failed to marshal role(%+v): %v" , role , err )
140
+ }
141
+ if err := ioutil .WriteFile (roleFilePath , data , fileutil .DefaultFileMode ); err != nil {
142
+ return fmt .Errorf ("failed to update %v: %v" , roleFilePath , err )
143
+ }
144
+ default :
145
+ return errors .New ("failed to parse role.yaml as a role" )
146
+ }
147
+ // not reachable
148
+ return nil
149
+ }
150
+
37
151
const roleTemplate = `kind: Role
38
152
apiVersion: rbac.authorization.k8s.io/v1
39
153
metadata:
0 commit comments