From 49f3d84b1dd20e7504018ee952d81885d5f21796 Mon Sep 17 00:00:00 2001 From: Ritu Sood Date: Thu, 1 Oct 2020 15:05:42 -0700 Subject: Adding CSR Approval functionality Update rsync to be able to approve CSR Issue-ID: MULTICLOUD-1143 Signed-off-by: Ritu Sood Change-Id: I0b2bec3475a3453a2d8fc9c2e87cfc4531b0e2f3 --- src/rsync/pkg/client/approve.go | 56 +++++++++++++++++ src/rsync/pkg/context/context.go | 38 +++++++++++ src/tools/emcoctl/cmd/utils.go | 26 +++++--- src/tools/emcoctl/examples/dcm.yaml | 105 +++++++++++++++++++++++++++++++ src/tools/emcoctl/examples/emco-cfg.yaml | 3 + 5 files changed, 220 insertions(+), 8 deletions(-) create mode 100644 src/rsync/pkg/client/approve.go create mode 100644 src/tools/emcoctl/examples/dcm.yaml diff --git a/src/rsync/pkg/client/approve.go b/src/rsync/pkg/client/approve.go new file mode 100644 index 00000000..ee157713 --- /dev/null +++ b/src/rsync/pkg/client/approve.go @@ -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 +} diff --git a/src/rsync/pkg/context/context.go b/src/rsync/pkg/context/context.go index a2771379..841dfcda 100644 --- a/src/rsync/pkg/context/context.go +++ b/src/rsync/pkg/context/context.go @@ -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 } diff --git a/src/tools/emcoctl/cmd/utils.go b/src/tools/emcoctl/cmd/utils.go index 62b33755..d266a00f 100644 --- a/src/tools/emcoctl/cmd/utils.go +++ b/src/tools/emcoctl/cmd/utils.go @@ -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 index 00000000..a567491b --- /dev/null +++ b/src/tools/emcoctl/examples/dcm.yaml @@ -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' diff --git a/src/tools/emcoctl/examples/emco-cfg.yaml b/src/tools/emcoctl/examples/emco-cfg.yaml index a7e284ab..039a6f34 100644 --- a/src/tools/emcoctl/examples/emco-cfg.yaml +++ b/src/tools/emcoctl/examples/emco-cfg.yaml @@ -10,3 +10,6 @@ ovnaction: host: localhost port: 9018 + dcm: + host: localhost + port: 9017 -- cgit 1.2.3-korg