From 8c0cc1278cc4d84863b076b2014b9bc9d8805218 Mon Sep 17 00:00:00 2001 From: "Igor D.C" Date: Fri, 25 Sep 2020 22:31:11 +0000 Subject: Implement Terminate operation in DCM Also makes minor changes to non-terminate code as a side-effect of supporting the new Terminate operation (such as including tagContext in the LogicalCloudClient implementation of LogicalCloudManager interface). These changes are/will also be leveraged by other operations. Issue-ID: MULTICLOUD-1143 Change-Id: Idbd2ec9f6cf0e5584a0f51cf4c16144db56d9fa0 Signed-off-by: Igor D.C --- src/dcm/api/api.go | 4 ++ src/dcm/api/logicalCloudHandler.go | 48 ++++++++++++++++++ src/dcm/pkg/module/apply.go | 90 +++++++++++++++++++++++++++++++++ src/dcm/pkg/module/logicalcloud.go | 36 +++++++++++-- src/dcm/pkg/module/logicalcloud_test.go | 8 +-- 5 files changed, 179 insertions(+), 7 deletions(-) diff --git a/src/dcm/api/api.go b/src/dcm/api/api.go index de1d5c97..0f68a517 100644 --- a/src/dcm/api/api.go +++ b/src/dcm/api/api.go @@ -44,6 +44,7 @@ func NewRouter( quotaClient = module.NewQuotaClient() } + // Set up Logical Cloud API logicalCloudHandler := logicalCloudHandler{client: logicalCloudClient, clusterClient: clusterClient, quotaClient: quotaClient, @@ -67,6 +68,9 @@ func NewRouter( lcRouter.HandleFunc( "/logical-clouds/{logical-cloud-name}/apply", logicalCloudHandler.applyHandler).Methods("POST") + lcRouter.HandleFunc( + "/logical-clouds/{logical-cloud-name}/terminate", + logicalCloudHandler.terminateHandler).Methods("POST") // To Do // get kubeconfig /*lcRouter.HandleFunc( diff --git a/src/dcm/api/logicalCloudHandler.go b/src/dcm/api/logicalCloudHandler.go index 36ec4e05..2e1811b7 100644 --- a/src/dcm/api/logicalCloudHandler.go +++ b/src/dcm/api/logicalCloudHandler.go @@ -25,6 +25,7 @@ import ( "github.com/gorilla/mux" "github.com/onap/multicloud-k8s/src/dcm/pkg/module" + pkgerrors "github.com/pkg/errors" ) // logicalCloudHandler is used to store backend implementations objects @@ -212,3 +213,50 @@ func (h logicalCloudHandler) applyHandler(w http.ResponseWriter, r *http.Request return } + +func (h logicalCloudHandler) terminateHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + project := vars["project-name"] + name := vars["logical-cloud-name"] + + // Get logical cloud + lc, err := h.client.Get(project, name) + if err != nil { + if err.Error() == "Logical Cloud does not exist" { + http.Error(w, err.Error(), http.StatusNotFound) + return + } + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + _, ctxVal, err := h.client.GetLogicalCloudContext(name) + if ctxVal == "" { + err = pkgerrors.New("Logical Cloud hasn't been applied yet") + http.Error(w, err.Error(), http.StatusConflict) + return + } + + // Get Clusters + clusters, err := h.clusterClient.GetAllClusters(project, name) + + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + //Get Quotas + quotas, err := h.quotaClient.GetAllQuotas(project, name) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + err = module.DestroyEtcdContext(lc, clusters, quotas) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + return +} diff --git a/src/dcm/pkg/module/apply.go b/src/dcm/pkg/module/apply.go index dbcbf8ac..84eb7ef7 100644 --- a/src/dcm/pkg/module/apply.go +++ b/src/dcm/pkg/module/apply.go @@ -28,11 +28,16 @@ import ( "strings" "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext" + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/grpc/installappclient" log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils" + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module/controller" pkgerrors "github.com/pkg/errors" "gopkg.in/yaml.v2" ) +// rsyncName denotes the name of the rsync controller +const rsyncName = "rsync" + type Resource struct { ApiVersion string `yaml:"apiVersion"` Kind string `yaml:"kind"` @@ -218,6 +223,45 @@ func createUserCSR(logicalcloud LogicalCloud) (string, error) { } +/* +queryDBAndSetRsyncInfo queries the MCO db to find the record the sync controller +and then sets the RsyncInfo global variable. +*/ +func queryDBAndSetRsyncInfo() (installappclient.RsyncInfo, error) { + client := controller.NewControllerClient() + vals, _ := client.GetControllers() + for _, v := range vals { + if v.Metadata.Name == rsyncName { + log.Info("Initializing RPC connection to resource synchronizer", log.Fields{ + "Controller": v.Metadata.Name, + }) + rsyncInfo := installappclient.NewRsyncInfo(v.Metadata.Name, v.Spec.Host, v.Spec.Port) + return rsyncInfo, nil + } + } + return installappclient.RsyncInfo{}, pkgerrors.Errorf("queryRsyncInfoInMCODB Failed - Could not get find rsync by name : %v", rsyncName) +} + +/* +callRsyncUninstall method shall take in the app context id and invoke the rsync service via grpc +*/ +func callRsyncUninstall(contextid interface{}) error { + rsyncInfo, err := queryDBAndSetRsyncInfo() + log.Info("Calling the Rsync ", log.Fields{ + "RsyncName": rsyncInfo.RsyncName, + }) + if err != nil { + return err + } + + appContextID := fmt.Sprintf("%v", contextid) + err = installappclient.InvokeUninstallApp(appContextID) + if err != nil { + return err + } + return nil +} + // TODO: // Install istio // Store user key for user creation @@ -422,3 +466,49 @@ func CreateEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster, return nil } + +// TODO: rename these methods +// DestroyEtcdContext remove from rsync then delete appcontext and all resources +func DestroyEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster, + quotaList []Quota) error { + + logicalCloudName := logicalcloud.MetaData.LogicalCloudName + // project := "test-project" // FIXME(igordc): temporary, need to do some rework in the LC structs + + _, ctxVal, err := NewLogicalCloudClient().GetLogicalCloudContext(logicalCloudName) + if err != nil { + return pkgerrors.Wrapf(err, "Error finding AppContext for Logical Cloud: %v", logicalCloudName) + } + + // call resource synchronizer to delete the CRs from every cluster of the logical cloud + err = callRsyncUninstall(ctxVal) + if err != nil { + return err + } + + // TODO: status handling for logical cloud after terminate: + // rsync updates the status of the appcontext to Terminated + // dcm should launch thread to observe status of appcontext before concluding logical cloud is terminated + // dcm should somewhat mimic the status tracking of rsync + // logical cloud might be in a non-applied non-terminated state for a long period of time......... + + // // remove the app context + // err = context.DeleteCompositeApp() + // if err != nil { + // return pkgerrors.Wrap(err, "Error deleting AppContext CompositeApp") + // } + + // remove the app context field from the cluster db record + // lckey := LogicalCloudKey{ + // LogicalCloudName: logicalcloud.MetaData.LogicalCloudName, + // Project: project, + // } + // err = db.DBconn.RemoveTag("orchestrator", lckey, "lccontext") + // if err != nil { + // log.Warn("Error removing AppContext from Logical Cloud", log.Fields{ + // "logical-cloud": logicalCloudName, + // }) + // } + + return nil +} diff --git a/src/dcm/pkg/module/logicalcloud.go b/src/dcm/pkg/module/logicalcloud.go index 7d3c806b..9b8ff703 100644 --- a/src/dcm/pkg/module/logicalcloud.go +++ b/src/dcm/pkg/module/logicalcloud.go @@ -17,6 +17,7 @@ package module import ( + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext" "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module" @@ -72,6 +73,7 @@ type LogicalCloudManager interface { GetAll(project string) ([]LogicalCloud, error) Delete(project, name string) error Update(project, name string, c LogicalCloud) (LogicalCloud, error) + GetLogicalCloudContext(name string) (appcontext.AppContext, string, error) } // Interface facilitates unit testing by mocking functions @@ -87,9 +89,10 @@ type Utility interface { // LogicalCloudClient implements the LogicalCloudManager // It will also be used to maintain some localized state type LogicalCloudClient struct { - storeName string - tagMeta string - util Utility + storeName string + tagMeta string + tagContext string + util Utility } // Added for unit testing; implements Utility interface @@ -227,6 +230,33 @@ func (v *LogicalCloudClient) Update(project, logicalCloudName string, c LogicalC return c, nil } +// GetClusterContext returns the AppContext for corresponding provider and name +func (v *LogicalCloudClient) GetLogicalCloudContext(name string) (appcontext.AppContext, string, error) { + //Construct key and tag to select the entry + key := LogicalCloudKey{ + LogicalCloudName: name, + Project: "test-project", // FIXME(igordc): temporary, need to do some rework in the LC structs + } + + value, err := db.DBconn.Find(v.storeName, key, v.tagContext) + if err != nil { + return appcontext.AppContext{}, "", pkgerrors.Wrap(err, "Get Logical Cloud Context") + } + + //value is a byte array + if value != nil { + ctxVal := string(value[0]) + var lcc appcontext.AppContext + _, err = lcc.LoadAppContext(ctxVal) + if err != nil { + return appcontext.AppContext{}, "", pkgerrors.Wrap(err, "Reinitializing Logical Cloud AppContext") + } + return lcc, ctxVal, nil + } + + return appcontext.AppContext{}, "", pkgerrors.New("Error getting Logical Cloud AppContext") +} + func (d DBService) DBInsert(storeName string, key db.Key, query interface{}, meta string, c interface{}) error { err := db.DBconn.Insert(storeName, key, nil, meta, c) diff --git a/src/dcm/pkg/module/logicalcloud_test.go b/src/dcm/pkg/module/logicalcloud_test.go index fb205753..0a0e2f5d 100644 --- a/src/dcm/pkg/module/logicalcloud_test.go +++ b/src/dcm/pkg/module/logicalcloud_test.go @@ -78,7 +78,7 @@ func TestCreateLogicalCloud(t *testing.T) { myMocks.On("DBInsert", "test_dcm", key, nil, "test_meta", lc).Return(nil) myMocks.On("DBFind", "test_dcm", key, "test_meta").Return(data1, err1) - lcClient := LogicalCloudClient{"test_dcm", "test_meta", myMocks} + lcClient := LogicalCloudClient{"test_dcm", "test_meta", "test_context", myMocks} _, err := lcClient.Create("test_project", lc) if err != nil { t.Errorf("Some error occured!") @@ -101,7 +101,7 @@ func TestGetLogicalCloud(t *testing.T) { myMocks.On("DBFind", "test_dcm", key, "test_meta").Return(data1, nil) myMocks.On("DBUnmarshal", data2).Return(nil) - lcClient := LogicalCloudClient{"test_dcm", "test_meta", myMocks} + lcClient := LogicalCloudClient{"test_dcm", "test_meta", "test_context", myMocks} _, err := lcClient.Get("test_project", "test_asdf") if err != nil { t.Errorf("Some error occured!") @@ -119,7 +119,7 @@ func TestDeleteLogicalCloud(t *testing.T) { myMocks.On("DBRemove", "test_dcm", key).Return(nil) - lcClient := LogicalCloudClient{"test_dcm", "test_meta", myMocks} + lcClient := LogicalCloudClient{"test_dcm", "test_meta", "test_context", myMocks} err := lcClient.Delete("test_project", "test_asdf") if err != nil { t.Errorf("Some error occured!") @@ -148,7 +148,7 @@ func TestUpdateLogicalCloud(t *testing.T) { myMocks.On("DBInsert", "test_dcm", key, nil, "test_meta", lc).Return(nil) myMocks.On("DBFind", "test_dcm", key, "test_meta").Return(data1, nil) myMocks.On("DBUnmarshal", data2).Return(nil) - lcClient := LogicalCloudClient{"test_dcm", "test_meta", myMocks} + lcClient := LogicalCloudClient{"test_dcm", "test_meta", "test_context", myMocks} _, err := lcClient.Update("test_project", "test_asdf", lc) if err != nil { t.Errorf("Some error occured!") -- cgit 1.2.3-korg