2 * Copyright 2020 Intel Corporation, Inc
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
29 "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext"
\r
30 log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils"
\r
32 pkgerrors "github.com/pkg/errors"
\r
36 type Resource struct {
\r
37 ApiVersion string `yaml:"apiVersion"`
\r
38 Kind string `yaml:"kind"`
\r
39 MetaData MetaDatas `yaml:"metadata"`
\r
40 Specification Specs `yaml:"spec,omitempty"`
\r
41 Rules []RoleRules `yaml:"rules,omitempty"`
\r
42 Subjects []RoleSubjects `yaml:"subjects,omitempty"`
\r
43 RoleRefs RoleRef `yaml:"roleRef,omitempty"`
\r
46 type MetaDatas struct {
\r
47 Name string `yaml:"name"`
\r
48 Namespace string `yaml:"namespace,omitempty"`
\r
52 Request string `yaml:"request,omitempty"`
\r
53 Usages []string `yaml:"usages,omitempty"`
\r
54 //Hard logicalcloud.QSpec `yaml:"hard,omitempty"`
\r
55 Hard QSpec `yaml:"hard,omitempty"`
\r
58 type RoleRules struct {
\r
59 ApiGroups []string `yaml:"apiGroups"`
\r
60 Resources []string `yaml:"resources"`
\r
61 Verbs []string `yaml:"verbs"`
\r
64 type RoleSubjects struct {
\r
65 Kind string `yaml:"kind"`
\r
66 Name string `yaml:"name"`
\r
67 ApiGroup string `yaml:"apiGroup"`
\r
70 type RoleRef struct {
\r
71 Kind string `yaml:"kind"`
\r
72 Name string `yaml:"name"`
\r
73 ApiGroup string `yaml:"apiGroup"`
\r
77 func createNamespace(logicalcloud LogicalCloud) (string, error) {
\r
79 namespace := Resource{
\r
82 MetaData: MetaDatas{
\r
83 Name: logicalcloud.Specification.NameSpace,
\r
87 nsData, err := yaml.Marshal(&namespace)
\r
93 return string(nsData), nil
\r
96 func createRole(logicalcloud LogicalCloud) (string, error) {
\r
98 userPermissions := logicalcloud.Specification.User.UserPermissions[0]
\r
101 ApiVersion: "rbac.authorization.k8s.io/v1beta1",
\r
103 MetaData: MetaDatas{
\r
104 Name: strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-role"}, ""),
\r
105 Namespace: logicalcloud.Specification.NameSpace,
\r
107 Rules: []RoleRules{ RoleRules{
\r
108 ApiGroups: userPermissions.APIGroups,
\r
109 Resources: userPermissions.Resources,
\r
110 Verbs: userPermissions.Verbs,
\r
116 roleData, err := yaml.Marshal(&role)
\r
121 return string(roleData), nil
\r
124 func createRoleBinding(logicalcloud LogicalCloud) (string, error) {
\r
126 roleBinding := Resource{
\r
127 ApiVersion: "rbac.authorization.k8s.io/v1beta1",
\r
128 Kind: "RoleBinding",
\r
129 MetaData: MetaDatas{
\r
130 Name: strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-roleBinding"}, ""),
\r
131 Namespace: logicalcloud.Specification.NameSpace,
\r
133 Subjects: []RoleSubjects{ RoleSubjects{
\r
135 Name: logicalcloud.Specification.User.UserName,
\r
142 Name: strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-role"}, ""),
\r
147 rBData, err := yaml.Marshal(&roleBinding)
\r
153 return string(rBData), nil
\r
157 func createQuota(quota []Quota, namespace string) (string, error) {
\r
158 lcQuota := quota[0]
\r
162 Kind: "ResourceQuota",
\r
163 MetaData: MetaDatas{
\r
164 Name: lcQuota.MetaData.QuotaName,
\r
165 Namespace: namespace,
\r
167 Specification: Specs{
\r
168 Hard: lcQuota.Specification,
\r
172 qData, err := yaml.Marshal(&q)
\r
179 return string(qData), nil
\r
183 func createUserCSR(logicalcloud LogicalCloud) (string, error) {
\r
185 userName := logicalcloud.Specification.User.UserName
\r
187 key, err := rsa.GenerateKey(rand.Reader, KEYSIZE)
\r
192 csrTemplate := x509.CertificateRequest{Subject: pkix.Name{CommonName: userName,},
\r
195 csrCert, err := x509.CreateCertificateRequest(rand.Reader, &csrTemplate, key)
\r
201 csr := pem.EncodeToMemory(&pem.Block{
\r
202 Type: "CERTIFICATE REQUEST",
\r
206 csrObj := Resource{
\r
207 ApiVersion: "certificates.k8s.io/v1beta1",
\r
208 Kind: "CertificateSigningRequest",
\r
209 MetaData: MetaDatas{
\r
210 Name: strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-user-csr"}, ""),
\r
211 Namespace: logicalcloud.Specification.NameSpace,
\r
213 Specification: Specs{
\r
214 Request: base64.StdEncoding.EncodeToString(csr),
\r
215 Usages: []string{"digital signature", "key encipherment"},
\r
219 csrData, err := yaml.Marshal(&csrObj)
\r
225 return string(csrData), nil
\r
232 // Store user key for user creation
\r
233 // Code to run kubectl commands for user
\r
234 // kubectl certificate approve lc1-user-cert
\r
235 // kubectl get csr lc1-user-cert -o jsonpath='{.status.certificate}' | base64 --decode > user.crt
\r
236 // kubectl config set-credentials user --client-certificate=<user.crt> --client-key=<user.key>
\r
237 // kubectl config set-context user-context --cluster=cluster-name --namespace=lc1 --user=user
\r
240 func CreateEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster,
\r
241 quotaList []Quota ) error {
\r
243 APP := "logical-cloud"
\r
244 logicalCloudName := logicalcloud.MetaData.LogicalCloudName
\r
248 namespaceName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+namespace"}, "")
\r
249 roleName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+role"}, "")
\r
250 roleBindingName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+roleBinding"}, "")
\r
251 quotaName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+quota"}, "")
\r
252 csrName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+CertificateSigningRequest"}, "")
\r
254 // Get resources to be added
\r
255 namespace, err := createNamespace(logicalcloud)
\r
257 return pkgerrors.Wrap(err, "Error Creating Namespace YAML for logical cloud")
\r
260 role, err := createRole(logicalcloud)
\r
262 return pkgerrors.Wrap(err, "Error Creating Role YAML for logical cloud")
\r
265 roleBinding, err := createRoleBinding(logicalcloud)
\r
267 return pkgerrors.Wrap(err, "Error Creating RoleBinding YAML for logical cloud")
\r
270 quota, err := createQuota(quotaList, logicalcloud.Specification.NameSpace)
\r
272 return pkgerrors.Wrap(err, "Error Creating Quota YAML for logical cloud")
\r
275 csr, err := createUserCSR(logicalcloud)
\r
277 return pkgerrors.Wrap(err, "Error Creating User CSR for logical cloud")
\r
281 context := appcontext.AppContext{}
\r
282 ctxVal, err := context.InitAppContext()
\r
284 return pkgerrors.Wrap(err, "Error creating AppContext")
\r
287 fmt.Printf("%v\n", ctxVal)
\r
289 handle, err := context.CreateCompositeApp()
\r
291 return pkgerrors.Wrap(err, "Error creating AppContext CompositeApp")
\r
295 appHandle, err := context.AddApp(handle, APP)
\r
297 cleanuperr := context.DeleteCompositeApp()
\r
298 if cleanuperr != nil {
\r
299 log.Warn("Error cleaning AppContext CompositeApp create failure", log.Fields{
\r
300 "logical-cloud": logicalCloudName,
\r
303 return pkgerrors.Wrap(err, "Error adding App to AppContext")
\r
307 // Iterate through cluster list and add all the clusters
\r
308 for _, cluster:= range clusterList {
\r
309 clusterName := strings.Join([]string{cluster.Specification.ClusterProvider, "+", cluster.Specification.ClusterName, }, "")
\r
310 clusterHandle, err := context.AddCluster(appHandle, clusterName)
\r
313 cleanuperr := context.DeleteCompositeApp()
\r
314 if cleanuperr != nil {
\r
315 log.Warn("Error cleaning AppContext after add cluster failure", log.Fields{
\r
316 "cluster-provider": cluster.Specification.ClusterProvider,
\r
317 "cluster": cluster.Specification.ClusterName,
\r
318 "logical-cloud": logicalCloudName,
\r
322 return pkgerrors.Wrap(err, "Error adding Cluster to AppContext")
\r
325 // Add namespace resource to each cluster
\r
326 _, err = context.AddResource(clusterHandle, namespaceName, namespace)
\r
328 cleanuperr := context.DeleteCompositeApp()
\r
329 if cleanuperr != nil {
\r
330 log.Warn("Error cleaning AppContext after add namespace resource failure", log.Fields{
\r
331 "cluster-provider": cluster.Specification.ClusterProvider,
\r
332 "cluster": cluster.Specification.ClusterName,
\r
333 "logical-cloud": logicalCloudName,
\r
337 return pkgerrors.Wrap(err, "Error adding Namespace Resource to AppContext")
\r
340 // Add csr resource to each cluster
\r
341 _, err = context.AddResource(clusterHandle, csrName, csr)
\r
343 cleanuperr := context.DeleteCompositeApp()
\r
344 if cleanuperr != nil {
\r
345 log.Warn("Error cleaning AppContext after add CSR resource failure", log.Fields{
\r
346 "cluster-provider": cluster.Specification.ClusterProvider,
\r
347 "cluster": cluster.Specification.ClusterName,
\r
348 "logical-cloud": logicalCloudName,
\r
352 return pkgerrors.Wrap(err, "Error adding CSR Resource to AppContext")
\r
357 // Add Role resource to each cluster
\r
358 _, err = context.AddResource(clusterHandle, roleName, role)
\r
360 cleanuperr := context.DeleteCompositeApp()
\r
361 if cleanuperr != nil {
\r
362 log.Warn("Error cleaning AppContext after add role resource failure", log.Fields{
\r
363 "cluster-provider": cluster.Specification.ClusterProvider,
\r
364 "cluster": cluster.Specification.ClusterName,
\r
365 "logical-cloud": logicalCloudName,
\r
369 return pkgerrors.Wrap(err, "Error adding role Resource to AppContext")
\r
372 // Add RoleBinding resource to each cluster
\r
373 _, err = context.AddResource(clusterHandle, roleBindingName, roleBinding)
\r
375 cleanuperr := context.DeleteCompositeApp()
\r
376 if cleanuperr != nil {
\r
377 log.Warn("Error cleaning AppContext after add roleBinding resource failure", log.Fields{
\r
378 "cluster-provider": cluster.Specification.ClusterProvider,
\r
379 "cluster": cluster.Specification.ClusterName,
\r
380 "logical-cloud": logicalCloudName,
\r
384 return pkgerrors.Wrap(err, "Error adding roleBinding Resource to AppContext")
\r
387 // Add quota resource to each cluster
\r
388 _, err = context.AddResource(clusterHandle, quotaName, quota)
\r
390 cleanuperr := context.DeleteCompositeApp()
\r
391 if cleanuperr != nil {
\r
392 log.Warn("Error cleaning AppContext after add quota resource failure", log.Fields{
\r
393 "cluster-provider": cluster.Specification.ClusterProvider,
\r
394 "cluster": cluster.Specification.ClusterName,
\r
395 "logical-cloud": logicalCloudName,
\r
399 return pkgerrors.Wrap(err, "Error adding quota Resource to AppContext")
\r
402 // Add Resource Order and Resource Dependency
\r
403 resOrder, err := json.Marshal(map[string][]string{"resorder" : []string{namespaceName, quotaName, csrName, roleName, roleBindingName}})
\r
405 return pkgerrors.Wrap(err, "Error creating resource order JSON")
\r
408 resDependency, err := json.Marshal(map[string]map[string]string{"resdependency" : map[string]string{namespaceName : "go",
\r
409 quotaName : strings.Join([]string{"wait on ", namespaceName}, ""), csrName: strings.Join([]string{"wait on ", quotaName}, ""),
\r
410 roleName : strings.Join([]string{"wait on ", csrName}, ""), roleBindingName: strings.Join([]string{"wait on ", roleName}, ""),}})
\r
413 return pkgerrors.Wrap(err, "Error creating resource dependency JSON")
\r
416 _, err = context.AddInstruction(clusterHandle, "resource", "order", string(resOrder))
\r
418 cleanuperr := context.DeleteCompositeApp()
\r
419 if cleanuperr != nil {
\r
420 log.Warn("Error cleaning AppContext after add instruction failure", log.Fields{
\r
421 "cluster-provider": cluster.Specification.ClusterProvider,
\r
422 "cluster": cluster.Specification.ClusterName,
\r
423 "logical-cloud": logicalCloudName,
\r
427 return pkgerrors.Wrap(err, "Error adding instruction order to AppContext")
\r
430 _, err = context.AddInstruction(clusterHandle, "resource", "dependency", string(resDependency))
\r
432 cleanuperr := context.DeleteCompositeApp()
\r
433 if cleanuperr != nil {
\r
434 log.Warn("Error cleaning AppContext after add instruction failure", log.Fields{
\r
435 "cluster-provider": cluster.Specification.ClusterProvider,
\r
436 "cluster": cluster.Specification.ClusterName,
\r
437 "logical-cloud": logicalCloudName,
\r
441 return pkgerrors.Wrap(err, "Error adding instruction dependency to AppContext")
\r