Implement Terminate operation in DCM 03/113203/2
authorIgor D.C <igor.duarte.cardoso@intel.com>
Fri, 25 Sep 2020 22:31:11 +0000 (22:31 +0000)
committerIgor D.C <igor.duarte.cardoso@intel.com>
Fri, 25 Sep 2020 23:24:29 +0000 (23:24 +0000)
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 <igor.duarte.cardoso@intel.com>
src/dcm/api/api.go
src/dcm/api/logicalCloudHandler.go
src/dcm/pkg/module/apply.go
src/dcm/pkg/module/logicalcloud.go
src/dcm/pkg/module/logicalcloud_test.go

index de1d5c9..0f68a51 100644 (file)
@@ -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(
index 36ec4e0..2e1811b 100644 (file)
@@ -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
+}
index dbcbf8a..84eb7ef 100644 (file)
@@ -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
+}
index 7d3c806..9b8ff70 100644 (file)
@@ -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)
index fb20575..0a0e2f5 100644 (file)
@@ -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!")