Adding CSR Approval functionality 44/113444/4
authorRitu Sood <ritu.sood@intel.com>
Thu, 1 Oct 2020 22:05:42 +0000 (15:05 -0700)
committerIgor D.C <igor.duarte.cardoso@intel.com>
Fri, 2 Oct 2020 22:31:31 +0000 (22:31 +0000)
Update rsync to be able to approve CSR

Issue-ID: MULTICLOUD-1143
Signed-off-by: Ritu Sood <ritu.sood@intel.com>
Change-Id: I0b2bec3475a3453a2d8fc9c2e87cfc4531b0e2f3

src/rsync/pkg/client/approve.go [new file with mode: 0644]
src/rsync/pkg/context/context.go
src/tools/emcoctl/cmd/utils.go
src/tools/emcoctl/examples/dcm.yaml [new file with mode: 0644]
src/tools/emcoctl/examples/emco-cfg.yaml

diff --git a/src/rsync/pkg/client/approve.go b/src/rsync/pkg/client/approve.go
new file mode 100644 (file)
index 0000000..ee15771
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+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 client
+
+import (
+       "encoding/json"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
+       "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext/subresources"
+       pkgerrors "github.com/pkg/errors"
+       "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils"
+)
+
+func (c *Client) Approve(name string, sa []byte) error {
+
+       var a subresources.ApprovalSubresource
+       err := json.Unmarshal(sa, &a)
+       if err != nil {
+               return pkgerrors.Wrap(err, "An error occurred while parsing the approval Subresource.")
+       }
+       csr, err := c.Clientset.CertificatesV1beta1().CertificateSigningRequests().Get(name, metav1.GetOptions{})
+       if err != nil {
+               return err
+       }
+       var timePtr metav1.Time
+       str := []string{a.LastUpdateTime}
+       if err = metav1.Convert_Slice_string_To_v1_Time(&str, &timePtr, nil); err != nil {
+           return pkgerrors.Wrap(err, "An error occurred while converting time from string.")
+       }
+       // Update CSR with Conditions
+       csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1beta1.CertificateSigningRequestCondition{
+               Type:           certificatesv1beta1.RequestConditionType(a.Type),
+               Reason:         a.Reason,
+               Message:        a.Message,
+               LastUpdateTime: timePtr,
+       })
+       // CSR Approval
+       _, err = c.Clientset.CertificatesV1beta1().CertificateSigningRequests().UpdateApproval(csr)
+       if err != nil {
+               logutils.Error("Failed to UpdateApproval", logutils.Fields{
+                       "error":    err,
+                       "resource": name,
+               })
+               return err
+       }
+       return nil
+}
index a277137..841dfcd 100644 (file)
@@ -68,6 +68,28 @@ func getRes(ac appcontext.AppContext, name string, app string, cluster string) (
        return byteRes, sh, nil
 }
 
+func getSubResApprove(ac appcontext.AppContext, name string, app string, cluster string) ([]byte, interface{}, error) {
+       var byteRes []byte
+       rh, err := ac.GetResourceHandle(app, cluster, name)
+       if err != nil {
+               return nil, nil, err
+       }
+       sh, err := ac.GetLevelHandle(rh, "subresource/approval")
+       if err != nil {
+               return nil, nil, err
+       }
+       resval, err := ac.GetValue(sh)
+       if err != nil {
+               return nil, sh, err
+       }
+       if resval != "" {
+               byteRes = []byte(fmt.Sprintf("%v", resval.(interface{})))
+       } else {
+               return nil, sh, pkgerrors.Errorf("SubResource value is nil %s", name)
+       }
+       return byteRes, sh, nil
+}
+
 func terminateResource(ac appcontext.AppContext, c *kubeclient.Client, name string, app string, cluster string, label string) error {
        res, sh, err := getRes(ac, name, app, cluster)
        if err != nil {
@@ -144,6 +166,22 @@ func instantiateResource(ac appcontext.AppContext, c *kubeclient.Client, name st
                "cluster":  cluster,
                "resource": name,
        })
+
+       // Currently only subresource supported is approval
+       subres, _, err := getSubResApprove(ac, name, app, cluster)
+       if err == nil {
+               result := strings.Split(name, "+")
+               if result[0] == "" {
+                       return pkgerrors.Errorf("Resource name is nil %s:", name)
+               }
+               logutils.Info("Approval Subresource::", logutils.Fields{
+                       "cluster":  cluster,
+                       "resource": result[0],
+                       "approval": string(subres),
+               })
+               err = c.Approve(result[0], subres)
+               return err
+       }
        return nil
 }
 
index 62b3375..d266a00 100644 (file)
@@ -25,8 +25,8 @@ import (
 
        "github.com/go-resty/resty/v2"
        "github.com/mitchellh/mapstructure"
-       "gopkg.in/yaml.v3"
        pkgerrors "github.com/pkg/errors"
+       "gopkg.in/yaml.v3"
 )
 
 var inputFiles []string
