2 * Copyright 2020 Intel Corporation, Inc
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
30 "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext"
31 log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils"
32 pkgerrors "github.com/pkg/errors"
36 type Resource struct {
37 ApiVersion string `yaml:"apiVersion"`
38 Kind string `yaml:"kind"`
39 MetaData MetaDatas `yaml:"metadata"`
40 Specification Specs `yaml:"spec,omitempty"`
41 Rules []RoleRules `yaml:"rules,omitempty"`
42 Subjects []RoleSubjects `yaml:"subjects,omitempty"`
43 RoleRefs RoleRef `yaml:"roleRef,omitempty"`
46 type MetaDatas struct {
47 Name string `yaml:"name"`
48 Namespace string `yaml:"namespace,omitempty"`
52 Request string `yaml:"request,omitempty"`
53 Usages []string `yaml:"usages,omitempty"`
54 //Hard logicalcloud.QSpec `yaml:"hard,omitempty"`
55 Hard QSpec `yaml:"hard,omitempty"`
58 type RoleRules struct {
59 ApiGroups []string `yaml:"apiGroups"`
60 Resources []string `yaml:"resources"`
61 Verbs []string `yaml:"verbs"`
64 type RoleSubjects struct {
65 Kind string `yaml:"kind"`
66 Name string `yaml:"name"`
67 ApiGroup string `yaml:"apiGroup"`
71 Kind string `yaml:"kind"`
72 Name string `yaml:"name"`
73 ApiGroup string `yaml:"apiGroup"`
76 func createNamespace(logicalcloud LogicalCloud) (string, error) {
78 namespace := Resource{
82 Name: logicalcloud.Specification.NameSpace,
86 nsData, err := yaml.Marshal(&namespace)
91 return string(nsData), nil
94 func createRole(logicalcloud LogicalCloud) (string, error) {
96 userPermissions := logicalcloud.Specification.User.UserPermissions[0]
99 ApiVersion: "rbac.authorization.k8s.io/v1beta1",
102 Name: strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-role"}, ""),
103 Namespace: logicalcloud.Specification.NameSpace,
105 Rules: []RoleRules{RoleRules{
106 ApiGroups: userPermissions.APIGroups,
107 Resources: userPermissions.Resources,
108 Verbs: userPermissions.Verbs,
113 roleData, err := yaml.Marshal(&role)
118 return string(roleData), nil
121 func createRoleBinding(logicalcloud LogicalCloud) (string, error) {
123 roleBinding := Resource{
124 ApiVersion: "rbac.authorization.k8s.io/v1beta1",
127 Name: strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-roleBinding"}, ""),
128 Namespace: logicalcloud.Specification.NameSpace,
130 Subjects: []RoleSubjects{RoleSubjects{
132 Name: logicalcloud.Specification.User.UserName,
139 Name: strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-role"}, ""),
144 rBData, err := yaml.Marshal(&roleBinding)
149 return string(rBData), nil
153 func createQuota(quota []Quota, namespace string) (string, error) {
158 Kind: "ResourceQuota",
160 Name: lcQuota.MetaData.QuotaName,
161 Namespace: namespace,
163 Specification: Specs{
164 Hard: lcQuota.Specification,
168 qData, err := yaml.Marshal(&q)
173 return string(qData), nil
177 func createUserCSR(logicalcloud LogicalCloud) (string, error) {
179 userName := logicalcloud.Specification.User.UserName
181 key, err := rsa.GenerateKey(rand.Reader, KEYSIZE)
186 csrTemplate := x509.CertificateRequest{Subject: pkix.Name{CommonName: userName}}
188 csrCert, err := x509.CreateCertificateRequest(rand.Reader, &csrTemplate, key)
194 csr := pem.EncodeToMemory(&pem.Block{
195 Type: "CERTIFICATE REQUEST",
200 ApiVersion: "certificates.k8s.io/v1beta1",
201 Kind: "CertificateSigningRequest",
203 Name: strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-user-csr"}, ""),
204 Namespace: logicalcloud.Specification.NameSpace,
206 Specification: Specs{
207 Request: base64.StdEncoding.EncodeToString(csr),
208 Usages: []string{"digital signature", "key encipherment"},
212 csrData, err := yaml.Marshal(&csrObj)
217 return string(csrData), nil
223 // Store user key for user creation
224 // Code to run kubectl commands for user
225 // kubectl certificate approve lc1-user-cert
226 // kubectl get csr lc1-user-cert -o jsonpath='{.status.certificate}' | base64 --decode > user.crt
227 // kubectl config set-credentials user --client-certificate=<user.crt> --client-key=<user.key>
228 // kubectl config set-context user-context --cluster=cluster-name --namespace=lc1 --user=user
230 func CreateEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster,
231 quotaList []Quota) error {
233 APP := "logical-cloud"
234 logicalCloudName := logicalcloud.MetaData.LogicalCloudName
237 namespaceName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+namespace"}, "")
238 roleName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+role"}, "")
239 roleBindingName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+roleBinding"}, "")
240 quotaName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+quota"}, "")
241 csrName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+CertificateSigningRequest"}, "")
243 // Get resources to be added
244 namespace, err := createNamespace(logicalcloud)
246 return pkgerrors.Wrap(err, "Error Creating Namespace YAML for logical cloud")
249 role, err := createRole(logicalcloud)
251 return pkgerrors.Wrap(err, "Error Creating Role YAML for logical cloud")
254 roleBinding, err := createRoleBinding(logicalcloud)
256 return pkgerrors.Wrap(err, "Error Creating RoleBinding YAML for logical cloud")
259 quota, err := createQuota(quotaList, logicalcloud.Specification.NameSpace)
261 return pkgerrors.Wrap(err, "Error Creating Quota YAML for logical cloud")
264 csr, err := createUserCSR(logicalcloud)
266 return pkgerrors.Wrap(err, "Error Creating User CSR for logical cloud")
269 context := appcontext.AppContext{}
270 ctxVal, err := context.InitAppContext()
272 return pkgerrors.Wrap(err, "Error creating AppContext")
275 fmt.Printf("%v\n", ctxVal)
277 handle, err := context.CreateCompositeApp()
279 return pkgerrors.Wrap(err, "Error creating AppContext CompositeApp")
282 appHandle, err := context.AddApp(handle, APP)
284 cleanuperr := context.DeleteCompositeApp()
285 if cleanuperr != nil {
286 log.Warn("Error cleaning AppContext CompositeApp create failure", log.Fields{
287 "logical-cloud": logicalCloudName,
290 return pkgerrors.Wrap(err, "Error adding App to AppContext")
293 // Iterate through cluster list and add all the clusters
294 for _, cluster := range clusterList {
295 clusterName := strings.Join([]string{cluster.Specification.ClusterProvider, "+", cluster.Specification.ClusterName}, "")
296 clusterHandle, err := context.AddCluster(appHandle, clusterName)
299 cleanuperr := context.DeleteCompositeApp()
300 if cleanuperr != nil {
301 log.Warn("Error cleaning AppContext after add cluster failure", log.Fields{
302 "cluster-provider": cluster.Specification.ClusterProvider,
303 "cluster": cluster.Specification.ClusterName,
304 "logical-cloud": logicalCloudName,
307 return pkgerrors.Wrap(err, "Error adding Cluster to AppContext")
310 // Add namespace resource to each cluster
311 _, err = context.AddResource(clusterHandle, namespaceName, namespace)
313 cleanuperr := context.DeleteCompositeApp()
314 if cleanuperr != nil {
315 log.Warn("Error cleaning AppContext after add namespace resource failure", log.Fields{
316 "cluster-provider": cluster.Specification.ClusterProvider,
317 "cluster": cluster.Specification.ClusterName,
318 "logical-cloud": logicalCloudName,
321 return pkgerrors.Wrap(err, "Error adding Namespace Resource to AppContext")
324 // Add csr resource to each cluster
325 _, err = context.AddResource(clusterHandle, csrName, csr)
327 cleanuperr := context.DeleteCompositeApp()
328 if cleanuperr != nil {
329 log.Warn("Error cleaning AppContext after add CSR resource failure", log.Fields{
330 "cluster-provider": cluster.Specification.ClusterProvider,
331 "cluster": cluster.Specification.ClusterName,
332 "logical-cloud": logicalCloudName,
335 return pkgerrors.Wrap(err, "Error adding CSR Resource to AppContext")
338 // Add Role resource to each cluster
339 _, err = context.AddResource(clusterHandle, roleName, role)
341 cleanuperr := context.DeleteCompositeApp()
342 if cleanuperr != nil {
343 log.Warn("Error cleaning AppContext after add role resource failure", log.Fields{
344 "cluster-provider": cluster.Specification.ClusterProvider,
345 "cluster": cluster.Specification.ClusterName,
346 "logical-cloud": logicalCloudName,
349 return pkgerrors.Wrap(err, "Error adding role Resource to AppContext")
352 // Add RoleBinding resource to each cluster
353 _, err = context.AddResource(clusterHandle, roleBindingName, roleBinding)
355 cleanuperr := context.DeleteCompositeApp()
356 if cleanuperr != nil {
357 log.Warn("Error cleaning AppContext after add roleBinding resource failure", log.Fields{
358 "cluster-provider": cluster.Specification.ClusterProvider,
359 "cluster": cluster.Specification.ClusterName,
360 "logical-cloud": logicalCloudName,
363 return pkgerrors.Wrap(err, "Error adding roleBinding Resource to AppContext")
366 // Add quota resource to each cluster
367 _, err = context.AddResource(clusterHandle, quotaName, quota)
369 cleanuperr := context.DeleteCompositeApp()
370 if cleanuperr != nil {
371 log.Warn("Error cleaning AppContext after add quota resource failure", log.Fields{
372 "cluster-provider": cluster.Specification.ClusterProvider,
373 "cluster": cluster.Specification.ClusterName,
374 "logical-cloud": logicalCloudName,
377 return pkgerrors.Wrap(err, "Error adding quota Resource to AppContext")
380 // Add Resource Order and Resource Dependency
381 resOrder, err := json.Marshal(map[string][]string{"resorder": []string{namespaceName, quotaName, csrName, roleName, roleBindingName}})
383 return pkgerrors.Wrap(err, "Error creating resource order JSON")
386 resDependency, err := json.Marshal(map[string]map[string]string{"resdependency": map[string]string{namespaceName: "go",
387 quotaName: strings.Join([]string{"wait on ", namespaceName}, ""), csrName: strings.Join([]string{"wait on ", quotaName}, ""),
388 roleName: strings.Join([]string{"wait on ", csrName}, ""), roleBindingName: strings.Join([]string{"wait on ", roleName}, "")}})
391 return pkgerrors.Wrap(err, "Error creating resource dependency JSON")
394 _, err = context.AddInstruction(clusterHandle, "resource", "order", string(resOrder))
396 cleanuperr := context.DeleteCompositeApp()
397 if cleanuperr != nil {
398 log.Warn("Error cleaning AppContext after add instruction failure", log.Fields{
399 "cluster-provider": cluster.Specification.ClusterProvider,
400 "cluster": cluster.Specification.ClusterName,
401 "logical-cloud": logicalCloudName,
404 return pkgerrors.Wrap(err, "Error adding instruction order to AppContext")
407 _, err = context.AddInstruction(clusterHandle, "resource", "dependency", string(resDependency))
409 cleanuperr := context.DeleteCompositeApp()
410 if cleanuperr != nil {
411 log.Warn("Error cleaning AppContext after add instruction failure", log.Fields{
412 "cluster-provider": cluster.Specification.ClusterProvider,
413 "cluster": cluster.Specification.ClusterName,
414 "logical-cloud": logicalCloudName,
417 return pkgerrors.Wrap(err, "Error adding instruction dependency to AppContext")