@@ -53,9 +53,9 @@ type emcoRes struct {
 }
 
 type emcoBody struct {
-       Meta Metadata               `json:"metadata,omitempty"`
-       Label string                `json:"label-name,omitempty"`
-       Spec map[string]interface{} `json:"spec,omitempty"`
+       Meta  Metadata               `json:"metadata,omitempty"`
+       Label string                 `json:"label-name,omitempty"`
+       Spec  map[string]interface{} `json:"spec,omitempty"`
 }
 
 type emcoCompositeAppSpec struct {
@@ -67,6 +67,7 @@ type Resources struct {
        body   []byte
        file   string
 }
+
 // RestyClient to use with CLI
 type RestyClient struct {
        client *resty.Client
@@ -141,7 +142,7 @@ func (r RestyClient) RestClientPost(anchor string, body []byte) error {
                return err
        }
        fmt.Println("URL:", anchor, "Response Code:", resp.StatusCode(), "Response:", resp)
-       if (resp.StatusCode() >= 201 && resp.StatusCode() <= 299) {
+       if resp.StatusCode() >= 201 && resp.StatusCode() <= 299 {
                return nil
        }
        return pkgerrors.Errorf("Server Post Error")
@@ -174,7 +175,7 @@ func (r RestyClient) RestClientMultipartPost(anchor string, body []byte, file st
                return err
        }
        fmt.Println("URL:", anchor, "Response Code:", resp.StatusCode(), "Response:", resp)
-       if (resp.StatusCode() >= 201 && resp.StatusCode() <= 299) {
+       if resp.StatusCode() >= 201 && resp.StatusCode() <= 299 {
                return nil
        }
        return pkgerrors.Errorf("Server Multipart Post Error")
@@ -248,6 +249,7 @@ func (r RestyClient) RestClientGet(anchor string, body []byte) error {
 
        return r.RestClientGetAnchor(anchor)
 }
+
 // RestClientDeleteAnchor returns all resource in the input file
 func (r RestyClient) RestClientDeleteAnchor(anchor string) error {
        url, err := GetURL(anchor)
@@ -262,6 +264,7 @@ func (r RestyClient) RestClientDeleteAnchor(anchor string) error {
        fmt.Println("URL:", anchor, "Response Code:", resp.StatusCode(), "Response:", resp)
        return nil
 }
+
 // RestClientDelete calls rest delete command
 func (r RestyClient) RestClientDelete(anchor string, body []byte) error {
 
@@ -306,6 +309,7 @@ func (r RestyClient) RestClientDelete(anchor string, body []byte) error {
        }
        return r.RestClientDeleteAnchor(anchor)
 }
+
 // GetURL reads the configuration file to get URL
 func GetURL(anchor string) (string, error) {
        var baseUrl string
@@ -324,13 +328,19 @@ func GetURL(anchor string) (string, error) {
        case "controllers":
                baseUrl = GetOrchestratorURL()
        case "projects":
+               if len(s) >= 3 && s[2] == "logical-clouds" {
+                       baseUrl = GetDcmURL()
+                       break
+               }
                if len(s) >= 6 && s[5] == "network-controller-intent" {
                        baseUrl = GetOvnactionURL()
-               } else {
-                       baseUrl = GetOrchestratorURL()
+                       break
                }
+               // All other paths go to Orchestrator
+               baseUrl = GetOrchestratorURL()
        default:
                return "", fmt.Errorf("Invalid Anchor")
        }
+       fmt.Printf(baseUrl)
        return (baseUrl + "/" + anchor), nil
 }
diff --git a/src/tools/emcoctl/examples/dcm.yaml b/src/tools/emcoctl/examples/dcm.yaml
new file mode 100644 (file)
index 0000000..a567491
--- /dev/null
@@ -0,0 +1,105 @@
+#creating controller entries
+version: emco/v2
+resourceContext:
+  anchor: controllers
+metadata :
+   name: rsync
+spec:
+  host: localhost
+  port: 9018
+
+---
+#creating cluster provider
+version: emco/v2
+resourceContext:
+  anchor: cluster-providers
+metadata :
+   name: cp-1
+
+---
+#creating cluster
+version: emco/v2
+resourceContext:
+  anchor: cluster-providers/cp-1/clusters
+metadata :
+   name: c1
+file:
+  # Replace with actual path
+  kubeconfig
+
+---
+#create project
+version: emco/v2
+resourceContext:
+  anchor: projects
+metadata :
+   name: proj1
+
+---
+#create logical cloud
+version: emco/v2
+resourceContext:
+  anchor: projects/proj1/logical-clouds
+metadata:
+  name: lc1
+spec:
+  namespace: ns1
+  user:
+    user-name: user-1
+    type: certificate
+    user-permissions:
+    - permission-name: permission-1
+      apiGroups:
+      - ""
+      resources:
+      - secrets
+      - pods
+      verbs:
+      - get
+      - watch
+      - list
+      - create
+
+---
+#create cluster reference
+version: emco/v2
+resourceContext:
+  anchor: projects/proj1/logical-clouds/lc1/cluster-references
+metadata:
+  name: lc-cl-1
+spec:
+  cluster-provider: cp-1
+  cluster-name: c1
+  loadbalancer-ip: "0.0.0.0"
+
+---
+#create cluster quotas
+version: emco/v2
+resourceContext:
+  anchor: projects/proj1/logical-clouds/lc1/cluster-quotas
+metadata:
+    name: quota-1
+spec:
+    limits.cpu: '400'
+    limits.memory: 1000Gi
+    requests.cpu: '300'
+    requests.memory: 900Gi
+    requests.storage: 500Gi
+    requests.ephemeral-storage: '500'
+    limits.ephemeral-storage: '500'
+    persistentvolumeclaims: '500'
+    pods: '500'
+    configmaps: '1000'
+    replicationcontrollers: '500'
+    resourcequotas: '500'
+    services: '500'
+    services.loadbalancers: '500'
+    services.nodeports: '500'
+    secrets: '500'
+    count/replicationcontrollers: '500'
+    count/deployments.apps: '500'
+    count/replicasets.apps: '500'
+    count/statefulsets.apps: '500'
+    count/jobs.batch: '500'
+    count/cronjobs.batch: '500'
+    count/deployments.extensions: '500'
index a7e284a..039a6f3 100644 (file)
@@ -10,3 +10,6 @@
   ovnaction:
     host: localhost
     port: 9018
+  dcm:
+    host: localhost
+    port: 9017