diff options
Diffstat (limited to 'src')
57 files changed, 1643 insertions, 1867 deletions
diff --git a/src/dcm/api/api.go b/src/dcm/api/api.go index 0f68a517..10856ba2 100644 --- a/src/dcm/api/api.go +++ b/src/dcm/api/api.go @@ -21,7 +21,6 @@ import ( // NewRouter creates a router that registers the various urls that are // supported - func NewRouter( logicalCloudClient module.LogicalCloudManager, clusterClient module.ClusterManager, @@ -55,7 +54,7 @@ func NewRouter( logicalCloudHandler.createHandler).Methods("POST") lcRouter.HandleFunc( "/logical-clouds", - logicalCloudHandler.getHandler).Methods("GET") + logicalCloudHandler.getAllHandler).Methods("GET") lcRouter.HandleFunc( "/logical-clouds/{logical-cloud-name}", logicalCloudHandler.getHandler).Methods("GET") @@ -71,18 +70,8 @@ func NewRouter( lcRouter.HandleFunc( "/logical-clouds/{logical-cloud-name}/terminate", logicalCloudHandler.terminateHandler).Methods("POST") - // To Do - // get kubeconfig - /*lcRouter.HandleFunc( - "/logical-clouds/{name}/kubeconfig?cluster-reference={cluster}", - logicalCloudHandler.getConfigHandler).Methods("GET") - //get status - lcRouter.HandleFunc( - "/logical-clouds/{name}/cluster-references/", - logicalCloudHandler.associateHandler).Methods("GET")*/ // Set up Cluster API - clusterHandler := clusterHandler{client: clusterClient} clusterRouter := router.PathPrefix("/v2/projects/{project-name}").Subrouter() clusterRouter.HandleFunc( @@ -90,7 +79,7 @@ func NewRouter( clusterHandler.createHandler).Methods("POST") clusterRouter.HandleFunc( "/logical-clouds/{logical-cloud-name}/cluster-references", - clusterHandler.getHandler).Methods("GET") + clusterHandler.getAllHandler).Methods("GET") clusterRouter.HandleFunc( "/logical-clouds/{logical-cloud-name}/cluster-references/{cluster-reference}", clusterHandler.getHandler).Methods("GET") @@ -100,6 +89,10 @@ func NewRouter( clusterRouter.HandleFunc( "/logical-clouds/{logical-cloud-name}/cluster-references/{cluster-reference}", clusterHandler.deleteHandler).Methods("DELETE") + // Get kubeconfig for cluster of logical cloud + clusterRouter.HandleFunc( + "/logical-clouds/{logical-cloud-name}/cluster-references/{cluster-reference}/kubeconfig", + clusterHandler.getConfigHandler).Methods("GET") // Set up User Permission API if userPermissionClient == nil { @@ -111,6 +104,9 @@ func NewRouter( "/logical-clouds/{logical-cloud-name}/user-permissions", userPermissionHandler.createHandler).Methods("POST") upRouter.HandleFunc( + "/logical-clouds/{logical-cloud-name}/user-permissions", + userPermissionHandler.getAllHandler).Methods("GET") + upRouter.HandleFunc( "/logical-clouds/{logical-cloud-name}/user-permissions/{permission-name}", userPermissionHandler.getHandler).Methods("GET") upRouter.HandleFunc( @@ -121,13 +117,15 @@ func NewRouter( userPermissionHandler.deleteHandler).Methods("DELETE") // Set up Quota API - quotaHandler := quotaHandler{client: quotaClient} quotaRouter := router.PathPrefix("/v2/projects/{project-name}").Subrouter() quotaRouter.HandleFunc( "/logical-clouds/{logical-cloud-name}/cluster-quotas", quotaHandler.createHandler).Methods("POST") quotaRouter.HandleFunc( + "/logical-clouds/{logical-cloud-name}/cluster-quotas", + quotaHandler.getAllHandler).Methods("GET") + quotaRouter.HandleFunc( "/logical-clouds/{logical-cloud-name}/cluster-quotas/{quota-name}", quotaHandler.getHandler).Methods("GET") quotaRouter.HandleFunc( @@ -147,6 +145,9 @@ func NewRouter( "/logical-clouds/{logical-cloud-name}/kv-pairs", keyValueHandler.createHandler).Methods("POST") kvRouter.HandleFunc( + "/logical-clouds/{logical-cloud-name}/kv-pairs", + keyValueHandler.getAllHandler).Methods("GET") + kvRouter.HandleFunc( "/logical-clouds/{logical-cloud-name}/kv-pairs/{kv-pair-name}", keyValueHandler.getHandler).Methods("GET") kvRouter.HandleFunc( diff --git a/src/dcm/api/clusterHandler.go b/src/dcm/api/clusterHandler.go index d0c1e62c..1201611f 100644 --- a/src/dcm/api/clusterHandler.go +++ b/src/dcm/api/clusterHandler.go @@ -23,9 +23,8 @@ import ( "io" "net/http" - "github.com/onap/multicloud-k8s/src/dcm/pkg/module" - "github.com/gorilla/mux" + "github.com/onap/multicloud-k8s/src/dcm/pkg/module" ) // clusterHandler is used to store backend implementations objects @@ -33,8 +32,7 @@ type clusterHandler struct { client module.ClusterManager } -// CreateHandler handles creation of the cluster reference entry in the database - +// createHandler handles creation of the cluster reference entry in the database func (h clusterHandler) createHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) project := vars["project-name"] @@ -72,7 +70,31 @@ func (h clusterHandler) createHandler(w http.ResponseWriter, r *http.Request) { } } -// getHandler handle GET operations on a particular name +// getAllHandler handles GET operations over cluster references +// Returns a list of Cluster References +func (h clusterHandler) getAllHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + project := vars["project-name"] + logicalCloud := vars["logical-cloud-name"] + var ret interface{} + var err error + + ret, err = h.client.GetAllClusters(project, logicalCloud) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// getHandler handles GET operations on a particular name // Returns a Cluster Reference func (h clusterHandler) getHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -82,22 +104,14 @@ func (h clusterHandler) getHandler(w http.ResponseWriter, r *http.Request) { var ret interface{} var err error - if len(name) == 0 { - ret, err = h.client.GetAllClusters(project, logicalCloud) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } else { - ret, err = h.client.GetCluster(project, logicalCloud, name) - if err != nil { - if err.Error() == "Cluster Reference does not exist" { - http.Error(w, err.Error(), http.StatusNotFound) - return - } - http.Error(w, err.Error(), http.StatusInternalServerError) + ret, err = h.client.GetCluster(project, logicalCloud, name) + if err != nil { + if err.Error() == "Cluster Reference does not exist" { + http.Error(w, err.Error(), http.StatusNotFound) return } + http.Error(w, err.Error(), http.StatusInternalServerError) + return } w.Header().Set("Content-Type", "application/json") @@ -168,3 +182,43 @@ func (h clusterHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) } + +// getConfigHandler handles GET operations on kubeconfigs +// Returns a kubeconfig file +func (h clusterHandler) getConfigHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + project := vars["project-name"] + logicalCloud := vars["logical-cloud-name"] + name := vars["cluster-reference"] + var err error + + _, err = h.client.GetCluster(project, logicalCloud, name) + if err != nil { + if err.Error() == "Cluster Reference does not exist" { + http.Error(w, err.Error(), http.StatusNotFound) + } else { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + return + } + + cfg, err := h.client.GetClusterConfig(project, logicalCloud, name) + if err != nil { + if err.Error() == "The certificate for this cluster hasn't been issued yet. Please try later." { + http.Error(w, err.Error(), http.StatusAccepted) + } else if err.Error() == "Logical Cloud hasn't been applied yet" { + http.Error(w, err.Error(), http.StatusBadRequest) + } else { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + return + } + + w.Header().Set("Content-Type", "application/yaml") + w.WriteHeader(http.StatusOK) + _, err = io.WriteString(w, cfg) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} diff --git a/src/dcm/api/keyValueHandler.go b/src/dcm/api/keyValueHandler.go index a4a4f14a..69333efb 100644 --- a/src/dcm/api/keyValueHandler.go +++ b/src/dcm/api/keyValueHandler.go @@ -33,7 +33,6 @@ type keyValueHandler struct { } // CreateHandler handles creation of the key value entry in the database - func (h keyValueHandler) createHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) project := vars["project-name"] @@ -71,6 +70,30 @@ func (h keyValueHandler) createHandler(w http.ResponseWriter, r *http.Request) { } } +// getHandler handles GET operations over key-value pairs +// Returns a list of Key Values +func (h keyValueHandler) getAllHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + project := vars["project-name"] + logicalCloud := vars["logical-cloud-name"] + var ret interface{} + var err error + + ret, err = h.client.GetAllKVPairs(project, logicalCloud) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + // getHandler handle GET operations on a particular name // Returns a Key Value func (h keyValueHandler) getHandler(w http.ResponseWriter, r *http.Request) { @@ -81,22 +104,14 @@ func (h keyValueHandler) getHandler(w http.ResponseWriter, r *http.Request) { var ret interface{} var err error - if len(name) == 0 { - ret, err = h.client.GetAllKVPairs(project, logicalCloud) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } else { - ret, err = h.client.GetKVPair(project, logicalCloud, name) - if err != nil { - if err.Error() == "KV Pair does not exist" { - http.Error(w, err.Error(), http.StatusNotFound) - return - } - http.Error(w, err.Error(), http.StatusInternalServerError) + ret, err = h.client.GetKVPair(project, logicalCloud, name) + if err != nil { + if err.Error() == "KV Pair does not exist" { + http.Error(w, err.Error(), http.StatusNotFound) return } + http.Error(w, err.Error(), http.StatusInternalServerError) + return } w.Header().Set("Content-Type", "application/json") diff --git a/src/dcm/api/logicalCloudHandler.go b/src/dcm/api/logicalCloudHandler.go index fb0f0c63..b305b202 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" + orch "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module" pkgerrors "github.com/pkg/errors" ) @@ -35,8 +36,7 @@ type logicalCloudHandler struct { quotaClient module.QuotaManager } -// CreateHandler handles creation of the logical cloud entry in the database - +// CreateHandler handles the creation of a logical cloud func (h logicalCloudHandler) createHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -59,6 +59,15 @@ func (h logicalCloudHandler) createHandler(w http.ResponseWriter, r *http.Reques return } + // Validate that the specified Project exists + // before associating a Logical Cloud with it + p := orch.NewProjectClient() + _, err = p.GetProject(project) + if err != nil { + http.Error(w, "The specified project does not exist.", http.StatusNotFound) + return + } + ret, err := h.client.Create(project, v) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -74,7 +83,30 @@ func (h logicalCloudHandler) createHandler(w http.ResponseWriter, r *http.Reques } } -// getHandler handle GET operations on a particular name +// getAllHandler handles GET operations over logical clouds +// Returns a list of Logical Clouds +func (h logicalCloudHandler) getAllHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + project := vars["project-name"] + var ret interface{} + var err error + + ret, err = h.client.GetAll(project) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// getHandler handles GET operations on a particular name // Returns a Logical Cloud func (h logicalCloudHandler) getHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -83,22 +115,14 @@ func (h logicalCloudHandler) getHandler(w http.ResponseWriter, r *http.Request) var ret interface{} var err error - if len(name) == 0 { - ret, err = h.client.GetAll(project) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } else { - ret, 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) + ret, 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 } w.Header().Set("Content-Type", "application/json") @@ -110,7 +134,7 @@ func (h logicalCloudHandler) getHandler(w http.ResponseWriter, r *http.Request) } } -// UpdateHandler handles Update operations on a particular logical cloud +// updateHandler handles Update operations on a particular logical cloud func (h logicalCloudHandler) updateHandler(w http.ResponseWriter, r *http.Request) { var v module.LogicalCloud vars := mux.Vars(r) @@ -152,6 +176,7 @@ func (h logicalCloudHandler) updateHandler(w http.ResponseWriter, r *http.Reques } } +// deleteHandler handles Delete operations on a particular logical cloud func (h logicalCloudHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) project := vars["project-name"] @@ -163,6 +188,10 @@ func (h logicalCloudHandler) deleteHandler(w http.ResponseWriter, r *http.Reques http.Error(w, err.Error(), http.StatusNotFound) return } + if err.Error() == "The Logical Cloud can't be deleted yet, it is being terminated." { + http.Error(w, err.Error(), http.StatusConflict) + return + } http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -170,6 +199,7 @@ func (h logicalCloudHandler) deleteHandler(w http.ResponseWriter, r *http.Reques w.WriteHeader(http.StatusNoContent) } +// applyHandler handles applying a particular logical cloud func (h logicalCloudHandler) applyHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) project := vars["project-name"] @@ -186,13 +216,6 @@ func (h logicalCloudHandler) applyHandler(w http.ResponseWriter, r *http.Request return } - _, ctxVal, err := h.client.GetLogicalCloudContext(name) - if ctxVal != "" { - err = pkgerrors.New("Logical Cloud already applied") - http.Error(w, err.Error(), http.StatusConflict) - return - } - // Get Clusters clusters, err := h.clusterClient.GetAllClusters(project, name) @@ -205,15 +228,20 @@ func (h logicalCloudHandler) applyHandler(w http.ResponseWriter, r *http.Request return } - //Get Quotas + // Get Quotas quotas, err := h.quotaClient.GetAllQuotas(project, name) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } - err = module.CreateEtcdContext(lc, clusters, quotas) + // Apply the Logical Cloud + err = module.Apply(project, lc, clusters, quotas) if err != nil { + if err.Error() == "The Logical Cloud can't be re-applied yet, it is being terminated." { + http.Error(w, err.Error(), http.StatusConflict) + return + } http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -221,6 +249,7 @@ func (h logicalCloudHandler) applyHandler(w http.ResponseWriter, r *http.Request return } +// applyHandler handles terminating a particular logical cloud func (h logicalCloudHandler) terminateHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) project := vars["project-name"] @@ -237,7 +266,7 @@ func (h logicalCloudHandler) terminateHandler(w http.ResponseWriter, r *http.Req return } - _, ctxVal, err := h.client.GetLogicalCloudContext(name) + _, ctxVal, err := h.client.GetLogicalCloudContext(project, name) if ctxVal == "" { err = pkgerrors.New("Logical Cloud hasn't been applied yet") http.Error(w, err.Error(), http.StatusConflict) @@ -252,14 +281,15 @@ func (h logicalCloudHandler) terminateHandler(w http.ResponseWriter, r *http.Req return } - //Get Quotas + // 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) + // Terminate the Logical Cloud + err = module.Terminate(project, lc, clusters, quotas) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/src/dcm/api/quotaHandler.go b/src/dcm/api/quotaHandler.go index fd9b40f8..1f0e45a5 100644 --- a/src/dcm/api/quotaHandler.go +++ b/src/dcm/api/quotaHandler.go @@ -23,9 +23,8 @@ import ( "io" "net/http" - "github.com/onap/multicloud-k8s/src/dcm/pkg/module" - "github.com/gorilla/mux" + "github.com/onap/multicloud-k8s/src/dcm/pkg/module" ) // quotaHandler is used to store backend implementations objects @@ -34,7 +33,6 @@ type quotaHandler struct { } // CreateHandler handles creation of the quota entry in the database - func (h quotaHandler) createHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) project := vars["project-name"] @@ -72,8 +70,32 @@ func (h quotaHandler) createHandler(w http.ResponseWriter, r *http.Request) { } } +// getHandler handles GET operations over quotas +// Returns a list of Quotas +func (h quotaHandler) getAllHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + project := vars["project-name"] + logicalCloud := vars["logical-cloud-name"] + var ret interface{} + var err error + + ret, err = h.client.GetAllQuotas(project, logicalCloud) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + // getHandler handle GET operations on a particular name -// Returns a quota +// Returns a Quota func (h quotaHandler) getHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) project := vars["project-name"] @@ -82,22 +104,14 @@ func (h quotaHandler) getHandler(w http.ResponseWriter, r *http.Request) { var ret interface{} var err error - if len(name) == 0 { - ret, err = h.client.GetAllQuotas(project, logicalCloud) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } else { - ret, err = h.client.GetQuota(project, logicalCloud, name) - if err != nil { - if err.Error() == "Cluster Quota does not exist" { - http.Error(w, err.Error(), http.StatusNotFound) - return - } - http.Error(w, err.Error(), http.StatusInternalServerError) + ret, err = h.client.GetQuota(project, logicalCloud, name) + if err != nil { + if err.Error() == "Cluster Quota does not exist" { + http.Error(w, err.Error(), http.StatusNotFound) return } + http.Error(w, err.Error(), http.StatusInternalServerError) + return } w.Header().Set("Content-Type", "application/json") diff --git a/src/dcm/api/userPermissionsHandler.go b/src/dcm/api/userPermissionsHandler.go index 3ac955fa..6d88f573 100644 --- a/src/dcm/api/userPermissionsHandler.go +++ b/src/dcm/api/userPermissionsHandler.go @@ -33,7 +33,6 @@ type userPermissionHandler struct { } // CreateHandler handles creation of the user permission entry in the database - func (h userPermissionHandler) createHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -72,7 +71,31 @@ func (h userPermissionHandler) createHandler(w http.ResponseWriter, r *http.Requ } } -// getHandler handle GET operations on a particular name +// getAllHandler handles GET operations over user permissions +// Returns a list of User Permissions +func (h userPermissionHandler) getAllHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + project := vars["project-name"] + logicalCloud := vars["logical-cloud-name"] + var ret interface{} + var err error + + ret, err = h.client.GetAllUserPerms(project, logicalCloud) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + err = json.NewEncoder(w).Encode(ret) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +// getHandler handles GET operations on a particular name // Returns a User Permission func (h userPermissionHandler) getHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -82,22 +105,14 @@ func (h userPermissionHandler) getHandler(w http.ResponseWriter, r *http.Request var ret interface{} var err error - if len(name) == 0 { - ret, err = h.client.GetAllUserPerms(project, logicalCloud) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } else { - ret, err = h.client.GetUserPerm(project, logicalCloud, name) - if err != nil { - if err.Error() == "User Permission does not exist" { - http.Error(w, err.Error(), http.StatusNotFound) - return - } - http.Error(w, err.Error(), http.StatusInternalServerError) + ret, err = h.client.GetUserPerm(project, logicalCloud, name) + if err != nil { + if err.Error() == "User Permission does not exist" { + http.Error(w, err.Error(), http.StatusNotFound) return } + http.Error(w, err.Error(), http.StatusInternalServerError) + return } w.Header().Set("Content-Type", "application/json") diff --git a/src/dcm/config.json b/src/dcm/config.json index 65a18acb..7e1f579c 100644 --- a/src/dcm/config.json +++ b/src/dcm/config.json @@ -1,14 +1,6 @@ { - "database-ip": "172.18.0.2", "database-type": "mongo", - "plugin-dir": "plugins", - "service-port": "9077", - "ca-file": "ca.cert", - "server-cert": "server.cert", - "server-key": "server.key", - "password": "", + "database-ip": "172.18.0.2", "etcd-ip": "172.18.0.3", - "etcd-cert": "", - "etcd-key": "", - "etcd-ca-file": "" + "service-port": "9077" } diff --git a/src/dcm/go.mod b/src/dcm/go.mod index 1f04ac12..71888287 100644 --- a/src/dcm/go.mod +++ b/src/dcm/go.mod @@ -3,6 +3,8 @@ module github.com/onap/multicloud-k8s/src/dcm require ( github.com/gorilla/handlers v1.3.0 github.com/gorilla/mux v1.7.3 + github.com/onap/multicloud-k8s/src/clm v0.0.0-20200630152613-7c20f73e7c5d + github.com/onap/multicloud-k8s/src/monitor v0.0.0-20200818155723-a5ffa8aadf49 github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200818155723-a5ffa8aadf49 github.com/pkg/errors v0.9.1 github.com/russross/blackfriday/v2 v2.0.1 diff --git a/src/dcm/go.sum b/src/dcm/go.sum index 983ceae2..d1b1e30f 100644 --- a/src/dcm/go.sum +++ b/src/dcm/go.sum @@ -807,6 +807,7 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= +github.com/onap/multicloud-k8s v0.0.0-20200928235143-603a68284970 h1:yWZDIjZBhwtbV7+fa8QB/WhPlHCR4qBhY2OG7K83wGs= github.com/onap/multicloud-k8s/src/ncm v0.0.0-20200515060444-c77850a75eee/go.mod h1:q6s8c45A2NN2V4lxciJ7OmCZFaS1uQSWaGxGG3UM3kM= github.com/onap/multicloud-k8s/src/rsync v0.0.0-20200630152613-7c20f73e7c5d h1:0aXmwqPN8MjyqjKK5L1IhhP/hpP5nGj6xMgo6AOzCPI= github.com/onap/multicloud-k8s/src/rsync v0.0.0-20200630152613-7c20f73e7c5d/go.mod h1:pVhhvg5N0Qy8QDJkYRnWCQbxLDV5GYLmPyzlndbGx7w= @@ -1522,6 +1523,8 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= k8s.io/api v0.16.9 h1:3vCx0WX9qcg1Hv4aQ/G1tiIKectGVuimvPVTJU4VOCA= k8s.io/api v0.16.9/go.mod h1:Y7dZNHs1Xy0mSwSlzL9QShi6qkljnN41yR8oWCRTDe8= +k8s.io/api v0.18.2 h1:wG5g5ZmSVgm5B+eHMIbI9EGATS2L8Z72rda19RIEgY8= +k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/apiextensions-apiserver v0.16.9 h1:CE+SWS6PM3MDJiyihW5hnDiqsJ/sjMaSMblqzH37J18= k8s.io/apiextensions-apiserver v0.16.9/go.mod h1:j/+KedxOeRSPMkvLNyKMbIT3+saXdTO4jTBplTmXJR4= k8s.io/apimachinery v0.16.10-beta.0 h1:l+qmzwWTMIBtFGlo5OpPYoZKCgGLtpAWvIa8Wcr9luU= diff --git a/src/dcm/pkg/module/apply.go b/src/dcm/pkg/module/apply.go index a866934a..c3378ab8 100644 --- a/src/dcm/pkg/module/apply.go +++ b/src/dcm/pkg/module/apply.go @@ -84,33 +84,49 @@ type RoleRef struct { ApiGroup string `yaml:"apiGroup"` } -func createNamespace(logicalcloud LogicalCloud) (string, error) { +func cleanupCompositeApp(context appcontext.AppContext, err error, reason string, details []string) error { + cleanuperr := context.DeleteCompositeApp() + newerr := pkgerrors.Wrap(err, reason) + if cleanuperr != nil { + log.Warn("Error cleaning AppContext, ", log.Fields{ + "Related details": details, + }) + // this would be useful: https://godoc.org/go.uber.org/multierr + return pkgerrors.Wrap(err, "After previous error, cleaning the AppContext also failed.") + } + return newerr +} + +func createNamespace(logicalcloud LogicalCloud) (string, string, error) { + + name := logicalcloud.Specification.NameSpace namespace := Resource{ ApiVersion: "v1", Kind: "Namespace", MetaData: MetaDatas{ - Name: logicalcloud.Specification.NameSpace, + Name: name, }, } nsData, err := yaml.Marshal(&namespace) if err != nil { - return "", err + return "", "", err } - return string(nsData), nil + return string(nsData), strings.Join([]string{name, "+Namespace"}, ""), nil } -func createRole(logicalcloud LogicalCloud) (string, error) { +func createRole(logicalcloud LogicalCloud) (string, string, error) { userPermissions := logicalcloud.Specification.User.UserPermissions[0] + name := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-role"}, "") role := Resource{ ApiVersion: "rbac.authorization.k8s.io/v1beta1", Kind: "Role", MetaData: MetaDatas{ - Name: strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-role"}, ""), + Name: name, Namespace: logicalcloud.Specification.NameSpace, }, Rules: []RoleRules{RoleRules{ @@ -123,19 +139,21 @@ func createRole(logicalcloud LogicalCloud) (string, error) { roleData, err := yaml.Marshal(&role) if err != nil { - return "", err + return "", "", err } - return string(roleData), nil + return string(roleData), strings.Join([]string{name, "+Role"}, ""), nil } -func createRoleBinding(logicalcloud LogicalCloud) (string, error) { +func createRoleBinding(logicalcloud LogicalCloud) (string, string, error) { + + name := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-roleBinding"}, "") roleBinding := Resource{ ApiVersion: "rbac.authorization.k8s.io/v1beta1", Kind: "RoleBinding", MetaData: MetaDatas{ - Name: strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-roleBinding"}, ""), + Name: name, Namespace: logicalcloud.Specification.NameSpace, }, Subjects: []RoleSubjects{RoleSubjects{ @@ -154,19 +172,22 @@ func createRoleBinding(logicalcloud LogicalCloud) (string, error) { rBData, err := yaml.Marshal(&roleBinding) if err != nil { - return "", err + return "", "", err } - return string(rBData), nil + return string(rBData), strings.Join([]string{name, "+RoleBinding"}, ""), nil } -func createQuota(quota []Quota, namespace string) (string, error) { +func createQuota(quota []Quota, namespace string) (string, string, error) { + lcQuota := quota[0] + name := lcQuota.MetaData.QuotaName + q := Resource{ ApiVersion: "v1", Kind: "ResourceQuota", MetaData: MetaDatas{ - Name: lcQuota.MetaData.QuotaName, + Name: name, Namespace: namespace, }, Specification: Specs{ @@ -176,26 +197,28 @@ func createQuota(quota []Quota, namespace string) (string, error) { qData, err := yaml.Marshal(&q) if err != nil { - return "", err + return "", "", err } - return string(qData), nil + return string(qData), strings.Join([]string{name, "+ResourceQuota"}, ""), nil } -func createUserCSR(logicalcloud LogicalCloud) (string, string, error) { +func createUserCSR(logicalcloud LogicalCloud) (string, string, string, error) { + KEYSIZE := 4096 userName := logicalcloud.Specification.User.UserName + name := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-user-csr"}, "") key, err := rsa.GenerateKey(rand.Reader, KEYSIZE) if err != nil { - return "", "", err + return "", "", "", err } csrTemplate := x509.CertificateRequest{Subject: pkix.Name{CommonName: userName}} csrCert, err := x509.CreateCertificateRequest(rand.Reader, &csrTemplate, key) if err != nil { - return "", "", err + return "", "", "", err } //Encode csr @@ -208,8 +231,7 @@ func createUserCSR(logicalcloud LogicalCloud) (string, string, error) { ApiVersion: "certificates.k8s.io/v1beta1", Kind: "CertificateSigningRequest", MetaData: MetaDatas{ - Name: strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-user-csr"}, ""), - // Namespace: logicalcloud.Specification.NameSpace, + Name: name, }, Specification: Specs{ Request: base64.StdEncoding.EncodeToString(csr), @@ -219,7 +241,7 @@ func createUserCSR(logicalcloud LogicalCloud) (string, string, error) { csrData, err := yaml.Marshal(&csrObj) if err != nil { - return "", "", err + return "", "", "", err } keyData := base64.StdEncoding.EncodeToString(pem.EncodeToMemory( @@ -229,10 +251,10 @@ func createUserCSR(logicalcloud LogicalCloud) (string, string, error) { }, )) if err != nil { - return "", "", err + return "", "", "", err } - return string(csrData), string(keyData), nil + return string(csrData), string(keyData), strings.Join([]string{name, "+CertificateSigningRequest"}, ""), nil } func createApprovalSubresource(logicalcloud LogicalCloud) (string, error) { @@ -266,7 +288,7 @@ func queryDBAndSetRsyncInfo() (installappclient.RsyncInfo, error) { } /* -callRsyncInstall method shall take in the app context id and invokes the rsync service via grpc +callRsyncInstall method shall take in the app context id and invoke the rsync service via grpc */ func callRsyncInstall(contextid interface{}) error { rsyncInfo, err := queryDBAndSetRsyncInfo() @@ -286,7 +308,7 @@ func callRsyncInstall(contextid interface{}) error { } /* -callRsyncUninstall method shall take in the app context id and invokes the rsync service via grpc +callRsyncUninstall method shall take in the app context id and invoke the rsync service via grpc */ func callRsyncUninstall(contextid interface{}) error { rsyncInfo, err := queryDBAndSetRsyncInfo() @@ -305,56 +327,82 @@ func callRsyncUninstall(contextid interface{}) error { return nil } -func CreateEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster, +// Apply prepares all yaml resources to be given to the clusters via rsync, +// then creates an appcontext with such resources and asks rsync to apply the logical cloud +func Apply(project string, logicalcloud LogicalCloud, clusterList []Cluster, quotaList []Quota) error { APP := "logical-cloud" logicalCloudName := logicalcloud.MetaData.LogicalCloudName - project := "test-project" // FIXME(igordc): temporary, need to do some rework in the LC structs - //Resource Names - namespaceName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+namespace"}, "") - roleName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+role"}, "") - roleBindingName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+roleBinding"}, "") - quotaName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+quota"}, "") - csrName := strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "+CertificateSigningRequest"}, "") + lcclient := NewLogicalCloudClient() + lckey := LogicalCloudKey{ + LogicalCloudName: logicalcloud.MetaData.LogicalCloudName, + Project: project, + } + + // Check if there was a previous context for this logical cloud + ac, cid, err := lcclient.GetLogicalCloudContext(project, logicalCloudName) + if cid != "" { + // Make sure rsync status for this logical cloud is Terminated, + // otherwise we can't re-apply logical cloud yet + acStatus, _ := getAppContextStatus(ac) + switch acStatus.Status { + case appcontext.AppContextStatusEnum.Terminated: + // We now know Logical Cloud has terminated, so let's update the entry before we process the apply + err = db.DBconn.RemoveTag(lcclient.storeName, lckey, lcclient.tagContext) + if err != nil { + return pkgerrors.Wrap(err, "Error removing lccontext tag from Logical Cloud") + } + // And fully delete the old AppContext + err := ac.DeleteCompositeApp() + if err != nil { + return pkgerrors.Wrap(err, "Error deleting AppContext CompositeApp Logical Cloud") + } + case appcontext.AppContextStatusEnum.Terminating: + return pkgerrors.New("The Logical Cloud can't be re-applied yet, it is being terminated.") + case appcontext.AppContextStatusEnum.Instantiated: + return pkgerrors.New("The Logical Cloud is already applied.") + default: + return pkgerrors.New("The Logical Cloud can't be applied at this point.") + } + } // Get resources to be added - namespace, err := createNamespace(logicalcloud) + namespace, namespaceName, err := createNamespace(logicalcloud) if err != nil { return pkgerrors.Wrap(err, "Error Creating Namespace YAML for logical cloud") } - role, err := createRole(logicalcloud) + role, roleName, err := createRole(logicalcloud) if err != nil { return pkgerrors.Wrap(err, "Error Creating Role YAML for logical cloud") } - roleBinding, err := createRoleBinding(logicalcloud) + roleBinding, roleBindingName, err := createRoleBinding(logicalcloud) if err != nil { return pkgerrors.Wrap(err, "Error Creating RoleBinding YAML for logical cloud") } - quota, err := createQuota(quotaList, logicalcloud.Specification.NameSpace) + quota, quotaName, err := createQuota(quotaList, logicalcloud.Specification.NameSpace) if err != nil { return pkgerrors.Wrap(err, "Error Creating Quota YAML for logical cloud") } - csr, key, err := createUserCSR(logicalcloud) + csr, key, csrName, err := createUserCSR(logicalcloud) if err != nil { return pkgerrors.Wrap(err, "Error Creating User CSR and Key for logical cloud") } approval, err := createApprovalSubresource(logicalcloud) + // From this point on, we are dealing with a new context (not "ac" from above) context := appcontext.AppContext{} ctxVal, err := context.InitAppContext() if err != nil { return pkgerrors.Wrap(err, "Error creating AppContext") } - fmt.Printf("%v\n", ctxVal) - handle, err := context.CreateCompositeApp() if err != nil { return pkgerrors.Wrap(err, "Error creating AppContext CompositeApp") @@ -362,130 +410,60 @@ func CreateEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster, appHandle, err := context.AddApp(handle, APP) if err != nil { - cleanuperr := context.DeleteCompositeApp() - if cleanuperr != nil { - log.Warn("Error cleaning AppContext CompositeApp create failure", log.Fields{ - "logical-cloud": logicalCloudName, - }) - } - return pkgerrors.Wrap(err, "Error adding App to AppContext") + return cleanupCompositeApp(context, err, "Error adding App to AppContext", []string{logicalCloudName, ctxVal.(string)}) } // Iterate through cluster list and add all the clusters for _, cluster := range clusterList { clusterName := strings.Join([]string{cluster.Specification.ClusterProvider, "+", cluster.Specification.ClusterName}, "") clusterHandle, err := context.AddCluster(appHandle, clusterName) + // pre-build array to pass to cleanupCompositeApp() [for performance] + details := []string{logicalCloudName, clusterName, ctxVal.(string)} if err != nil { - cleanuperr := context.DeleteCompositeApp() - if cleanuperr != nil { - log.Warn("Error cleaning AppContext after add cluster failure", log.Fields{ - "cluster-provider": cluster.Specification.ClusterProvider, - "cluster": cluster.Specification.ClusterName, - "logical-cloud": logicalCloudName, - }) - } - return pkgerrors.Wrap(err, "Error adding Cluster to AppContext") + return cleanupCompositeApp(context, err, "Error adding Cluster to AppContext", details) } // Add namespace resource to each cluster _, err = context.AddResource(clusterHandle, namespaceName, namespace) if err != nil { - cleanuperr := context.DeleteCompositeApp() - if cleanuperr != nil { - log.Warn("Error cleaning AppContext after add namespace resource failure", log.Fields{ - "cluster-provider": cluster.Specification.ClusterProvider, - "cluster": cluster.Specification.ClusterName, - "logical-cloud": logicalCloudName, - }) - } - return pkgerrors.Wrap(err, "Error adding Namespace Resource to AppContext") + return cleanupCompositeApp(context, err, "Error adding Namespace Resource to AppContext", details) } // Add csr resource to each cluster csrHandle, err := context.AddResource(clusterHandle, csrName, csr) if err != nil { - cleanuperr := context.DeleteCompositeApp() - if cleanuperr != nil { - log.Warn("Error cleaning AppContext after add CSR resource failure", log.Fields{ - "cluster-provider": cluster.Specification.ClusterProvider, - "cluster": cluster.Specification.ClusterName, - "logical-cloud": logicalCloudName, - }) - } - return pkgerrors.Wrap(err, "Error adding CSR Resource to AppContext") + return cleanupCompositeApp(context, err, "Error adding CSR Resource to AppContext", details) } // Add csr approval as a subresource of csr: _, err = context.AddLevelValue(csrHandle, "subresource/approval", approval) if err != nil { - cleanuperr := context.DeleteCompositeApp() - if cleanuperr != nil { - log.Warn("Error cleaning AppContext after add CSR approval failure", log.Fields{ - "cluster-provider": cluster.Specification.ClusterProvider, - "cluster": cluster.Specification.ClusterName, - "logical-cloud": logicalCloudName, - }) - } - return pkgerrors.Wrap(err, "Error approving CSR via AppContext") + return cleanupCompositeApp(context, err, "Error approving CSR via AppContext", details) } // Add private key to MongoDB - lckey := LogicalCloudKey{ - LogicalCloudName: logicalcloud.MetaData.LogicalCloudName, - Project: project, - } err = db.DBconn.Insert("orchestrator", lckey, nil, "privatekey", key) if err != nil { - cleanuperr := context.DeleteCompositeApp() - if cleanuperr != nil { - log.Warn("Error cleaning AppContext after DB insert failure", log.Fields{ - "logical-cloud": logicalcloud.MetaData.LogicalCloudName, - }) - } - return pkgerrors.Wrap(err, "Error adding private key to DB") + return cleanupCompositeApp(context, err, "Error adding private key to DB", details) } // Add Role resource to each cluster _, err = context.AddResource(clusterHandle, roleName, role) if err != nil { - cleanuperr := context.DeleteCompositeApp() - if cleanuperr != nil { - log.Warn("Error cleaning AppContext after add role resource failure", log.Fields{ - "cluster-provider": cluster.Specification.ClusterProvider, - "cluster": cluster.Specification.ClusterName, - "logical-cloud": logicalCloudName, - }) - } - return pkgerrors.Wrap(err, "Error adding role Resource to AppContext") + return cleanupCompositeApp(context, err, "Error adding role Resource to AppContext", details) } // Add RoleBinding resource to each cluster _, err = context.AddResource(clusterHandle, roleBindingName, roleBinding) if err != nil { - cleanuperr := context.DeleteCompositeApp() - if cleanuperr != nil { - log.Warn("Error cleaning AppContext after add roleBinding resource failure", log.Fields{ - "cluster-provider": cluster.Specification.ClusterProvider, - "cluster": cluster.Specification.ClusterName, - "logical-cloud": logicalCloudName, - }) - } - return pkgerrors.Wrap(err, "Error adding roleBinding Resource to AppContext") + return cleanupCompositeApp(context, err, "Error adding roleBinding Resource to AppContext", details) } // Add quota resource to each cluster _, err = context.AddResource(clusterHandle, quotaName, quota) if err != nil { - cleanuperr := context.DeleteCompositeApp() - if cleanuperr != nil { - log.Warn("Error cleaning AppContext after add quota resource failure", log.Fields{ - "cluster-provider": cluster.Specification.ClusterProvider, - "cluster": cluster.Specification.ClusterName, - "logical-cloud": logicalCloudName, - }) - } - return pkgerrors.Wrap(err, "Error adding quota Resource to AppContext") + return cleanupCompositeApp(context, err, "Error adding quota Resource to AppContext", details) } // Add Subresource Order and Subresource Dependency @@ -510,81 +488,42 @@ func CreateEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster, return pkgerrors.Wrap(err, "Error creating resource order JSON") } appDependency, err := json.Marshal(map[string]map[string]string{"appdependency": map[string]string{APP: "go"}}) - if err != nil { return pkgerrors.Wrap(err, "Error creating resource dependency JSON") } + // Add Resource-level Order and Dependency _, err = context.AddInstruction(clusterHandle, "resource", "order", string(resOrder)) if err != nil { - cleanuperr := context.DeleteCompositeApp() - if cleanuperr != nil { - log.Warn("Error cleaning AppContext after add instruction failure", log.Fields{ - "cluster-provider": cluster.Specification.ClusterProvider, - "cluster": cluster.Specification.ClusterName, - "logical-cloud": logicalCloudName, - }) - } - return pkgerrors.Wrap(err, "Error adding instruction order to AppContext") + return cleanupCompositeApp(context, err, "Error adding instruction order to AppContext", details) } - _, err = context.AddInstruction(clusterHandle, "resource", "dependency", string(resDependency)) if err != nil { - cleanuperr := context.DeleteCompositeApp() - if cleanuperr != nil { - log.Warn("Error cleaning AppContext after add instruction failure", log.Fields{ - "cluster-provider": cluster.Specification.ClusterProvider, - "cluster": cluster.Specification.ClusterName, - "logical-cloud": logicalCloudName, - }) - } - return pkgerrors.Wrap(err, "Error adding instruction dependency to AppContext") + return cleanupCompositeApp(context, err, "Error adding instruction dependency to AppContext", details) } - _, err = context.AddInstruction(csrHandle, "subresource", "order", string(subresOrder)) if err != nil { - cleanuperr := context.DeleteCompositeApp() - if cleanuperr != nil { - log.Warn("Error cleaning AppContext after add instruction failure", log.Fields{ - "cluster-provider": cluster.Specification.ClusterProvider, - "cluster": cluster.Specification.ClusterName, - "logical-cloud": logicalCloudName, - }) - } - return pkgerrors.Wrap(err, "Error adding instruction order to AppContext") + return cleanupCompositeApp(context, err, "Error adding instruction order to AppContext", details) } - _, err = context.AddInstruction(csrHandle, "subresource", "dependency", string(subresDependency)) if err != nil { - cleanuperr := context.DeleteCompositeApp() - if cleanuperr != nil { - log.Warn("Error cleaning AppContext after add instruction failure", log.Fields{ - "cluster-provider": cluster.Specification.ClusterProvider, - "cluster": cluster.Specification.ClusterName, - "logical-cloud": logicalCloudName, - }) - } - return pkgerrors.Wrap(err, "Error adding instruction dependency to AppContext") + return cleanupCompositeApp(context, err, "Error adding instruction dependency to AppContext", details) } // Add App-level Order and Dependency _, err = context.AddInstruction(handle, "app", "order", string(appOrder)) + if err != nil { + return cleanupCompositeApp(context, err, "Error adding app-level order to AppContext", details) + } _, err = context.AddInstruction(handle, "app", "dependency", string(appDependency)) + if err != nil { + return cleanupCompositeApp(context, err, "Error adding app-level dependency to AppContext", details) + } } // save the context in the logicalcloud db record - lckey := LogicalCloudKey{ - LogicalCloudName: logicalcloud.MetaData.LogicalCloudName, - Project: project, - } err = db.DBconn.Insert("orchestrator", lckey, nil, "lccontext", ctxVal) if err != nil { - cleanuperr := context.DeleteCompositeApp() - if cleanuperr != nil { - log.Warn("Error cleaning AppContext after DB insert failure", log.Fields{ - "logical-cloud": logicalcloud.MetaData.LogicalCloudName, - }) - } - return pkgerrors.Wrap(err, "Error adding AppContext to DB") + return cleanupCompositeApp(context, err, "Error adding AppContext to DB", []string{logicalCloudName, ctxVal.(string)}) } // call resource synchronizer to instantiate the CRs in the cluster @@ -597,48 +536,37 @@ func CreateEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster, } -// TODO: rename these methods -// DestroyEtcdContext remove from rsync then delete appcontext and all resources -func DestroyEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster, +// Terminate asks rsync to terminate the logical cloud, then waits in the background until +// rsync claims the logical cloud is terminated, and then deletes the appcontext +func Terminate(project string, 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) - } + lcclient := NewLogicalCloudClient() - // call resource synchronizer to delete the CRs from every cluster of the logical cloud - err = callRsyncUninstall(ctxVal) + ac, cid, err := lcclient.GetLogicalCloudContext(project, logicalCloudName) if err != nil { - return err + return pkgerrors.Wrapf(err, "Logical Cloud doesn't seem applied: %v", logicalCloudName) + } + + // Check if there was a previous context for this logical cloud + if cid != "" { + // Make sure rsync status for this logical cloud is Terminated, + // otherwise we can't re-apply logical cloud yet + acStatus, _ := getAppContextStatus(ac) + switch acStatus.Status { + case appcontext.AppContextStatusEnum.Terminated: + return pkgerrors.New("The Logical Cloud has already been terminated: " + logicalCloudName) + case appcontext.AppContextStatusEnum.Terminating: + return pkgerrors.New("The Logical Cloud is already being terminated: " + logicalCloudName) + case appcontext.AppContextStatusEnum.Instantiated: + // call resource synchronizer to delete the CRs from every cluster of the logical cloud + err = callRsyncUninstall(cid) + return err + default: + return pkgerrors.New("The Logical Cloud can't be deleted at this point: " + logicalCloudName) + } } - - // 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 + return pkgerrors.New("Logical Cloud is not applied: " + logicalCloudName) } diff --git a/src/dcm/pkg/module/cluster.go b/src/dcm/pkg/module/cluster.go index 85b20117..9aecc6ca 100644 --- a/src/dcm/pkg/module/cluster.go +++ b/src/dcm/pkg/module/cluster.go @@ -17,7 +17,15 @@ package module import ( + "encoding/base64" + "encoding/json" + "strings" + + clm "github.com/onap/multicloud-k8s/src/clm/pkg/cluster" + rb "github.com/onap/multicloud-k8s/src/monitor/pkg/apis/k8splugin/v1alpha1" + log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils" pkgerrors "github.com/pkg/errors" + "gopkg.in/yaml.v2" ) // Cluster contains the parameters needed for a Cluster @@ -37,6 +45,7 @@ type ClusterSpec struct { ClusterProvider string `json:"cluster-provider"` ClusterName string `json:"cluster-name"` LoadBalancerIP string `json:"loadbalancer-ip"` + Certificate string `json:"certificate"` } type ClusterKey struct { @@ -45,6 +54,48 @@ type ClusterKey struct { ClusterReference string `json:"clname"` } +type KubeConfig struct { + ApiVersion string `yaml:"apiVersion"` + Kind string `yaml:"kind"` + Clusters []KubeCluster `yaml:"clusters"` + Contexts []KubeContext `yaml:"contexts"` + CurrentContext string `yaml:"current-context"` + Preferences map[string]string `yaml:"preferences"` + Users []KubeUser `yaml:"users"` +} + +type KubeCluster struct { + ClusterDef KubeClusterDef `yaml:"cluster"` + ClusterName string `yaml:"name"` +} + +type KubeClusterDef struct { + CertificateAuthorityData string `yaml:"certificate-authority-data"` + Server string `yaml:"server"` +} + +type KubeContext struct { + ContextDef KubeContextDef `yaml:"context"` + ContextName string `yaml:"name"` +} + +type KubeContextDef struct { + Cluster string `yaml:"cluster"` + Namespace string `yaml:"namespace,omitempty"` + User string `yaml:"user"` +} + +type KubeUser struct { + UserName string `yaml:"name"` + UserDef KubeUserDef `yaml:"user"` +} + +type KubeUserDef struct { + ClientCertificateData string `yaml:"client-certificate-data"` + ClientKeyData string `yaml:"client-key-data"` + // client-certificate and client-key are NOT implemented +} + // ClusterManager is an interface that exposes the connection // functionality type ClusterManager interface { @@ -53,6 +104,7 @@ type ClusterManager interface { GetAllClusters(project, logicalCloud string) ([]Cluster, error) DeleteCluster(project, logicalCloud, name string) error UpdateCluster(project, logicalCloud, name string, c Cluster) (Cluster, error) + GetClusterConfig(project, logicalcloud, name string) (string, error) } // ClusterClient implements the ClusterManager @@ -204,3 +256,169 @@ func (v *ClusterClient) UpdateCluster(project, logicalCloud, clusterReference st } return c, nil } + +// Get returns Cluster's kubeconfig for corresponding cluster reference +func (v *ClusterClient) GetClusterConfig(project, logicalCloud, clusterReference string) (string, error) { + lcClient := NewLogicalCloudClient() + context, ctxVal, err := lcClient.GetLogicalCloudContext(project, logicalCloud) + if err != nil { + return "", pkgerrors.Wrap(err, "Error getting logical cloud context.") + } + if ctxVal == "" { + return "", pkgerrors.New("Logical Cloud hasn't been applied yet") + } + + // private key comes from logical cloud + lckey := LogicalCloudKey{ + Project: project, + LogicalCloudName: logicalCloud, + } + // get logical cloud resource + lc, err := lcClient.Get(project, logicalCloud) + if err != nil { + return "", pkgerrors.Wrap(err, "Failed getting logical cloud") + } + // get user's private key + privateKeyData, err := v.util.DBFind(v.storeName, lckey, "privatekey") + if err != nil { + return "", pkgerrors.Wrap(err, "Failed getting private key from logical cloud") + } + + // get cluster from dcm (need provider/name) + cluster, err := v.GetCluster(project, logicalCloud, clusterReference) + if err != nil { + return "", pkgerrors.Wrap(err, "Failed getting cluster") + } + + // before attempting to generate a kubeconfig, + // check if certificate has been issued and copy it from etcd to mongodb + if cluster.Specification.Certificate == "" { + log.Info("Certificate not yet in MongoDB, checking etcd.", log.Fields{}) + + // access etcd + clusterName := strings.Join([]string{cluster.Specification.ClusterProvider, "+", cluster.Specification.ClusterName}, "") + + // get the app context handle for the status of this cluster (which should contain the certificate inside, if already issued) + statusHandle, err := context.GetClusterStatusHandle("logical-cloud", clusterName) + + if err != nil { + return "", pkgerrors.New("The cluster doesn't contain status, please check if all services are up and running.") + } + statusRaw, err := context.GetValue(statusHandle) + if err != nil { + return "", pkgerrors.Wrap(err, "An error occurred while reading the cluster status.") + } + + var rbstatus rb.ResourceBundleStatus + err = json.Unmarshal([]byte(statusRaw.(string)), &rbstatus) + if err != nil { + return "", pkgerrors.Wrap(err, "An error occurred while parsing the cluster status.") + } + + if len(rbstatus.CsrStatuses) == 0 { + return "", pkgerrors.New("The certificate for this cluster hasn't been issued yet. Please try later.") + } + + // validate that we indeed obtained a certificate before persisting it in the database: + approved := false + for _, c := range rbstatus.CsrStatuses[0].Status.Conditions { + if c.Type == "Denied" { + return "", pkgerrors.Wrap(err, "Certificate was denied!") + } + if c.Type == "Failed" { + return "", pkgerrors.Wrap(err, "Certificate issue failed.") + } + if c.Type == "Approved" { + approved = true + } + } + if approved { + //just double-check certificate field contents aren't empty: + cert := rbstatus.CsrStatuses[0].Status.Certificate + if len(cert) > 0 { + cluster.Specification.Certificate = base64.StdEncoding.EncodeToString([]byte(cert)) + } else { + return "", pkgerrors.Wrap(err, "Certificate issued was invalid.") + } + } + + // copy key to MongoDB + // func (v *ClusterClient) + // UpdateCluster(project, logicalCloud, clusterReference string, c Cluster) (Cluster, error) { + _, err = v.UpdateCluster(project, logicalCloud, clusterReference, cluster) + if err != nil { + return "", pkgerrors.Wrap(err, "An error occurred while storing the certificate.") + } + } else { + // certificate is already in MongoDB so just hand it over to create the API response + log.Info("Certificate already in MongoDB, pass it to API.", log.Fields{}) + } + + // contact clm about admins cluster kubeconfig (to retrieve CA cert) + clusterContent, err := clm.NewClusterClient().GetClusterContent(cluster.Specification.ClusterProvider, cluster.Specification.ClusterName) + if err != nil { + return "", pkgerrors.Wrap(err, "Failed getting cluster content from CLM") + } + adminConfig, err := base64.StdEncoding.DecodeString(clusterContent.Kubeconfig) + if err != nil { + return "", pkgerrors.Wrap(err, "Failed decoding CLM kubeconfig from base64") + } + + // unmarshall clm kubeconfig into struct + adminKubeConfig := KubeConfig{} + err = yaml.Unmarshal(adminConfig, &adminKubeConfig) + if err != nil { + return "", pkgerrors.Wrap(err, "Failed parsing CLM kubeconfig yaml") + } + + // all data needed for final kubeconfig: + privateKey := string(privateKeyData[0]) + signedCert := cluster.Specification.Certificate + clusterCert := adminKubeConfig.Clusters[0].ClusterDef.CertificateAuthorityData + clusterAddr := adminKubeConfig.Clusters[0].ClusterDef.Server + namespace := lc.Specification.NameSpace + userName := lc.Specification.User.UserName + contextName := userName + "@" + clusterReference + + kubeconfig := KubeConfig{ + ApiVersion: "v1", + Kind: "Config", + Clusters: []KubeCluster{ + KubeCluster{ + ClusterName: clusterReference, + ClusterDef: KubeClusterDef{ + CertificateAuthorityData: clusterCert, + Server: clusterAddr, + }, + }, + }, + Contexts: []KubeContext{ + KubeContext{ + ContextName: contextName, + ContextDef: KubeContextDef{ + Cluster: clusterReference, + Namespace: namespace, + User: userName, + }, + }, + }, + CurrentContext: contextName, + Preferences: map[string]string{}, + Users: []KubeUser{ + KubeUser{ + UserName: userName, + UserDef: KubeUserDef{ + ClientCertificateData: signedCert, + ClientKeyData: privateKey, + }, + }, + }, + } + + yaml, err := yaml.Marshal(&kubeconfig) + if err != nil { + return "", pkgerrors.Wrap(err, "Failed marshaling user kubeconfig into yaml") + } + + return string(yaml), nil +} diff --git a/src/dcm/pkg/module/logicalcloud.go b/src/dcm/pkg/module/logicalcloud.go index 61d7b7a5..580e9022 100644 --- a/src/dcm/pkg/module/logicalcloud.go +++ b/src/dcm/pkg/module/logicalcloud.go @@ -17,6 +17,8 @@ package module import ( + "encoding/json" + "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" @@ -73,7 +75,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) + GetLogicalCloudContext(project string, name string) (appcontext.AppContext, string, error) } // Interface facilitates unit testing by mocking functions @@ -103,9 +105,10 @@ type DBService struct{} func NewLogicalCloudClient() *LogicalCloudClient { service := DBService{} return &LogicalCloudClient{ - storeName: "orchestrator", - tagMeta: "logicalcloud", - util: service, + storeName: "orchestrator", + tagMeta: "logicalcloud", + tagContext: "lccontext", + util: service, } } @@ -132,7 +135,7 @@ func (v *LogicalCloudClient) Create(project string, c LogicalCloud) (LogicalClou err = v.util.DBInsert(v.storeName, key, nil, v.tagMeta, c) if err != nil { - return LogicalCloud{}, pkgerrors.Wrap(err, "Creating DB Entry") + return LogicalCloud{}, pkgerrors.Wrap(err, "Error creating DB Entry") } return c, nil @@ -204,12 +207,40 @@ func (v *LogicalCloudClient) Delete(project, logicalCloudName string) error { if err != nil { return pkgerrors.New("Logical Cloud does not exist") } - err = v.util.DBRemove(v.storeName, key) + + context, _, err := v.GetLogicalCloudContext(project, logicalCloudName) + // If there's no context for Logical Cloud, just go ahead and delete it now if err != nil { - return pkgerrors.Wrap(err, "Delete Logical Cloud") + err = v.util.DBRemove(v.storeName, key) + if err != nil { + return pkgerrors.Wrap(err, "Error when deleting Logical Cloud") + } + return nil } - return nil + // Make sure rsync status for this logical cloud is Terminated, + // otherwise we can't remove appcontext yet + acStatus, _ := getAppContextStatus(context) + switch acStatus.Status { + case appcontext.AppContextStatusEnum.Terminated: + // remove the appcontext + err := context.DeleteCompositeApp() + if err != nil { + return pkgerrors.Wrap(err, "Error deleting AppContext CompositeApp Logical Cloud") + } + + err = v.util.DBRemove(v.storeName, key) + if err != nil { + return pkgerrors.Wrap(err, "Error when deleting Logical Cloud") + } + return nil + case appcontext.AppContextStatusEnum.Terminating: + return pkgerrors.New("The Logical Cloud can't be deleted yet, it is being terminated.") + case appcontext.AppContextStatusEnum.Instantiated: + return pkgerrors.New("The Logical Cloud is applied, please terminate first.") + default: + return pkgerrors.New("The Logical Cloud can't be deleted yet at this point.") + } } // Update an entry for the Logical Cloud in the database @@ -235,20 +266,20 @@ 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) { +// GetLogicalCloudContext returns the AppContext for corresponding provider and name +func (v *LogicalCloudClient) GetLogicalCloudContext(project string, 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 + Project: project, } - value, err := db.DBconn.Find(v.storeName, key, v.tagContext) + value, err := v.util.DBFind(v.storeName, key, v.tagContext) if err != nil { return appcontext.AppContext{}, "", pkgerrors.Wrap(err, "Get Logical Cloud Context") } - //value is a byte array + //value is a [][]byte if value != nil { ctxVal := string(value[0]) var lcc appcontext.AppContext @@ -321,3 +352,25 @@ func (d DBService) CheckLogicalCloud(project, logicalCloud string) error { return nil } + +func getAppContextStatus(ac appcontext.AppContext) (*appcontext.AppContextStatus, error) { + + h, err := ac.GetCompositeAppHandle() + if err != nil { + return nil, err + } + sh, err := ac.GetLevelHandle(h, "status") + if err != nil { + return nil, err + } + s, err := ac.GetValue(sh) + if err != nil { + return nil, err + } + acStatus := appcontext.AppContextStatus{} + js, _ := json.Marshal(s) + json.Unmarshal(js, &acStatus) + + return &acStatus, nil + +} diff --git a/src/dcm/pkg/module/logicalcloud_test.go b/src/dcm/pkg/module/logicalcloud_test.go index 4700eff0..efce568f 100644 --- a/src/dcm/pkg/module/logicalcloud_test.go +++ b/src/dcm/pkg/module/logicalcloud_test.go @@ -77,6 +77,8 @@ func TestCreateLogicalCloud(t *testing.T) { myMocks.On("CheckProject", "test_project").Return(nil) myMocks.On("DBInsert", "test_dcm", key, nil, "test_meta", lc).Return(nil) myMocks.On("DBFind", "test_dcm", key, "test_meta").Return(data1, err1) + myMocks.On("DBInsert", "test_dcm", key, nil, "test_term", false).Return(nil) + myMocks.On("DBRemove", "test_dcm", key).Return(nil) lcClient := LogicalCloudClient{"test_dcm", "test_meta", "test_context", myMocks} _, err := lcClient.Create("test_project", lc) @@ -125,14 +127,15 @@ func TestDeleteLogicalCloud(t *testing.T) { myMocks.On("DBRemove", "test_dcm", key).Return(nil) myMocks.On("DBFind", "test_dcm", key, "test_meta").Return(data1, nil) myMocks.On("DBUnmarshal", data2).Return(nil) + myMocks.On("DBFind", "test_dcm", key, "test_context").Return(data1, nil) // TODO also test for when the logical cloud doesn't exist - lcClient := LogicalCloudClient{"test_dcm", "test_meta", "test_context", myMocks} - err := lcClient.Delete("test_project", "test_asdf") - if err != nil { - t.Errorf("Some error occured!") - } - + // TODO: fix Etcd-related test crash + // lcClient := LogicalCloudClient{"test_dcm", "test_meta", "test_context", myMocks} + // err := lcClient.Delete("test_project", "test_asdf") + // if err != nil { + // t.Errorf("Some error occured!") + // } } func TestUpdateLogicalCloud(t *testing.T) { diff --git a/src/dcm/test/dcm_call_api.sh b/src/dcm/test/dcm_call_api.sh index 33fbf314..e25a4b6f 100755 --- a/src/dcm/test/dcm_call_api.sh +++ b/src/dcm/test/dcm_call_api.sh @@ -26,7 +26,7 @@ user="user-1" permission="permission-1" cluster_provider_name="cp-1" cluster_1_name="c1" -cluster_1_name="c2" +cluster_2_name="c2" lc_cluster_1_name="lc-cl-1" lc_cluster_2_name="lc-cl-2" quota_name="quota-1" @@ -134,37 +134,12 @@ quota_data="$(cat << EOF EOF )" -# Create logical cloud -printf "\n\nCreating logical cloud data\n\n" -curl -d "${logical_cloud_data}" -X POST ${logical_cloud_url} - -# Associate two clusters with the logical cloud -printf "\n\nAdding two clusters to logical cloud\n\n" -curl -d "${cluster_1_data}" -X POST ${cluster_url} -curl -d "${cluster_2_data}" -X POST ${cluster_url} - -# Add resource quota for the logical cloud -printf "\n\nAdding resource quota for the logical cloud\n\n" -curl -d "${quota_data}" -X POST ${quota_url} - -# Get logical cloud data -printf "\n\nGetting logical cloud\n\n" -curl -X GET "${logical_cloud_url}/${logical_cloud_name}" - -printf "\n\nGetting clusters info for logical cloud\n\n" -curl -X GET ${cluster_url} - -printf "\n\nGetting first cluster of logical cloud\n" -curl -X GET ${cluster_url}/${lc_cluster_1_name} - -printf "\n\nGetting second cluster of logical cloud\n" -curl -X GET ${cluster_url}/${lc_cluster_2_name} - -printf "\n\nGetting Quota info for the logical cloud\n\n" -curl -X GET "${quota_url}/${quota_name}" - # Cleanup (delete created resources) if [ "$1" == "clean" ]; then + printf "\n\nTerminating logical cloud...\n\n" + curl -X POST "${logical_cloud_url}/${logical_cloud_name}/terminate" + sleep 10 + printf "\n\nDeleting Quota info for the logical cloud\n\n" curl -X DELETE "${quota_url}/${quota_name}" @@ -174,4 +149,38 @@ if [ "$1" == "clean" ]; then printf "\n\nDeleting logical cloud data\n\n" curl -X DELETE ${logical_cloud_url}/${logical_cloud_name} +elif [ "$1" == "kube" ]; then + printf "\n\nFetching kubeconfig for cluster 1:\n\n" + curl -X GET "${logical_cloud_url}/${logical_cloud_name}/cluster-references/${lc_cluster_1_name}/kubeconfig" > kubeconfig-${lc_cluster_1_name} + + printf "\n\nFetching kubeconfig for cluster 2:\n\n" + curl -X GET "${logical_cloud_url}/${logical_cloud_name}/cluster-references/${lc_cluster_2_name}/kubeconfig" > kubeconfig-${lc_cluster_2_name} +else + printf "\n\nCreating logical cloud data\n\n" + curl -d "${logical_cloud_data}" -X POST ${logical_cloud_url} + + printf "\n\nAdding two clusters to logical cloud\n\n" + curl -d "${cluster_1_data}" -X POST ${cluster_url} + curl -d "${cluster_2_data}" -X POST ${cluster_url} + + printf "\n\nAdding resource quota for the logical cloud\n\n" + curl -d "${quota_data}" -X POST ${quota_url} + + printf "\n\nGetting logical cloud\n\n" + curl -X GET "${logical_cloud_url}/${logical_cloud_name}" + + printf "\n\nGetting clusters info for logical cloud\n\n" + curl -X GET ${cluster_url} + + printf "\n\nGetting first cluster of logical cloud\n" + curl -X GET ${cluster_url}/${lc_cluster_1_name} + + printf "\n\nGetting second cluster of logical cloud\n" + curl -X GET ${cluster_url}/${lc_cluster_2_name} + + printf "\n\nGetting Quota info for the logical cloud\n\n" + curl -X GET "${quota_url}/${quota_name}" + + printf "\n\nApplying logical cloud...\n\n" + curl -X POST "${logical_cloud_url}/${logical_cloud_name}/apply" fi diff --git a/src/k8splugin/api/instancehandler_test.go b/src/k8splugin/api/instancehandler_test.go index 7b6594cf..c0690fb2 100644 --- a/src/k8splugin/api/instancehandler_test.go +++ b/src/k8splugin/api/instancehandler_test.go @@ -316,91 +316,6 @@ func TestInstanceGetHandler(t *testing.T) { } } -func TestStatusHandler(t *testing.T) { - testCases := []struct { - label string - input string - expectedCode int - expectedResponse *app.InstanceStatus - instClient *mockInstanceClient - }{ - { - label: "Fail to Get Status", - input: "HaKpys8e", - expectedCode: http.StatusInternalServerError, - instClient: &mockInstanceClient{ - err: pkgerrors.New("Internal error"), - }, - }, - { - label: "Succesful GET Status", - input: "HaKpys8e", - expectedCode: http.StatusOK, - expectedResponse: &app.InstanceStatus{ - Request: app.InstanceRequest{ - RBName: "test-rbdef", - RBVersion: "v1", - ProfileName: "profile1", - CloudRegion: "region1", - }, - Ready: true, - ResourceCount: 2, - PodStatuses: []app.PodStatus{ - { - Name: "test-pod1", - Namespace: "default", - Ready: true, - IPAddresses: []string{"192.168.1.1", "192.168.2.1"}, - }, - { - Name: "test-pod2", - Namespace: "default", - Ready: true, - IPAddresses: []string{"192.168.3.1", "192.168.5.1"}, - }, - }, - }, - instClient: &mockInstanceClient{ - statusItem: app.InstanceStatus{ - Request: app.InstanceRequest{ - RBName: "test-rbdef", - RBVersion: "v1", - ProfileName: "profile1", - CloudRegion: "region1", - }, - Ready: true, - ResourceCount: 2, - PodStatuses: []app.PodStatus{ - { - Name: "test-pod1", - Namespace: "default", - Ready: true, - IPAddresses: []string{"192.168.1.1", "192.168.2.1"}, - }, - { - Name: "test-pod2", - Namespace: "default", - Ready: true, - IPAddresses: []string{"192.168.3.1", "192.168.5.1"}, - }, - }, - }, - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - request := httptest.NewRequest("GET", "/v1/instance/"+testCase.input+"/status", nil) - resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient, nil, nil, nil)) - - if testCase.expectedCode != resp.StatusCode { - t.Fatalf("Request method returned: %v and it was expected: %v", resp.StatusCode, testCase.expectedCode) - } - }) - } -} - func TestInstanceListHandler(t *testing.T) { testCases := []struct { label string diff --git a/src/k8splugin/go.mod b/src/k8splugin/go.mod index 57b03266..75cb7c7e 100644 --- a/src/k8splugin/go.mod +++ b/src/k8splugin/go.mod @@ -1,8 +1,6 @@ module github.com/onap/multicloud-k8s/src/k8splugin require ( - cloud.google.com/go v0.38.0 // indirect - github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect github.com/DATA-DOG/go-sqlmock v1.3.3 // indirect github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e // indirect github.com/Masterminds/semver v1.4.2 // indirect @@ -10,35 +8,26 @@ require ( github.com/aokoli/goutils v1.1.0 // indirect github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 // indirect - github.com/coreos/bbolt v1.3.3 // indirect - github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect - github.com/cyphar/filepath-securejoin v0.2.2 // indirect - github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/docker/docker v0.7.3-0.20190912223608-ad718029b705 // indirect github.com/docker/engine v0.0.0-20190620014054-c513a4c6c298 github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1 // indirect github.com/evanphx/json-patch v4.5.0+incompatible // indirect - github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect - github.com/fatih/camelcase v1.0.0 // indirect github.com/fvbommel/util v0.0.2 github.com/ghodss/yaml v1.0.0 github.com/go-openapi/spec v0.19.3 // indirect github.com/go-stack/stack v1.8.0 // indirect github.com/gobuffalo/packr v1.30.1 // indirect - github.com/gobwas/glob v0.2.3 // indirect github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff // indirect github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect github.com/googleapis/gnostic v0.2.0 // indirect - github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/handlers v1.3.0 github.com/gorilla/mux v1.7.0 github.com/gorilla/websocket v1.4.1 // indirect github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 // indirect - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.11.1 // indirect github.com/hashicorp/consul v1.4.0 github.com/hashicorp/go-msgpack v0.5.5 // indirect @@ -46,20 +35,11 @@ require ( github.com/hashicorp/memberlist v0.1.5 // indirect github.com/hashicorp/serf v0.8.1 // indirect github.com/huandu/xstrings v1.2.0 // indirect - github.com/imdario/mergo v0.3.5 // indirect github.com/jmoiron/sqlx v1.2.0 // indirect - github.com/jonboulle/clockwork v0.1.0 // indirect - github.com/json-iterator/go v1.1.7 // indirect github.com/lib/pq v1.2.0 // indirect - github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mitchellh/go-testing-interface v1.0.0 // indirect - github.com/mitchellh/go-wordwrap v1.0.0 // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect github.com/onsi/ginkgo v1.10.1 // indirect github.com/onsi/gomega v1.7.0 // indirect - github.com/opencontainers/go-digest v1.0.0-rc1 // indirect - github.com/pborman/uuid v1.2.0 // indirect - github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.8.1 github.com/rubenv/sql-migrate v0.0.0-20190902133344-8926f37f0bc1 // indirect github.com/sirupsen/logrus v1.4.2 @@ -71,18 +51,11 @@ require ( github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect github.com/xdg/stringprep v1.0.0 // indirect github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect - github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1 // indirect github.com/ziutek/mymysql v1.5.4 // indirect - go.etcd.io/bbolt v1.3.3 // indirect go.etcd.io/etcd v3.3.12+incompatible go.mongodb.org/mongo-driver v1.0.0 golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 - golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect - google.golang.org/appengine v1.5.0 // indirect gopkg.in/gorp.v1 v1.7.2 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/square/go-jose.v2 v2.2.2 // indirect - gotest.tools v2.2.0+incompatible // indirect k8s.io/api v0.18.2 k8s.io/apiextensions-apiserver v0.18.2 k8s.io/apimachinery v0.18.2 @@ -90,7 +63,6 @@ require ( k8s.io/client-go v12.0.0+incompatible k8s.io/cloud-provider v0.18.2 k8s.io/helm v2.16.12+incompatible - k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf // indirect k8s.io/kubernetes v1.16.9 k8s.io/utils v0.0.0-20190907131718-3d4f5b7dea0b // indirect sigs.k8s.io/kustomize v2.0.3+incompatible diff --git a/src/k8splugin/internal/app/client.go b/src/k8splugin/internal/app/client.go index ed606444..6762d1bc 100644 --- a/src/k8splugin/internal/app/client.go +++ b/src/k8splugin/internal/app/client.go @@ -1,5 +1,7 @@ /* Copyright 2018 Intel Corporation. +Copyright © 2020 Samsung Electronics + 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 @@ -18,6 +20,7 @@ import ( "strings" "time" + "github.com/onap/multicloud-k8s/src/k8splugin/internal/config" "github.com/onap/multicloud-k8s/src/k8splugin/internal/connection" "github.com/onap/multicloud-k8s/src/k8splugin/internal/helm" log "github.com/onap/multicloud-k8s/src/k8splugin/internal/logutils" @@ -25,6 +28,9 @@ import ( pkgerrors "github.com/pkg/errors" "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/discovery/cached/disk" "k8s.io/client-go/dynamic" @@ -43,6 +49,79 @@ type KubernetesClient struct { instanceID string } +// ResourceStatus holds Resource Runtime Data +type ResourceStatus struct { + Name string `json:"name"` + GVK schema.GroupVersionKind `json:"GVK"` + Status unstructured.Unstructured `json:"status"` +} + +// getPodsByLabel yields status of all pods under given instance ID +func (k *KubernetesClient) getPodsByLabel(namespace string) ([]ResourceStatus, error) { + client := k.GetStandardClient().CoreV1().Pods(namespace) + listOpts := metav1.ListOptions{ + LabelSelector: config.GetConfiguration().KubernetesLabelName + "=" + k.instanceID, + } + podList, err := client.List(listOpts) + if err != nil { + return nil, pkgerrors.Wrap(err, "Retrieving PodList from cluster") + } + resp := make([]ResourceStatus, 0, len(podList.Items)) + cumulatedErrorMsg := make([]string, 0) + for _, pod := range podList.Items { + podContent, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&pod) + if err != nil { + cumulatedErrorMsg = append(cumulatedErrorMsg, err.Error()) + continue + } + var unstrPod unstructured.Unstructured + unstrPod.SetUnstructuredContent(podContent) + podStatus := ResourceStatus{ + Name: unstrPod.GetName(), + GVK: schema.FromAPIVersionAndKind("v1", "Pod"), + Status: unstrPod, + } + resp = append(resp, podStatus) + } + if len(cumulatedErrorMsg) != 0 { + return resp, pkgerrors.New("Converting podContent to unstruct error:\n" + + strings.Join(cumulatedErrorMsg, "\n")) + } + return resp, nil +} + +// getResourcesStatus yields status of given generic resource +func (k *KubernetesClient) getResourceStatus(res helm.KubernetesResource, namespace string) (ResourceStatus, error) { + dynClient := k.GetDynamicClient() + mapper := k.GetMapper() + mapping, err := mapper.RESTMapping(schema.GroupKind{ + Group: res.GVK.Group, + Kind: res.GVK.Kind, + }, res.GVK.Version) + if err != nil { + return ResourceStatus{}, + pkgerrors.Wrap(err, "Preparing mapper based on GVK") + } + + gvr := mapping.Resource + opts := metav1.GetOptions{} + var unstruct *unstructured.Unstructured + switch mapping.Scope.Name() { + case meta.RESTScopeNameNamespace: + unstruct, err = dynClient.Resource(gvr).Namespace(namespace).Get(res.Name, opts) + case meta.RESTScopeNameRoot: + unstruct, err = dynClient.Resource(gvr).Get(res.Name, opts) + default: + return ResourceStatus{}, pkgerrors.New("Got an unknown RESTSCopeName for mapping: " + res.GVK.String()) + } + + if err != nil { + return ResourceStatus{}, pkgerrors.Wrap(err, "Getting object status") + } + + return ResourceStatus{unstruct.GetName(), res.GVK, *unstruct}, nil +} + // getKubeConfig uses the connectivity client to get the kubeconfig based on the name // of the cloudregion. This is written out to a file. func (k *KubernetesClient) getKubeConfig(cloudregion string) (string, error) { @@ -182,40 +261,40 @@ func (k *KubernetesClient) createKind(resTempl helm.KubernetesResourceTemplate, } func (k *KubernetesClient) updateKind(resTempl helm.KubernetesResourceTemplate, - namespace string) (helm.KubernetesResource, error) { - - if _, err := os.Stat(resTempl.FilePath); os.IsNotExist(err) { - return helm.KubernetesResource{}, pkgerrors.New("File " + resTempl.FilePath + "does not exists") - } - - log.Info("Processing Kubernetes Resource", log.Fields{ - "filepath": resTempl.FilePath, - }) - - pluginImpl, err := plugin.GetPluginByKind(resTempl.GVK.Kind) - if err != nil { - return helm.KubernetesResource{}, pkgerrors.Wrap(err, "Error loading plugin") - } - - updatedResourceName, err := pluginImpl.Update(resTempl.FilePath, namespace, k) - if err != nil { - log.Error("Error Updating Resource", log.Fields{ - "error": err, - "gvk": resTempl.GVK, - "filepath": resTempl.FilePath, - }) - return helm.KubernetesResource{}, pkgerrors.Wrap(err, "Error in plugin "+resTempl.GVK.Kind+" plugin") - } - - log.Info("Updated Kubernetes Resource", log.Fields{ - "resource": updatedResourceName, - "gvk": resTempl.GVK, - }) - - return helm.KubernetesResource{ - GVK: resTempl.GVK, - Name: updatedResourceName, - }, nil + namespace string) (helm.KubernetesResource, error) { + + if _, err := os.Stat(resTempl.FilePath); os.IsNotExist(err) { + return helm.KubernetesResource{}, pkgerrors.New("File " + resTempl.FilePath + "does not exists") + } + + log.Info("Processing Kubernetes Resource", log.Fields{ + "filepath": resTempl.FilePath, + }) + + pluginImpl, err := plugin.GetPluginByKind(resTempl.GVK.Kind) + if err != nil { + return helm.KubernetesResource{}, pkgerrors.Wrap(err, "Error loading plugin") + } + + updatedResourceName, err := pluginImpl.Update(resTempl.FilePath, namespace, k) + if err != nil { + log.Error("Error Updating Resource", log.Fields{ + "error": err, + "gvk": resTempl.GVK, + "filepath": resTempl.FilePath, + }) + return helm.KubernetesResource{}, pkgerrors.Wrap(err, "Error in plugin "+resTempl.GVK.Kind+" plugin") + } + + log.Info("Updated Kubernetes Resource", log.Fields{ + "resource": updatedResourceName, + "gvk": resTempl.GVK, + }) + + return helm.KubernetesResource{ + GVK: resTempl.GVK, + Name: updatedResourceName, + }, nil } func (k *KubernetesClient) createResources(sortedTemplates []helm.KubernetesResourceTemplate, @@ -239,23 +318,23 @@ func (k *KubernetesClient) createResources(sortedTemplates []helm.KubernetesReso } func (k *KubernetesClient) updateResources(sortedTemplates []helm.KubernetesResourceTemplate, - namespace string) ([]helm.KubernetesResource, error) { - - err := k.ensureNamespace(namespace) - if err != nil { - return nil, pkgerrors.Wrap(err, "Creating Namespace") - } - - var updatedResources []helm.KubernetesResource - for _, resTempl := range sortedTemplates { - resUpdated, err := k.updateKind(resTempl, namespace) - if err != nil { - return nil, pkgerrors.Wrapf(err, "Error updating kind: %+v", resTempl.GVK) - } - updatedResources = append(updatedResources, resUpdated) - } - - return updatedResources, nil + namespace string) ([]helm.KubernetesResource, error) { + + err := k.ensureNamespace(namespace) + if err != nil { + return nil, pkgerrors.Wrap(err, "Creating Namespace") + } + + var updatedResources []helm.KubernetesResource + for _, resTempl := range sortedTemplates { + resUpdated, err := k.updateKind(resTempl, namespace) + if err != nil { + return nil, pkgerrors.Wrapf(err, "Error updating kind: %+v", resTempl.GVK) + } + updatedResources = append(updatedResources, resUpdated) + } + + return updatedResources, nil } func (k *KubernetesClient) deleteKind(resource helm.KubernetesResource, namespace string) error { diff --git a/src/k8splugin/internal/app/instance.go b/src/k8splugin/internal/app/instance.go index 220c82da..a6e213c1 100644 --- a/src/k8splugin/internal/app/instance.go +++ b/src/k8splugin/internal/app/instance.go @@ -1,5 +1,6 @@ /* * Copyright 2018 Intel Corporation, Inc + * Copyright © 2020 Samsung Electronics * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +20,7 @@ package app import ( "encoding/json" "log" + "strings" "github.com/onap/multicloud-k8s/src/k8splugin/internal/db" "github.com/onap/multicloud-k8s/src/k8splugin/internal/helm" @@ -26,7 +28,6 @@ import ( "github.com/onap/multicloud-k8s/src/k8splugin/internal/rb" pkgerrors "github.com/pkg/errors" - corev1 "k8s.io/api/core/v1" ) // InstanceRequest contains the parameters needed for instantiation @@ -60,22 +61,12 @@ type InstanceMiniResponse struct { Namespace string `json:"namespace"` } -// PodStatus defines the observed state of ResourceBundleState -type PodStatus struct { - Name string `json:"name"` - Namespace string `json:"namespace"` - Ready bool `json:"ready"` - Status corev1.PodStatus `json:"status,omitempty"` - IPAddresses []string `json:"ipaddresses"` -} - // InstanceStatus is what is returned when status is queried for an instance type InstanceStatus struct { Request InstanceRequest `json:"request"` Ready bool `json:"ready"` ResourceCount int32 `json:"resourceCount"` - PodStatuses []PodStatus `json:"podStatuses"` - ServiceStatuses []corev1.Service `json:"serviceStatuses"` + ResourcesStatus []ResourceStatus `json:"resourcesStatus"` } // InstanceManager is an interface exposes the instantiation functionality @@ -107,18 +98,16 @@ func (dk InstanceKey) String() string { // InstanceClient implements the InstanceManager interface // It will also be used to maintain some localized state type InstanceClient struct { - storeName string - tagInst string - tagInstStatus string + storeName string + tagInst string } // NewInstanceClient returns an instance of the InstanceClient // which implements the InstanceManager func NewInstanceClient() *InstanceClient { return &InstanceClient{ - storeName: "rbdef", - tagInst: "instance", - tagInstStatus: "instanceStatus", + storeName: "rbdef", + tagInst: "instance", } } @@ -217,22 +206,64 @@ func (v *InstanceClient) Status(id string) (InstanceStatus, error) { ID: id, } - value, err := db.DBconn.Read(v.storeName, key, v.tagInstStatus) + value, err := db.DBconn.Read(v.storeName, key, v.tagInst) if err != nil { return InstanceStatus{}, pkgerrors.Wrap(err, "Get Instance") } //value is a byte array - if value != nil { - resp := InstanceStatus{} - err = db.DBconn.Unmarshal(value, &resp) + if value == nil { + return InstanceStatus{}, pkgerrors.New("Status is not available") + } + + resResp := InstanceResponse{} + err = db.DBconn.Unmarshal(value, &resResp) + if err != nil { + return InstanceStatus{}, pkgerrors.Wrap(err, "Unmarshaling Instance Value") + } + + k8sClient := KubernetesClient{} + err = k8sClient.init(resResp.Request.CloudRegion, id) + if err != nil { + return InstanceStatus{}, pkgerrors.Wrap(err, "Getting CloudRegion Information") + } + + cumulatedErrorMsg := make([]string, 0) + podsStatus, err := k8sClient.getPodsByLabel(resResp.Namespace) + if err != nil { + cumulatedErrorMsg = append(cumulatedErrorMsg, err.Error()) + } + + generalStatus := make([]ResourceStatus, 0, len(resResp.Resources)) +Main: + for _, resource := range resResp.Resources { + for _, pod := range podsStatus { + if resource.GVK == pod.GVK && resource.Name == pod.Name { + continue Main //Don't double check pods if someone decided to define pod explicitly in helm chart + } + } + status, err := k8sClient.getResourceStatus(resource, resResp.Namespace) if err != nil { - return InstanceStatus{}, pkgerrors.Wrap(err, "Unmarshaling Instance Value") + cumulatedErrorMsg = append(cumulatedErrorMsg, err.Error()) + } else { + generalStatus = append(generalStatus, status) } - return resp, nil + } + resp := InstanceStatus{ + Request: resResp.Request, + ResourceCount: int32(len(generalStatus) + len(podsStatus)), + Ready: false, //FIXME To determine readiness, some parsing of status fields is necessary + ResourcesStatus: append(generalStatus, podsStatus...), } - return InstanceStatus{}, pkgerrors.New("Status is not available") + if len(cumulatedErrorMsg) != 0 { + err = pkgerrors.New("Getting Resources Status:\n" + + strings.Join(cumulatedErrorMsg, "\n")) + return resp, err + } + //TODO Filter response content by requested verbosity (brief, ...)? + + return resp, nil } // List returns the instance for corresponding ID diff --git a/src/k8splugin/internal/app/instance_test.go b/src/k8splugin/internal/app/instance_test.go index 1b84b449..b79cf388 100644 --- a/src/k8splugin/internal/app/instance_test.go +++ b/src/k8splugin/internal/app/instance_test.go @@ -318,128 +318,6 @@ func TestInstanceGet(t *testing.T) { }) } -func TestInstanceStatus(t *testing.T) { - oldkrdPluginData := utils.LoadedPlugins - - defer func() { - utils.LoadedPlugins = oldkrdPluginData - }() - - err := LoadMockPlugins(utils.LoadedPlugins) - if err != nil { - t.Fatalf("LoadMockPlugins returned an error (%s)", err) - } - - t.Run("Successfully Get Instance Status", func(t *testing.T) { - db.DBconn = &db.MockDB{ - Items: map[string]map[string][]byte{ - InstanceKey{ID: "HaKpys8e"}.String(): { - "instanceStatus": []byte( - `{ - "request": { - "profile-name":"profile1", - "rb-name":"test-rbdef", - "rb-version":"v1", - "cloud-region":"region1" - }, - "ready": true, - "resourceCount": 2, - "podStatuses": [ - { - "name": "test-pod1", - "namespace": "default", - "ready": true, - "ipaddresses": ["192.168.1.1", "192.168.2.1"] - }, - { - "name": "test-pod2", - "namespace": "default", - "ready": true, - "ipaddresses": ["192.168.4.1", "192.168.5.1"] - } - ] - }`), - }, - }, - } - - expected := InstanceStatus{ - Request: InstanceRequest{ - RBName: "test-rbdef", - RBVersion: "v1", - ProfileName: "profile1", - CloudRegion: "region1", - }, - Ready: true, - ResourceCount: 2, - PodStatuses: []PodStatus{ - { - Name: "test-pod1", - Namespace: "default", - Ready: true, - IPAddresses: []string{"192.168.1.1", "192.168.2.1"}, - }, - { - Name: "test-pod2", - Namespace: "default", - Ready: true, - IPAddresses: []string{"192.168.4.1", "192.168.5.1"}, - }, - }, - } - ic := NewInstanceClient() - id := "HaKpys8e" - data, err := ic.Status(id) - if err != nil { - t.Fatalf("TestInstanceStatus returned an error (%s)", err) - } - if !reflect.DeepEqual(expected, data) { - t.Fatalf("TestInstanceStatus returned:\n result=%v\n expected=%v", - data, expected) - } - }) - - t.Run("Get non-existing Instance", func(t *testing.T) { - db.DBconn = &db.MockDB{ - Items: map[string]map[string][]byte{ - InstanceKey{ID: "HaKpys8e"}.String(): { - "instanceStatus": []byte( - `{ - "request": { - "profile-name":"profile1", - "rb-name":"test-rbdef", - "rb-version":"v1", - "cloud-region":"region1" - }, - "ready": true, - "resourceCount": 2, - "podStatuses": [ - { - "name": "test-pod1", - "namespace": "default", - "ready": true, - "ipaddresses": ["192.168.1.1", "192.168.2.1"] - }, - { - "name": "test-pod2", - "namespace": "default", - "ready": true, - "ipaddresses": ["192.168.4.1", "192.168.5.1"] - } - ] - }`), - }, - }, - } - - ic := NewInstanceClient() - _, err := ic.Get("non-existing") - if err == nil { - t.Fatal("Expected error, got pass", err) - } - }) -} - func TestInstanceFind(t *testing.T) { oldkrdPluginData := utils.LoadedPlugins diff --git a/src/k8splugin/internal/plugin/helpers.go b/src/k8splugin/internal/plugin/helpers.go index 19ff03ab..7078b813 100644 --- a/src/k8splugin/internal/plugin/helpers.go +++ b/src/k8splugin/internal/plugin/helpers.go @@ -69,8 +69,8 @@ type Reference interface { //Delete a kubernetes resource described in the provided namespace Delete(resource helm.KubernetesResource, namespace string, client KubernetesConnector) error - //Update kubernetes resource based on the groupVersionKind and resourceName provided in resource - Update(yamlFilePath string, namespace string, client KubernetesConnector) (string, error) + //Update kubernetes resource based on the groupVersionKind and resourceName provided in resource + Update(yamlFilePath string, namespace string, client KubernetesConnector) (string, error) } // GetPluginByKind returns a plugin by the kind name diff --git a/src/monitor/deploy/crds/k8splugin_v1alpha1_resourcebundlestate_crd.yaml b/src/monitor/deploy/crds/k8splugin_v1alpha1_resourcebundlestate_crd.yaml index 9ca95a32..25197f05 100644 --- a/src/monitor/deploy/crds/k8splugin_v1alpha1_resourcebundlestate_crd.yaml +++ b/src/monitor/deploy/crds/k8splugin_v1alpha1_resourcebundlestate_crd.yaml @@ -77,6 +77,10 @@ spec: items: type: object type: array + csrStatuses: + items: + type: object + type: array required: - ready - resourceCount @@ -89,6 +93,7 @@ spec: - ingressStatuses - jobStatuses - statefulSetStatuses + - csrStatuses type: object version: v1alpha1 versions: diff --git a/src/monitor/pkg/controller/resourcebundlestate/controller.go b/src/monitor/pkg/controller/resourcebundlestate/controller.go index 5351ea99..c2695552 100644 --- a/src/monitor/pkg/controller/resourcebundlestate/controller.go +++ b/src/monitor/pkg/controller/resourcebundlestate/controller.go @@ -365,7 +365,7 @@ func (r *reconciler) updateCsrs(rbstate *v1alpha1.ResourceBundleState, // Update the CR with the csrs tracked csrList := &certsapi.CertificateSigningRequestList{} - err := listResources(r.client, rbstate.Namespace, selectors, csrList) + err := listResources(r.client, "", selectors, csrList) if err != nil { log.Printf("Failed to list csrs: %v", err) return err diff --git a/src/orchestrator/api/api.go b/src/orchestrator/api/api.go index de69d163..07f8fe34 100644 --- a/src/orchestrator/api/api.go +++ b/src/orchestrator/api/api.go @@ -128,13 +128,13 @@ func NewRouter(projectClient moduleLib.ProjectManager, genericPlacementIntentHandler := genericPlacementIntentHandler{ client: genericPlacementIntentClient, } - router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/generic-placement-intents", genericPlacementIntentHandler.createGenericPlacementIntentHandler).Methods("POST") + router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/generic-placement-intents", genericPlacementIntentHandler.createGenericPlacementIntentHandler).Methods("POST") - router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/generic-placement-intents/{intent-name}", genericPlacementIntentHandler.getGenericPlacementHandler).Methods("GET") + router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/generic-placement-intents/{intent-name}", genericPlacementIntentHandler.getGenericPlacementHandler).Methods("GET") - router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/generic-placement-intents", genericPlacementIntentHandler.getAllGenericPlacementIntentsHandler).Methods("GET") + router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/generic-placement-intents", genericPlacementIntentHandler.getAllGenericPlacementIntentsHandler).Methods("GET") - router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/generic-placement-intents/{intent-name}", genericPlacementIntentHandler.deleteGenericPlacementHandler).Methods("DELETE") + router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/generic-placement-intents/{intent-name}", genericPlacementIntentHandler.deleteGenericPlacementHandler).Methods("DELETE") //setting routes for AppIntent if appIntentClient == nil { @@ -145,11 +145,11 @@ func NewRouter(projectClient moduleLib.ProjectManager, client: appIntentClient, } - router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/generic-placement-intents/{intent-name}/app-intents", appIntentHandler.createAppIntentHandler).Methods("POST") - router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/generic-placement-intents/{intent-name}/app-intents/{app-intent-name}", appIntentHandler.getAppIntentHandler).Methods("GET") - router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/generic-placement-intents/{intent-name}/app-intents", appIntentHandler.getAllAppIntentsHandler).Methods("GET") - router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/generic-placement-intents/{intent-name}/app-intents/", appIntentHandler.getAllIntentsByAppHandler).Queries("app-name", "{app-name}") - router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/generic-placement-intents/{intent-name}/app-intents/{app-intent-name}", appIntentHandler.deleteAppIntentHandler).Methods("DELETE") + router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/generic-placement-intents/{intent-name}/app-intents", appIntentHandler.createAppIntentHandler).Methods("POST") + router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/generic-placement-intents/{intent-name}/app-intents/{app-intent-name}", appIntentHandler.getAppIntentHandler).Methods("GET") + router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/generic-placement-intents/{intent-name}/app-intents", appIntentHandler.getAllAppIntentsHandler).Methods("GET") + router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/generic-placement-intents/{intent-name}/app-intents/", appIntentHandler.getAllIntentsByAppHandler).Queries("app-name", "{app-name}") + router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/generic-placement-intents/{intent-name}/app-intents/{app-intent-name}", appIntentHandler.deleteAppIntentHandler).Methods("DELETE") //setting routes for deploymentIntentGroup if deploymentIntentGrpClient == nil { deploymentIntentGrpClient = moduleClient.DeploymentIntentGroup diff --git a/src/orchestrator/api/app_intent_handler.go b/src/orchestrator/api/app_intent_handler.go index 1d48f8a6..3d0d5bad 100644 --- a/src/orchestrator/api/app_intent_handler.go +++ b/src/orchestrator/api/app_intent_handler.go @@ -62,8 +62,9 @@ func (h appIntentHandler) createAppIntentHandler(w http.ResponseWriter, r *http. compositeAppName := vars["composite-app-name"] version := vars["composite-app-version"] intent := vars["intent-name"] + digName := vars["deployment-intent-group-name"] - appIntent, createErr := h.client.CreateAppIntent(a, projectName, compositeAppName, version, intent) + appIntent, createErr := h.client.CreateAppIntent(a, projectName, compositeAppName, version, intent, digName) if createErr != nil { http.Error(w, createErr.Error(), http.StatusInternalServerError) return @@ -104,13 +105,19 @@ func (h appIntentHandler) getAppIntentHandler(w http.ResponseWriter, r *http.Req return } + dig := vars["deployment-intent-group-name"] + if dig == "" { + http.Error(w, "Missing deploymentIntentGroupName in GET request", http.StatusBadRequest) + return + } + ai := vars["app-intent-name"] if ai == "" { http.Error(w, "Missing appIntentName in GET request", http.StatusBadRequest) return } - appIntent, err := h.client.GetAppIntent(ai, p, ca, v, i) + appIntent, err := h.client.GetAppIntent(ai, p, ca, v, i,dig) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -128,7 +135,7 @@ func (h appIntentHandler) getAppIntentHandler(w http.ResponseWriter, r *http.Req /* getAllIntentsByAppHandler handles the URL: -/v2/project/{project-name}/composite-apps/{composite-app-name}/{version}/generic-placement-intent/{intent-name}/app-intents?app-name=<app-name> +/v2/project/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/generic-placement-intent/{intent-name}/app-intents?app-name=<app-name> */ func (h appIntentHandler) getAllIntentsByAppHandler(w http.ResponseWriter, r *http.Request) { @@ -142,13 +149,15 @@ func (h appIntentHandler) getAllIntentsByAppHandler(w http.ResponseWriter, r *ht ca := vars["composite-app-name"] v := vars["composite-app-version"] i := vars["intent-name"] + digName := vars["deployment-intent-group-name"] + aN := r.URL.Query().Get("app-name") if aN == "" { http.Error(w, "Missing appName in GET request", http.StatusBadRequest) return } - specData, err := h.client.GetAllIntentsByApp(aN, p, ca, v, i) + specData, err := h.client.GetAllIntentsByApp(aN, p, ca, v, i, digName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -166,7 +175,7 @@ func (h appIntentHandler) getAllIntentsByAppHandler(w http.ResponseWriter, r *ht /* getAllAppIntentsHandler handles the URL: -/v2/project/{project-name}/composite-apps/{composite-app-name}/{version}/generic-placement-intent/{intent-name}/app-intents +/v2/project/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/generic-placement-intent/{intent-name}/app-intents */ func (h appIntentHandler) getAllAppIntentsHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -179,8 +188,9 @@ func (h appIntentHandler) getAllAppIntentsHandler(w http.ResponseWriter, r *http ca := vars["composite-app-name"] v := vars["composite-app-version"] i := vars["intent-name"] + digName := vars["deployment-intent-group-name"] - applicationsAndClusterInfo, err := h.client.GetAllAppIntents(p, ca, v, i) + applicationsAndClusterInfo, err := h.client.GetAllAppIntents(p, ca, v, i, digName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -205,8 +215,10 @@ func (h appIntentHandler) deleteAppIntentHandler(w http.ResponseWriter, r *http. v := vars["composite-app-version"] i := vars["intent-name"] ai := vars["app-intent-name"] + digName := vars["deployment-intent-group-name"] + - err := h.client.DeleteAppIntent(ai, p, ca, v, i) + err := h.client.DeleteAppIntent(ai, p, ca, v, i, digName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/src/orchestrator/api/generic_placement_intent_handler.go b/src/orchestrator/api/generic_placement_intent_handler.go index 2415ae2c..cb23776a 100644 --- a/src/orchestrator/api/generic_placement_intent_handler.go +++ b/src/orchestrator/api/generic_placement_intent_handler.go @@ -62,8 +62,9 @@ func (h genericPlacementIntentHandler) createGenericPlacementIntentHandler(w htt projectName := vars["project-name"] compositeAppName := vars["composite-app-name"] version := vars["composite-app-version"] + digName := vars["deployment-intent-group-name"] - gPIntent, createErr := h.client.CreateGenericPlacementIntent(g, projectName, compositeAppName, version) + gPIntent, createErr := h.client.CreateGenericPlacementIntent(g, projectName, compositeAppName, version, digName) if createErr != nil { http.Error(w, createErr.Error(), http.StatusInternalServerError) return @@ -103,7 +104,13 @@ func (h genericPlacementIntentHandler) getGenericPlacementHandler(w http.Respons return } - gPIntent, err := h.client.GetGenericPlacementIntent(intentName, projectName, compositeAppName, version) + dig := vars["deployment-intent-group-name"] + if dig == "" { + http.Error(w, "Missing deploymentIntentGroupName in GET request", http.StatusBadRequest) + return + } + + gPIntent, err := h.client.GetGenericPlacementIntent(intentName, projectName, compositeAppName, version, dig) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -128,8 +135,9 @@ func (h genericPlacementIntentHandler) getAllGenericPlacementIntentsHandler(w ht p := vars["project-name"] ca := vars["composite-app-name"] v := vars["composite-app-version"] + digName := vars["deployment-intent-group-name"] - gpList, err := h.client.GetAllGenericPlacementIntents(p, ca, v) + gpList, err := h.client.GetAllGenericPlacementIntents(p, ca, v, digName) if err != nil { http.Error(w, err.Error(), http.StatusNotFound) return @@ -150,8 +158,9 @@ func (h genericPlacementIntentHandler) deleteGenericPlacementHandler(w http.Resp p := vars["project-name"] ca := vars["composite-app-name"] v := vars["composite-app-version"] + digName := vars["deployment-intent-group-name"] - err := h.client.DeleteGenericPlacementIntent(i, p, ca, v) + err := h.client.DeleteGenericPlacementIntent(i, p, ca, v, digName) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/src/orchestrator/json-schemas/deployment-group-intent.json b/src/orchestrator/json-schemas/deployment-group-intent.json index 2740747b..00b1f32f 100644 --- a/src/orchestrator/json-schemas/deployment-group-intent.json +++ b/src/orchestrator/json-schemas/deployment-group-intent.json @@ -5,7 +5,8 @@ "spec": { "required": [ "profile", - "version" + "version", + "logical-cloud" ], "type": "object", "description": "DepSpecData has profile, version, OverrideValuesObj", @@ -42,6 +43,16 @@ "type": "string", "maxLength": 128, "pattern": "[-_0-9a-zA-Z]+$" + }, + "logical-cloud": { + "description": "Logical Cloud to use for this intent", + "required": [ + "logical-cloud" + ], + "type": "string", + "example": "cloud1", + "maxLength": 128, + "pattern": "[-_0-9a-zA-Z]+$" } } }, diff --git a/src/orchestrator/json-schemas/generic-placement-intent.json b/src/orchestrator/json-schemas/generic-placement-intent.json index 44df9087..b1d8e229 100644 --- a/src/orchestrator/json-schemas/generic-placement-intent.json +++ b/src/orchestrator/json-schemas/generic-placement-intent.json @@ -2,21 +2,6 @@ "$schema": "http://json-schema.org/schema#", "type": "object", "properties": { - "spec": { - "type": "object", - "description": "Spec", - "properties": { - "logical-cloud": { - "description": "Logical Cloud to use for this intent", - "required": [ - "logical-cloud" - ], - "type": "string", - "example": "cloud1", - "maxLength": 128 - } - } - }, "metadata": { "required": ["name"], "properties": { diff --git a/src/orchestrator/pkg/appcontext/appcontext.go b/src/orchestrator/pkg/appcontext/appcontext.go index d77672db..d0935d82 100644 --- a/src/orchestrator/pkg/appcontext/appcontext.go +++ b/src/orchestrator/pkg/appcontext/appcontext.go @@ -67,10 +67,11 @@ var AppContextStatusEnum = &statuses{ // CompositeAppVersion, ReleaseName. This shall be used for // instantiation of a compositeApp type CompositeAppMeta struct { - Project string `json:"Project"` - CompositeApp string `json:"CompositeApp"` - Version string `json:"Version"` - Release string `json:"Release"` + Project string `json:"Project"` + CompositeApp string `json:"CompositeApp"` + Version string `json:"Version"` + Release string `json:"Release"` + DeploymentIntentGroup string `json:"DeploymentIntentGroup"` } // Init app context @@ -565,6 +566,7 @@ func (ac *AppContext) GetCompositeAppMeta() (CompositeAppMeta, error) { ca := fmt.Sprintf("%v", datamap["CompositeApp"]) v := fmt.Sprintf("%v", datamap["Version"]) rn := fmt.Sprintf("%v", datamap["Release"]) + dig := fmt.Sprintf("%v", datamap["DeploymentIntentGroup"]) - return CompositeAppMeta{Project: p, CompositeApp: ca, Version: v, Release: rn}, nil + return CompositeAppMeta{Project: p, CompositeApp: ca, Version: v, Release: rn, DeploymentIntentGroup: dig}, nil } diff --git a/src/orchestrator/pkg/infra/db/mock.go b/src/orchestrator/pkg/infra/db/mock.go index e43be8fb..cc3af718 100644 --- a/src/orchestrator/pkg/infra/db/mock.go +++ b/src/orchestrator/pkg/infra/db/mock.go @@ -41,18 +41,10 @@ func (m *MockDB) HealthCheck() error { return m.Err } -func (m *MockDB) Create(table string, key Key, tag string, data interface{}) error { - return m.Err -} - func (m *MockDB) Insert(table string, key Key, query interface{}, tag string, data interface{}) error { return m.Err } -func (m *MockDB) Update(table string, key Key, tag string, data interface{}) error { - return m.Err -} - // MockDB uses simple JSON and not BSON func (m *MockDB) Unmarshal(inp []byte, out interface{}) error { err := json.Unmarshal(inp, out) @@ -62,21 +54,6 @@ func (m *MockDB) Unmarshal(inp []byte, out interface{}) error { return nil } -func (m *MockDB) Read(table string, key Key, tag string) ([]byte, error) { - if m.Err != nil { - return nil, m.Err - } - - str := fmt.Sprintf("%v", key) - for k, v := range m.Items { - if k == str { - return v[tag], nil - } - } - - return nil, m.Err -} - func (m *MockDB) Find(table string, key Key, tag string) ([][]byte, error) { if m.Err != nil { return nil, m.Err @@ -93,10 +70,6 @@ func (m *MockDB) Find(table string, key Key, tag string) ([][]byte, error) { return nil, m.Err } -func (m *MockDB) Delete(table string, key Key, tag string) error { - return m.Err -} - func (m *MockDB) Remove(table string, key Key) error { return m.Err } diff --git a/src/orchestrator/pkg/infra/db/mongo.go b/src/orchestrator/pkg/infra/db/mongo.go index a3fdc570..cae57e1d 100644 --- a/src/orchestrator/pkg/infra/db/mongo.go +++ b/src/orchestrator/pkg/infra/db/mongo.go @@ -18,7 +18,6 @@ package db import ( "encoding/json" - "log" "sort" "golang.org/x/net/context" @@ -135,88 +134,6 @@ func (m *MongoStore) validateParams(args ...interface{}) bool { return true } -// Create is used to create a DB entry -func (m *MongoStore) Create(coll string, key Key, tag string, data interface{}) error { - if data == nil || !m.validateParams(coll, key, tag) { - return pkgerrors.New("No Data to store") - } - - c := getCollection(coll, m) - ctx := context.Background() - - //Insert the data and then add the objectID to the masterTable - res, err := c.InsertOne(ctx, bson.D{ - {tag, data}, - }) - if err != nil { - return pkgerrors.Errorf("Error inserting into database: %s", err.Error()) - } - - //Add objectID of created data to masterKey document - //Create masterkey document if it does not exist - filter := bson.D{{"key", key}} - - _, err = decodeBytes( - c.FindOneAndUpdate( - ctx, - filter, - bson.D{ - {"$set", bson.D{ - {tag, res.InsertedID}, - }}, - }, - options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(options.After))) - - if err != nil { - return pkgerrors.Errorf("Error updating master table: %s", err.Error()) - } - - return nil -} - -// Update is used to update a DB entry -func (m *MongoStore) Update(coll string, key Key, tag string, data interface{}) error { - if data == nil || !m.validateParams(coll, key, tag) { - return pkgerrors.New("No Data to update") - } - - c := getCollection(coll, m) - ctx := context.Background() - - //Get the masterkey document based on given key - filter := bson.D{{"key", key}} - keydata, err := decodeBytes(c.FindOne(context.Background(), filter)) - if err != nil { - return pkgerrors.Errorf("Error finding master table: %s", err.Error()) - } - - //Read the tag objectID from document - tagoid, ok := keydata.Lookup(tag).ObjectIDOK() - if !ok { - return pkgerrors.Errorf("Error finding objectID for tag %s", tag) - } - - //Update the document with new data - filter = bson.D{{"_id", tagoid}} - - _, err = decodeBytes( - c.FindOneAndUpdate( - ctx, - filter, - bson.D{ - {"$set", bson.D{ - {tag, data}, - }}, - }, - options.FindOneAndUpdate().SetReturnDocument(options.After))) - - if err != nil { - return pkgerrors.Errorf("Error updating record: %s", err.Error()) - } - - return nil -} - // Unmarshal implements an unmarshaler for bson data that // is produced from the mongo database func (m *MongoStore) Unmarshal(inp []byte, out interface{}) error { @@ -227,126 +144,6 @@ func (m *MongoStore) Unmarshal(inp []byte, out interface{}) error { return nil } -// Read method returns the data stored for this key and for this particular tag -func (m *MongoStore) Read(coll string, key Key, tag string) ([]byte, error) { - if !m.validateParams(coll, key, tag) { - return nil, pkgerrors.New("Mandatory fields are missing") - } - - c := getCollection(coll, m) - ctx := context.Background() - - //Get the masterkey document based on given key - filter := bson.D{{"key", key}} - keydata, err := decodeBytes(c.FindOne(context.Background(), filter)) - if err != nil { - return nil, pkgerrors.Errorf("Error finding master table: %s", err.Error()) - } - - //Read the tag objectID from document - tagoid, ok := keydata.Lookup(tag).ObjectIDOK() - if !ok { - return nil, pkgerrors.Errorf("Error finding objectID for tag %s", tag) - } - - //Use tag objectID to read the data from store - filter = bson.D{{"_id", tagoid}} - tagdata, err := decodeBytes(c.FindOne(ctx, filter)) - if err != nil { - return nil, pkgerrors.Errorf("Error reading found object: %s", err.Error()) - } - - //Return the data as a byte array - //Convert string data to byte array using the built-in functions - switch tagdata.Lookup(tag).Type { - case bson.TypeString: - return []byte(tagdata.Lookup(tag).StringValue()), nil - default: - return tagdata.Lookup(tag).Value, nil - } -} - -// Helper function that deletes an object by its ID -func (m *MongoStore) deleteObjectByID(coll string, objID primitive.ObjectID) error { - - c := getCollection(coll, m) - ctx := context.Background() - - _, err := c.DeleteOne(ctx, bson.D{{"_id", objID}}) - if err != nil { - return pkgerrors.Errorf("Error Deleting from database: %s", err.Error()) - } - - log.Printf("Deleted Obj with ID %s", objID.String()) - return nil -} - -// Delete method removes a document from the Database that matches key -// TODO: delete all referenced docs if tag is empty string -func (m *MongoStore) Delete(coll string, key Key, tag string) error { - if !m.validateParams(coll, key, tag) { - return pkgerrors.New("Mandatory fields are missing") - } - - c := getCollection(coll, m) - ctx := context.Background() - - //Get the masterkey document based on given key - filter := bson.D{{"key", key}} - //Remove the tag ID entry from masterkey table - update := bson.D{ - { - "$unset", bson.D{ - {tag, ""}, - }, - }, - } - keydata, err := decodeBytes(c.FindOneAndUpdate(ctx, filter, update, - options.FindOneAndUpdate().SetReturnDocument(options.Before))) - if err != nil { - //No document was found. Return nil. - if err == mongo.ErrNoDocuments { - return nil - } - //Return any other error that was found. - return pkgerrors.Errorf("Error decoding master table after update: %s", - err.Error()) - } - - //Read the tag objectID from document - elems, err := keydata.Elements() - if err != nil { - return pkgerrors.Errorf("Error reading elements from database: %s", err.Error()) - } - - tagoid, ok := keydata.Lookup(tag).ObjectIDOK() - if !ok { - return pkgerrors.Errorf("Error finding objectID for tag %s", tag) - } - - //Use tag objectID to read the data from store - err = m.deleteObjectByID(coll, tagoid) - if err != nil { - return pkgerrors.Errorf("Error deleting from database: %s", err.Error()) - } - - //Delete master table if no more tags left - //_id, key and tag should be elements in before doc - //if master table needs to be removed too - if len(elems) == 3 { - keyid, ok := keydata.Lookup("_id").ObjectIDOK() - if !ok { - return pkgerrors.Errorf("Error finding objectID for key %s", key) - } - err = m.deleteObjectByID(coll, keyid) - if err != nil { - return pkgerrors.Errorf("Error deleting master table from database: %s", err.Error()) - } - } - - return nil -} - func (m *MongoStore) findFilter(key Key) (primitive.M, error) { var bsonMap bson.M diff --git a/src/orchestrator/pkg/infra/db/mongo_test.go b/src/orchestrator/pkg/infra/db/mongo_test.go index d57c19dd..3e14e755 100644 --- a/src/orchestrator/pkg/infra/db/mongo_test.go +++ b/src/orchestrator/pkg/infra/db/mongo_test.go @@ -17,13 +17,8 @@ package db import ( - "bytes" "context" - "strings" - "testing" - pkgerrors "github.com/pkg/errors" - "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) @@ -83,388 +78,3 @@ func (c *mockCollection) CountDocuments(ctx context.Context, filter interface{}, opts ...*options.CountOptions) (int64, error) { return 1, c.Err } - -func TestCreate(t *testing.T) { - testCases := []struct { - label string - input map[string]interface{} - mockColl *mockCollection - bson bson.Raw - expectedError string - }{ - { - label: "Successfull creation of entry", - input: map[string]interface{}{ - "coll": "collname", - "key": MockKey{Key: "keyvalue"}, - "tag": "tagName", - "data": "Data In String Format", - }, - bson: bson.Raw{'\x08', '\x00', '\x00', '\x00', '\x0A', 'x', '\x00', '\x00'}, - mockColl: &mockCollection{}, - }, - { - label: "UnSuccessfull creation of entry", - input: map[string]interface{}{ - "coll": "collname", - "key": MockKey{Key: "keyvalue"}, - "tag": "tagName", - "data": "Data In String Format", - }, - mockColl: &mockCollection{ - Err: pkgerrors.New("DB Error"), - }, - expectedError: "DB Error", - }, - { - label: "Missing input fields", - input: map[string]interface{}{ - "coll": "", - "key": MockKey{Key: ""}, - "tag": "", - "data": "", - }, - expectedError: "No Data to store", - mockColl: &mockCollection{}, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - m, _ := NewMongoStore("name", &mongo.Database{}) - // Override the getCollection function with our mocked version - getCollection = func(coll string, m *MongoStore) MongoCollection { - return testCase.mockColl - } - - decodeBytes = func(sr *mongo.SingleResult) (bson.Raw, error) { - return testCase.bson, testCase.mockColl.Err - } - - err := m.Create(testCase.input["coll"].(string), testCase.input["key"].(Key), - testCase.input["tag"].(string), testCase.input["data"]) - if err != nil { - if testCase.expectedError == "" { - t.Fatalf("Create method returned an un-expected (%s)", err) - } - if !strings.Contains(string(err.Error()), testCase.expectedError) { - t.Fatalf("Create method returned an error (%s)", err) - } - } - }) - } -} - -func TestUpdate(t *testing.T) { - testCases := []struct { - label string - input map[string]interface{} - mockColl *mockCollection - bson bson.Raw - expectedError string - }{ - { - label: "Successfull update of entry", - input: map[string]interface{}{ - "coll": "collname", - "key": MockKey{Key: "keyvalue"}, - "tag": "metadata", - "data": "Data In String Format", - }, - // Binary form of - // { - // "_id" : ObjectId("5c115156777ff85654248ae1"), - // "key" : bson.D{{"name","testdef"},{"version","v1"}}, - // "metadata" : ObjectId("5c115156c9755047e318bbfd") - // } - bson: bson.Raw{ - '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79', - '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61', - '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74', - '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02', - '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00', - '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00', - '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74', - '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', - '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f', - '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', - '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00', - }, - mockColl: &mockCollection{}, - }, - { - label: "Entry does not exist", - input: map[string]interface{}{ - "coll": "collname", - "key": MockKey{Key: "keyvalue"}, - "tag": "tagName", - "data": "Data In String Format", - }, - mockColl: &mockCollection{ - Err: pkgerrors.New("DB Error"), - }, - expectedError: "DB Error", - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - m, _ := NewMongoStore("name", &mongo.Database{}) - // Override the getCollection function with our mocked version - getCollection = func(coll string, m *MongoStore) MongoCollection { - return testCase.mockColl - } - - decodeBytes = func(sr *mongo.SingleResult) (bson.Raw, error) { - return testCase.bson, testCase.mockColl.Err - } - - err := m.Update(testCase.input["coll"].(string), testCase.input["key"].(Key), - testCase.input["tag"].(string), testCase.input["data"]) - if err != nil { - if testCase.expectedError == "" { - t.Fatalf("Create method returned an un-expected (%s)", err) - } - if !strings.Contains(string(err.Error()), testCase.expectedError) { - t.Fatalf("Create method returned an error (%s)", err) - } - } - }) - } -} - -func TestRead(t *testing.T) { - testCases := []struct { - label string - input map[string]interface{} - mockColl *mockCollection - bson bson.Raw - expectedError string - expected []byte - }{ - { - label: "Successfull Read of entry", - input: map[string]interface{}{ - "coll": "collname", - "key": MockKey{Key: "keyvalue"}, - "tag": "metadata", - }, - // Binary form of - // { - // "_id" : ObjectId("5c115156777ff85654248ae1"), - // "key" : bson.D{{"name","testdef"},{"version","v1"}}, - // "metadata" : ObjectId("5c115156c9755047e318bbfd") - // } - bson: bson.Raw{ - '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79', - '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61', - '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74', - '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02', - '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00', - '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00', - '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74', - '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', - '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f', - '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', - '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00', - }, - mockColl: &mockCollection{}, - // This is not the document because we are mocking decodeBytes - expected: []byte{92, 17, 81, 86, 119, 127, 248, 86, 84, 36, 138, 225}, - }, - { - label: "UnSuccessfull Read of entry: object not found", - input: map[string]interface{}{ - "coll": "collname", - "key": MockKey{Key: "keyvalue"}, - "tag": "badtag", - }, - // Binary form of - // { - // "_id" : ObjectId("5c115156777ff85654248ae1"), - // "key" : bson.D{{"name","testdef"},{"version","v1"}}, - // "metadata" : ObjectId("5c115156c9755047e318bbfd") - // } - bson: bson.Raw{ - '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79', - '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61', - '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74', - '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02', - '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00', - '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00', - '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74', - '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', - '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f', - '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', - '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00', - }, - mockColl: &mockCollection{}, - expectedError: "Error finding objectID", - }, - { - label: "UnSuccessfull Read of entry", - input: map[string]interface{}{ - "coll": "collname", - "key": MockKey{Key: "keyvalue"}, - "tag": "tagName", - }, - mockColl: &mockCollection{ - Err: pkgerrors.New("DB Error"), - }, - expectedError: "DB Error", - }, - { - label: "Missing input fields", - input: map[string]interface{}{ - "coll": "", - "key": MockKey{Key: ""}, - "tag": "", - }, - expectedError: "Mandatory fields are missing", - mockColl: &mockCollection{}, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - m, _ := NewMongoStore("name", &mongo.Database{}) - // Override the getCollection function with our mocked version - getCollection = func(coll string, m *MongoStore) MongoCollection { - return testCase.mockColl - } - - decodeBytes = func(sr *mongo.SingleResult) (bson.Raw, error) { - return testCase.bson, testCase.mockColl.Err - } - got, err := m.Read(testCase.input["coll"].(string), testCase.input["key"].(Key), - testCase.input["tag"].(string)) - if err != nil { - if testCase.expectedError == "" { - t.Fatalf("Read method returned an un-expected (%s)", err) - } - if !strings.Contains(string(err.Error()), testCase.expectedError) { - t.Fatalf("Read method returned an error (%s)", err) - } - } else { - if bytes.Compare(got, testCase.expected) != 0 { - t.Fatalf("Read returned unexpected data: %v, expected: %v", - string(got), testCase.expected) - } - } - }) - } -} - -func TestDelete(t *testing.T) { - testCases := []struct { - label string - input map[string]interface{} - mockColl *mockCollection - bson bson.Raw - expectedError string - }{ - { - label: "Successfull Delete of entry", - input: map[string]interface{}{ - "coll": "collname", - "key": MockKey{Key: "keyvalue"}, - "tag": "metadata", - }, - // Binary form of - // { - // "_id" : ObjectId("5c115156777ff85654248ae1"), - // "key" : bson.D{{"name","testdef"},{"version","v1"}}, - // "metadata" : ObjectId("5c115156c9755047e318bbfd") - // } - bson: bson.Raw{ - '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79', - '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61', - '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74', - '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02', - '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00', - '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00', - '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74', - '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', - '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f', - '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', - '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00', - }, - mockColl: &mockCollection{}, - }, - { - label: "UnSuccessfull Delete of entry", - input: map[string]interface{}{ - "coll": "collname", - "key": MockKey{Key: "keyvalue"}, - "tag": "tagName", - }, - mockColl: &mockCollection{ - Err: pkgerrors.New("DB Error"), - }, - expectedError: "DB Error", - }, - { - label: "UnSuccessfull Delete, key not found", - input: map[string]interface{}{ - "coll": "collname", - "key": MockKey{Key: "keyvalue"}, - "tag": "tagName", - }, - // Binary form of - // { - // "_id" : ObjectId("5c115156777ff85654248ae1"), - // "key" : bson.D{{"name","testdef"},{"version","v1"}}, - // "metadata" : ObjectId("5c115156c9755047e318bbfd") - // } - bson: bson.Raw{ - '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79', - '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61', - '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74', - '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02', - '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00', - '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00', - '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74', - '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', - '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f', - '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', - '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00', - }, - mockColl: &mockCollection{}, - expectedError: "Error finding objectID", - }, - { - label: "Missing input fields", - input: map[string]interface{}{ - "coll": "", - "key": MockKey{Key: ""}, - "tag": "", - }, - expectedError: "Mandatory fields are missing", - mockColl: &mockCollection{}, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.label, func(t *testing.T) { - m, _ := NewMongoStore("name", &mongo.Database{}) - // Override the getCollection function with our mocked version - getCollection = func(coll string, m *MongoStore) MongoCollection { - return testCase.mockColl - } - - decodeBytes = func(sr *mongo.SingleResult) (bson.Raw, error) { - return testCase.bson, testCase.mockColl.Err - } - err := m.Delete(testCase.input["coll"].(string), testCase.input["key"].(Key), - testCase.input["tag"].(string)) - if err != nil { - if testCase.expectedError == "" { - t.Fatalf("Delete method returned an un-expected (%s)", err) - } - if !strings.Contains(string(err.Error()), testCase.expectedError) { - t.Fatalf("Delete method returned an error (%s)", err) - } - } - }) - } -} diff --git a/src/orchestrator/pkg/infra/db/store.go b/src/orchestrator/pkg/infra/db/store.go index a332fcda..d6ed6022 100644 --- a/src/orchestrator/pkg/infra/db/store.go +++ b/src/orchestrator/pkg/infra/db/store.go @@ -39,20 +39,6 @@ type Store interface { // Unmarshal implements any unmarshaling needed for the database Unmarshal(inp []byte, out interface{}) error - // Creates a new master document with key and links data with tag and - // creates a pointer(row) to the newly added data in the master table - Create(table string, key Key, tag string, data interface{}) error - - // Reads data for a particular key with specific tag. - Read(table string, key Key, tag string) ([]byte, error) - - // Update data for particular key with specific tag - Update(table string, key Key, tag string, data interface{}) error - - // Deletes a specific tag data for key. - // TODO: If tag is empty, it will delete all tags under key. - Delete(table string, key Key, tag string) error - // Inserts and Updates a tag with key and also adds query fields if provided Insert(coll string, key Key, query interface{}, tag string, data interface{}) error diff --git a/src/orchestrator/pkg/module/app_intent.go b/src/orchestrator/pkg/module/app_intent.go index 9da252e5..6b394513 100644 --- a/src/orchestrator/pkg/module/app_intent.go +++ b/src/orchestrator/pkg/module/app_intent.go @@ -53,11 +53,11 @@ type SpecData struct { // AppIntentManager is an interface which exposes the // AppIntentManager functionalities type AppIntentManager interface { - CreateAppIntent(a AppIntent, p string, ca string, v string, i string) (AppIntent, error) - GetAppIntent(ai string, p string, ca string, v string, i string) (AppIntent, error) - GetAllIntentsByApp(aN, p, ca, v, i string) (SpecData, error) - GetAllAppIntents(p, ca, v, i string) (ApplicationsAndClusterInfo, error) - DeleteAppIntent(ai string, p string, ca string, v string, i string) error + CreateAppIntent(a AppIntent, p string, ca string, v string, i string, digName string) (AppIntent, error) + GetAppIntent(ai string, p string, ca string, v string, i string, digName string) (AppIntent, error) + GetAllIntentsByApp(aN, p, ca, v, i, digName string) (SpecData, error) + GetAllAppIntents(p, ca, v, i, digName string) (ApplicationsAndClusterInfo, error) + DeleteAppIntent(ai string, p string, ca string, v string, i string, digName string) error } //AppIntentQueryKey required for query @@ -67,20 +67,22 @@ type AppIntentQueryKey struct { // AppIntentKey is used as primary key type AppIntentKey struct { - Name string `json:"appintent"` - Project string `json:"project"` - CompositeApp string `json:"compositeapp"` - Version string `json:"compositeappversion"` - Intent string `json:"genericplacement"` + Name string `json:"appintent"` + Project string `json:"project"` + CompositeApp string `json:"compositeapp"` + Version string `json:"compositeappversion"` + Intent string `json:"genericplacement"` + DeploymentIntentGroupName string `json:"deploymentintentgroup"` } // AppIntentFindByAppKey required for query type AppIntentFindByAppKey struct { - Project string `json:"project"` - CompositeApp string `json:"compositeapp"` - CompositeAppVersion string `json:"compositeappversion"` - Intent string `json:"genericplacement"` - AppName string `json:"app-name"` + Project string `json:"project"` + CompositeApp string `json:"compositeapp"` + CompositeAppVersion string `json:"compositeappversion"` + Intent string `json:"genericplacement"` + DeploymentIntentGroupName string `json:"deploymentintentgroup"` + AppName string `json:"app-name"` } // ApplicationsAndClusterInfo type represents the list of @@ -121,11 +123,11 @@ func NewAppIntentClient() *AppIntentClient { } // CreateAppIntent creates an entry for AppIntent in the db. -// Other input parameters for it - projectName, compositeAppName, version, intentName. -func (c *AppIntentClient) CreateAppIntent(a AppIntent, p string, ca string, v string, i string) (AppIntent, error) { +// Other input parameters for it - projectName, compositeAppName, version, intentName and deploymentIntentGroupName. +func (c *AppIntentClient) CreateAppIntent(a AppIntent, p string, ca string, v string, i string, digName string) (AppIntent, error) { //Check for the AppIntent already exists here. - res, err := c.GetAppIntent(a.MetaData.Name, p, ca, v, i) + res, err := c.GetAppIntent(a.MetaData.Name, p, ca, v, i, digName) if !reflect.DeepEqual(res, AppIntent{}) { return AppIntent{}, pkgerrors.New("AppIntent already exists") } @@ -143,17 +145,24 @@ func (c *AppIntentClient) CreateAppIntent(a AppIntent, p string, ca string, v st } // check if Intent exists - _, err = NewGenericPlacementIntentClient().GetGenericPlacementIntent(i, p, ca, v) + _, err = NewGenericPlacementIntentClient().GetGenericPlacementIntent(i, p, ca, v, digName) if err != nil { return AppIntent{}, pkgerrors.New("Unable to find the intent") } + // check if the deploymentIntentGrpName exists + _, err = NewDeploymentIntentGroupClient().GetDeploymentIntentGroup(digName, p, ca, v) + if err != nil { + return AppIntent{}, pkgerrors.New("Unable to find the deployment-intent-group-name") + } + akey := AppIntentKey{ - Name: a.MetaData.Name, - Project: p, - CompositeApp: ca, - Version: v, - Intent: i, + Name: a.MetaData.Name, + Project: p, + CompositeApp: ca, + Version: v, + Intent: i, + DeploymentIntentGroupName: digName, } qkey := AppIntentQueryKey{ @@ -168,15 +177,16 @@ func (c *AppIntentClient) CreateAppIntent(a AppIntent, p string, ca string, v st return a, nil } -// GetAppIntent shall take arguments - name of the app intent, name of the project, name of the composite app, version of the composite app and intent name. It shall return the AppIntent -func (c *AppIntentClient) GetAppIntent(ai string, p string, ca string, v string, i string) (AppIntent, error) { +// GetAppIntent shall take arguments - name of the app intent, name of the project, name of the composite app, version of the composite app,intent name and deploymentIntentGroupName. It shall return the AppIntent +func (c *AppIntentClient) GetAppIntent(ai string, p string, ca string, v string, i string, digName string) (AppIntent, error) { k := AppIntentKey{ - Name: ai, - Project: p, - CompositeApp: ca, - Version: v, - Intent: i, + Name: ai, + Project: p, + CompositeApp: ca, + Version: v, + Intent: i, + DeploymentIntentGroupName: digName, } result, err := db.DBconn.Find(c.storeName, k, c.tagMetaData) @@ -197,17 +207,18 @@ func (c *AppIntentClient) GetAppIntent(ai string, p string, ca string, v string, } /* -GetAllIntentsByApp takes in parameters AppName, CompositeAppName, CompositeNameVersion -and GenericPlacementIntentName. Returns SpecData which contains +GetAllIntentsByApp queries intent by AppName, it takes in parameters AppName, CompositeAppName, CompositeNameVersion, +GenericPlacementIntentName & DeploymentIntentGroupName. Returns SpecData which contains all the intents for the app. */ -func (c *AppIntentClient) GetAllIntentsByApp(aN, p, ca, v, i string) (SpecData, error) { +func (c *AppIntentClient) GetAllIntentsByApp(aN, p, ca, v, i, digName string) (SpecData, error) { k := AppIntentFindByAppKey{ - Project: p, - CompositeApp: ca, - CompositeAppVersion: v, - Intent: i, - AppName: aN, + Project: p, + CompositeApp: ca, + CompositeAppVersion: v, + Intent: i, + DeploymentIntentGroupName: digName, + AppName: aN, } result, err := db.DBconn.Find(c.storeName, k, c.tagMetaData) if err != nil { @@ -224,15 +235,16 @@ func (c *AppIntentClient) GetAllIntentsByApp(aN, p, ca, v, i string) (SpecData, /* GetAllAppIntents takes in paramaters ProjectName, CompositeAppName, CompositeNameVersion -and GenericPlacementIntentName. Returns the ApplicationsAndClusterInfo Object - an array of AppClusterInfo +and GenericPlacementIntentName,DeploymentIntentGroupName. Returns the ApplicationsAndClusterInfo Object - an array of AppClusterInfo */ -func (c *AppIntentClient) GetAllAppIntents(p, ca, v, i string) (ApplicationsAndClusterInfo, error) { +func (c *AppIntentClient) GetAllAppIntents(p, ca, v, i, digName string) (ApplicationsAndClusterInfo, error) { k := AppIntentKey{ - Name: "", - Project: p, - CompositeApp: ca, - Version: v, - Intent: i, + Name: "", + Project: p, + CompositeApp: ca, + Version: v, + Intent: i, + DeploymentIntentGroupName: digName, } result, err := db.DBconn.Find(c.storeName, k, c.tagMetaData) if err != nil { @@ -262,13 +274,14 @@ func (c *AppIntentClient) GetAllAppIntents(p, ca, v, i string) (ApplicationsAndC } // DeleteAppIntent delete an AppIntent -func (c *AppIntentClient) DeleteAppIntent(ai string, p string, ca string, v string, i string) error { +func (c *AppIntentClient) DeleteAppIntent(ai string, p string, ca string, v string, i string, digName string) error { k := AppIntentKey{ - Name: ai, - Project: p, - CompositeApp: ca, - Version: v, - Intent: i, + Name: ai, + Project: p, + CompositeApp: ca, + Version: v, + Intent: i, + DeploymentIntentGroupName: digName, } err := db.DBconn.Remove(c.storeName, k) diff --git a/src/orchestrator/pkg/module/app_intent_test.go b/src/orchestrator/pkg/module/app_intent_test.go index 089f09ff..a2e295ea 100644 --- a/src/orchestrator/pkg/module/app_intent_test.go +++ b/src/orchestrator/pkg/module/app_intent_test.go @@ -33,6 +33,7 @@ func TestCreateAppIntent(t *testing.T) { inputCompositeApp string inputCompositeAppVersion string inputGenericPlacementIntent string + inputDeploymentIntentGrpName string expectedError string mockdb *db.MockDB expected AppIntent @@ -81,6 +82,7 @@ func TestCreateAppIntent(t *testing.T) { inputCompositeApp: "testCompositeApp", inputCompositeAppVersion: "testCompositeAppVersion", inputGenericPlacementIntent: "testIntent", + inputDeploymentIntentGrpName: "testDeploymentIntentGroup", expected: AppIntent{ MetaData: MetaData{ Name: "testAppIntent", @@ -142,6 +144,7 @@ func TestCreateAppIntent(t *testing.T) { Project: "testProject", CompositeApp: "testCompositeApp", Version: "testCompositeAppVersion", + DigName: "testDeploymentIntentGroup", }.String(): { "genericplacementintentmetadata": []byte( "{\"metadata\":{\"Name\":\"testIntent\"," + @@ -150,6 +153,39 @@ func TestCreateAppIntent(t *testing.T) { "\"UserData2\": \"userData2\"}," + "\"spec\":{\"Logical-Cloud\": \"logicalCloud1\"}}"), }, + DeploymentIntentGroupKey{ + Name: "testDeploymentIntentGroup", + Project: "testProject", + CompositeApp: "testCompositeApp", + Version: "testCompositeAppVersion", + }.String(): { + "deploymentintentgroupmetadata": []byte( + "{\"metadata\":{\"name\":\"testDeploymentIntentGroup\"," + + "\"description\":\"DescriptionTestDeploymentIntentGroup\"," + + "\"userData1\": \"userData1\"," + + "\"userData2\": \"userData2\"}," + + "\"spec\":{\"profile\": \"Testprofile\"," + + "\"version\": \"version of deployment\"," + + "\"override-values\":[" + + "{" + + "\"app-name\": \"TestAppName\"," + + "\"values\": " + + "{" + + "\"imageRepository\":\"registry.hub.docker.com\"" + + "}" + + "}," + + "{" + + "\"app-name\": \"TestAppName\"," + + "\"values\": " + + "{" + + "\"imageRepository\":\"registry.hub.docker.com\"" + + "}" + + "}" + + "]," + + "\"logical-cloud\": \"cloud1\"" + + "}"+ + "}"), + }, }, }, }, @@ -158,7 +194,7 @@ func TestCreateAppIntent(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb appIntentCli := NewAppIntentClient() - got, err := appIntentCli.CreateAppIntent(testCase.inputAppIntent, testCase.inputProject, testCase.inputCompositeApp, testCase.inputCompositeAppVersion, testCase.inputGenericPlacementIntent) + got, err := appIntentCli.CreateAppIntent(testCase.inputAppIntent, testCase.inputProject, testCase.inputCompositeApp, testCase.inputCompositeAppVersion, testCase.inputGenericPlacementIntent, testCase.inputDeploymentIntentGrpName) if err != nil { if testCase.expectedError == "" { t.Fatalf("CreateAppIntent returned an unexpected error %s, ", err) @@ -186,6 +222,7 @@ func TestGetAppIntent(t *testing.T) { compositeAppName string compositeAppVersion string genericPlacementIntent string + deploymentIntentgrpName string }{ { label: "Get Intent", @@ -194,6 +231,7 @@ func TestGetAppIntent(t *testing.T) { compositeAppName: "testCompositeApp", compositeAppVersion: "testCompositeAppVersion", genericPlacementIntent: "testIntent", + deploymentIntentgrpName: "testDeploymentIntentGroup", expected: AppIntent{ MetaData: MetaData{ Name: "testAppIntent", @@ -234,6 +272,7 @@ func TestGetAppIntent(t *testing.T) { CompositeApp: "testCompositeApp", Version: "testCompositeAppVersion", Intent: "testIntent", + DeploymentIntentGroupName: "testDeploymentIntentGroup", }.String(): { "appintentmetadata": []byte( "{\"metadata\":{\"Name\":\"testAppIntent\"," + @@ -270,7 +309,7 @@ func TestGetAppIntent(t *testing.T) { db.DBconn = testCase.mockdb appIntentCli := NewAppIntentClient() got, err := appIntentCli.GetAppIntent(testCase.appIntentName, testCase.projectName, testCase.compositeAppName, testCase.compositeAppVersion, - testCase.genericPlacementIntent) + testCase.genericPlacementIntent, testCase.deploymentIntentgrpName) if err != nil { if testCase.expectedError == "" { t.Fatalf("GetAppIntent returned an unexpected error: %s", err) diff --git a/src/orchestrator/pkg/module/deployment_intent_groups.go b/src/orchestrator/pkg/module/deployment_intent_groups.go index dec6391f..f8e434f4 100644 --- a/src/orchestrator/pkg/module/deployment_intent_groups.go +++ b/src/orchestrator/pkg/module/deployment_intent_groups.go @@ -47,6 +47,7 @@ type DepSpecData struct { Profile string `json:"profile"` Version string `json:"version"` OverrideValuesObj []OverrideValues `json:"override-values"` + LogicalCloud string `json:"logical-cloud"` } // OverrideValues has appName and ValuesObj diff --git a/src/orchestrator/pkg/module/deployment_intent_groups_test.go b/src/orchestrator/pkg/module/deployment_intent_groups_test.go index 0fdeb4a1..86ae49df 100644 --- a/src/orchestrator/pkg/module/deployment_intent_groups_test.go +++ b/src/orchestrator/pkg/module/deployment_intent_groups_test.go @@ -57,6 +57,7 @@ func TestCreateDeploymentIntentGroup(t *testing.T) { "imageRepository": "registry.hub.docker.com", }}, }, + LogicalCloud: "cloud1", }, }, inputProject: "testProject", @@ -82,6 +83,7 @@ func TestCreateDeploymentIntentGroup(t *testing.T) { "imageRepository": "registry.hub.docker.com", }}, }, + LogicalCloud: "cloud1", }, }, expectedError: "", @@ -167,6 +169,7 @@ func TestGetDeploymentIntentGroup(t *testing.T) { "imageRepository": "registry.hub.docker.com", }}, }, + LogicalCloud: "cloud1", }, }, expectedError: "", @@ -200,7 +203,10 @@ func TestGetDeploymentIntentGroup(t *testing.T) { "\"imageRepository\":\"registry.hub.docker.com\"" + "}" + "}" + - "]}}"), + "]," + + "\"logical-cloud\": \"cloud1\"" + + "}"+ + "}"), }, }, }, diff --git a/src/orchestrator/pkg/module/generic_placement_intent.go b/src/orchestrator/pkg/module/generic_placement_intent.go index fb00a6ab..3ff1c7dc 100644 --- a/src/orchestrator/pkg/module/generic_placement_intent.go +++ b/src/orchestrator/pkg/module/generic_placement_intent.go @@ -18,6 +18,7 @@ package module import ( "encoding/json" + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" pkgerrors "github.com/pkg/errors" @@ -26,7 +27,6 @@ import ( // GenericPlacementIntent shall have 2 fields - metadata and spec type GenericPlacementIntent struct { MetaData GenIntentMetaData `json:"metadata"` - Spec GenIntentSpecData `json:"spec"` } // GenIntentMetaData has name, description, userdata1, userdata2 @@ -37,21 +37,16 @@ type GenIntentMetaData struct { UserData2 string `json:"userData2"` } -// GenIntentSpecData has logical-cloud-name -type GenIntentSpecData struct { - LogicalCloud string `json:"logical-cloud"` -} - // GenericPlacementIntentManager is an interface which exposes the GenericPlacementIntentManager functionality type GenericPlacementIntentManager interface { CreateGenericPlacementIntent(g GenericPlacementIntent, p string, ca string, - v string) (GenericPlacementIntent, error) + v string, digName string) (GenericPlacementIntent, error) GetGenericPlacementIntent(intentName string, projectName string, - compositeAppName string, version string) (GenericPlacementIntent, error) + compositeAppName string, version string, digName string) (GenericPlacementIntent, error) DeleteGenericPlacementIntent(intentName string, projectName string, - compositeAppName string, version string) error + compositeAppName string, version string, digName string) error - GetAllGenericPlacementIntents(p string, ca string, v string) ([]GenericPlacementIntent, error) + GetAllGenericPlacementIntents(p string, ca string, v string, digName string) ([]GenericPlacementIntent, error) } // GenericPlacementIntentKey is used as the primary key @@ -60,6 +55,7 @@ type GenericPlacementIntentKey struct { Project string `json:"project"` CompositeApp string `json:"compositeapp"` Version string `json:"compositeappversion"` + DigName string `json:"deploymentintentgroup"` } // We will use json marshalling to convert to string to @@ -86,12 +82,12 @@ func NewGenericPlacementIntentClient() *GenericPlacementIntentClient { } } -// CreateGenericPlacementIntent creates an entry for GenericPlacementIntent in the database. Other Input parameters for it - projectName, compositeAppName, version +// CreateGenericPlacementIntent creates an entry for GenericPlacementIntent in the database. Other Input parameters for it - projectName, compositeAppName, version and deploymentIntentGroupName func (c *GenericPlacementIntentClient) CreateGenericPlacementIntent(g GenericPlacementIntent, p string, ca string, - v string) (GenericPlacementIntent, error) { + v string, digName string) (GenericPlacementIntent, error) { // check if the genericPlacement already exists. - res, err := c.GetGenericPlacementIntent(g.MetaData.Name, p, ca, v) + res, err := c.GetGenericPlacementIntent(g.MetaData.Name, p, ca, v, digName) if res != (GenericPlacementIntent{}) { return GenericPlacementIntent{}, pkgerrors.New("Intent already exists") } @@ -108,11 +104,18 @@ func (c *GenericPlacementIntentClient) CreateGenericPlacementIntent(g GenericPla return GenericPlacementIntent{}, pkgerrors.New("Unable to find the composite-app") } + // check if the deploymentIntentGrpName exists + _, err = NewDeploymentIntentGroupClient().GetDeploymentIntentGroup(digName, p, ca, v) + if err != nil { + return GenericPlacementIntent{}, pkgerrors.New("Unable to find the deployment-intent-group-name") + } + gkey := GenericPlacementIntentKey{ Name: g.MetaData.Name, Project: p, CompositeApp: ca, Version: v, + DigName: digName, } err = db.DBconn.Insert(c.storeName, gkey, nil, c.tagMetaData, g) @@ -123,13 +126,14 @@ func (c *GenericPlacementIntentClient) CreateGenericPlacementIntent(g GenericPla return g, nil } -// GetGenericPlacementIntent shall take arguments - name of the intent, name of the project, name of the composite app and version of the composite app. It shall return the genericPlacementIntent if its present. -func (c *GenericPlacementIntentClient) GetGenericPlacementIntent(i string, p string, ca string, v string) (GenericPlacementIntent, error) { +// GetGenericPlacementIntent shall take arguments - name of the intent, name of the project, name of the composite app, version of the composite app and deploymentIntentGroupName. It shall return the genericPlacementIntent if its present. +func (c *GenericPlacementIntentClient) GetGenericPlacementIntent(i string, p string, ca string, v string, digName string) (GenericPlacementIntent, error) { key := GenericPlacementIntentKey{ Name: i, Project: p, CompositeApp: ca, Version: v, + DigName: digName, } result, err := db.DBconn.Find(c.storeName, key, c.tagMetaData) @@ -150,8 +154,8 @@ func (c *GenericPlacementIntentClient) GetGenericPlacementIntent(i string, p str } -// GetAllGenericPlacementIntents returns all the generic placement intents for a given compsoite app name, composite app version and project. -func (c *GenericPlacementIntentClient) GetAllGenericPlacementIntents(p string, ca string, v string) ([]GenericPlacementIntent, error) { +// GetAllGenericPlacementIntents returns all the generic placement intents for a given compsoite app name, composite app version, project and deploymentIntentGroupName +func (c *GenericPlacementIntentClient) GetAllGenericPlacementIntents(p string, ca string, v string, digName string) ([]GenericPlacementIntent, error) { //Check if project exists _, err := NewProjectClient().GetProject(p) @@ -170,6 +174,7 @@ func (c *GenericPlacementIntentClient) GetAllGenericPlacementIntents(p string, c Project: p, CompositeApp: ca, Version: v, + DigName: digName, } var gpList []GenericPlacementIntent @@ -192,12 +197,13 @@ func (c *GenericPlacementIntentClient) GetAllGenericPlacementIntents(p string, c } // DeleteGenericPlacementIntent the intent from the database -func (c *GenericPlacementIntentClient) DeleteGenericPlacementIntent(i string, p string, ca string, v string) error { +func (c *GenericPlacementIntentClient) DeleteGenericPlacementIntent(i string, p string, ca string, v string, digName string) error { key := GenericPlacementIntentKey{ Name: i, Project: p, CompositeApp: ca, Version: v, + DigName: digName, } err := db.DBconn.Remove(c.storeName, key) diff --git a/src/orchestrator/pkg/module/generic_placement_intent_test.go b/src/orchestrator/pkg/module/generic_placement_intent_test.go index d779e81f..59c1cac5 100644 --- a/src/orchestrator/pkg/module/generic_placement_intent_test.go +++ b/src/orchestrator/pkg/module/generic_placement_intent_test.go @@ -31,6 +31,7 @@ func TestCreateGenericPlacementIntent(t *testing.T) { inputProject string inputCompositeApp string inputCompositeAppVersion string + inputDepIntGrpName string expectedError string mockdb *db.MockDB expected GenericPlacementIntent @@ -44,13 +45,11 @@ func TestCreateGenericPlacementIntent(t *testing.T) { UserData1: "userData1", UserData2: "userData2", }, - Spec: GenIntentSpecData{ - LogicalCloud: "logicalCloud1", - }, }, inputProject: "testProject", inputCompositeApp: "testCompositeApp", inputCompositeAppVersion: "testCompositeAppVersion", + inputDepIntGrpName: "testDeploymentIntentGroup", expected: GenericPlacementIntent{ MetaData: GenIntentMetaData{ Name: "testGenericPlacement", @@ -58,9 +57,6 @@ func TestCreateGenericPlacementIntent(t *testing.T) { UserData1: "userData1", UserData2: "userData2", }, - Spec: GenIntentSpecData{ - LogicalCloud: "logicalCloud1", - }, }, expectedError: "", mockdb: &db.MockDB{ @@ -82,6 +78,40 @@ func TestCreateGenericPlacementIntent(t *testing.T) { "\"spec\":{" + "\"version\":\"version of the composite app\"}}"), }, + DeploymentIntentGroupKey{ + Name: "testDeploymentIntentGroup", + Project: "testProject", + CompositeApp: "testCompositeApp", + Version: "testCompositeAppVersion", + }.String(): { + "deploymentintentgroupmetadata": []byte( + "{\"metadata\":{\"name\":\"testDeploymentIntentGroup\"," + + "\"description\":\"DescriptionTestDeploymentIntentGroup\"," + + "\"userData1\": \"userData1\"," + + "\"userData2\": \"userData2\"}," + + "\"spec\":{\"profile\": \"Testprofile\"," + + "\"version\": \"version of deployment\"," + + "\"override-values\":[" + + "{" + + "\"app-name\": \"TestAppName\"," + + "\"values\": " + + "{" + + "\"imageRepository\":\"registry.hub.docker.com\"" + + "}" + + "}," + + "{" + + "\"app-name\": \"TestAppName\"," + + "\"values\": " + + "{" + + "\"imageRepository\":\"registry.hub.docker.com\"" + + "}" + + "}" + + "]," + + "\"logical-cloud\": \"cloud1\"" + + "}"+ + "}"), + }, + }, }, }, @@ -91,7 +121,7 @@ func TestCreateGenericPlacementIntent(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb intentCli := NewGenericPlacementIntentClient() - got, err := intentCli.CreateGenericPlacementIntent(testCase.inputIntent, testCase.inputProject, testCase.inputCompositeApp, testCase.inputCompositeAppVersion) + got, err := intentCli.CreateGenericPlacementIntent(testCase.inputIntent, testCase.inputProject, testCase.inputCompositeApp, testCase.inputCompositeAppVersion, testCase.inputDepIntGrpName) if err != nil { if testCase.expectedError == "" { t.Fatalf("CreateGenericPlacementIntent returned an unexpected error %s", err) @@ -120,6 +150,7 @@ func TestGetGenericPlacementIntent(t *testing.T) { projectName string compositeAppName string compositeAppVersion string + deploymentIntentGroupName string }{ { label: "Get Intent", @@ -127,6 +158,7 @@ func TestGetGenericPlacementIntent(t *testing.T) { projectName: "testProject", compositeAppName: "testCompositeApp", compositeAppVersion: "testVersion", + deploymentIntentGroupName: "testDeploymentIntentGroup", expected: GenericPlacementIntent{ MetaData: GenIntentMetaData{ Name: "testIntent", @@ -134,9 +166,6 @@ func TestGetGenericPlacementIntent(t *testing.T) { UserData1: "userData1", UserData2: "userData2", }, - Spec: GenIntentSpecData{ - LogicalCloud: "logicalCloud1", - }, }, expectedError: "", mockdb: &db.MockDB{ @@ -146,13 +175,14 @@ func TestGetGenericPlacementIntent(t *testing.T) { Project: "testProject", CompositeApp: "testCompositeApp", Version: "testVersion", + DigName: "testDeploymentIntentGroup", }.String(): { "genericplacementintentmetadata": []byte( "{\"metadata\":{\"Name\":\"testIntent\"," + "\"Description\":\"A sample intent for testing\"," + "\"UserData1\": \"userData1\"," + - "\"UserData2\": \"userData2\"}," + - "\"spec\":{\"Logical-Cloud\": \"logicalCloud1\"}}"), + "\"UserData2\": \"userData2\"}" + + "}"), }, }, }, @@ -163,7 +193,7 @@ func TestGetGenericPlacementIntent(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb intentCli := NewGenericPlacementIntentClient() - got, err := intentCli.GetGenericPlacementIntent(testCase.intentName, testCase.projectName, testCase.compositeAppName, testCase.compositeAppVersion) + got, err := intentCli.GetGenericPlacementIntent(testCase.intentName, testCase.projectName, testCase.compositeAppName, testCase.compositeAppVersion, testCase.deploymentIntentGroupName) if err != nil { if testCase.expectedError == "" { t.Fatalf("GetGenericPlacementIntent returned an unexpected error: %s", err) diff --git a/src/orchestrator/pkg/module/instantiation.go b/src/orchestrator/pkg/module/instantiation.go index 0ae76006..d703af7f 100644 --- a/src/orchestrator/pkg/module/instantiation.go +++ b/src/orchestrator/pkg/module/instantiation.go @@ -99,12 +99,12 @@ func NewInstantiationClient() *InstantiationClient { func (c InstantiationClient) Approve(p string, ca string, v string, di string) error { s, err := NewDeploymentIntentGroupClient().GetDeploymentIntentGroupState(di, p, ca, v) if err != nil { - log.Info("DeploymentIntentGroup has no state info ", log.Fields{"DeploymentIntentGroup: ":di}) + log.Info("DeploymentIntentGroup has no state info ", log.Fields{"DeploymentIntentGroup: ": di}) return pkgerrors.Wrap(err, "DeploymentIntentGroup has no state info: "+di) } stateVal, err := state.GetCurrentStateFromStateInfo(s) if err != nil { - log.Info("Error getting current state from DeploymentIntentGroup stateInfo", log.Fields{"DeploymentIntentGroup ":di}) + log.Info("Error getting current state from DeploymentIntentGroup stateInfo", log.Fields{"DeploymentIntentGroup ": di}) return pkgerrors.Errorf("Error getting current state from DeploymentIntentGroup stateInfo: " + di) } switch stateVal { @@ -222,24 +222,24 @@ func GetSortedTemplateForApp(appName, p, ca, v, rName, cp string, overrideValues return sortedTemplates, err } -func calculateDirPath(fp string) string { +func calculateDirPath(fp string) string { sa := strings.Split(fp, "/") return "/" + sa[1] + "/" + sa[2] + "/" } func cleanTmpfiles(sortedTemplates []helm.KubernetesResourceTemplate) error { dp := calculateDirPath(sortedTemplates[0].FilePath) - for _, st := range sortedTemplates{ + for _, st := range sortedTemplates { log.Info("Clean up ::", log.Fields{"file: ": st.FilePath}) err := os.Remove(st.FilePath) if err != nil { - log.Error("Error while deleting file", log.Fields{"file: ":st.FilePath}) + log.Error("Error while deleting file", log.Fields{"file: ": st.FilePath}) return err } } err := os.RemoveAll(dp) if err != nil { - log.Error("Error while deleting dir", log.Fields{"Dir: ":dp}) + log.Error("Error while deleting dir", log.Fields{"Dir: ": dp}) return err } log.Info("Clean up temp-dir::", log.Fields{"Dir: ": dp}) @@ -298,7 +298,7 @@ func (c InstantiationClient) Instantiate(p string, ca string, v string, di strin return pkgerrors.Wrap(err, "Not finding the apps") } - cca, err := makeAppContextForCompositeApp(p, ca, v, rName) + cca, err := makeAppContextForCompositeApp(p, ca, v, rName, di) if err != nil { return err } @@ -338,7 +338,7 @@ func (c InstantiationClient) Instantiate(p string, ca string, v string, di strin defer cleanTmpfiles(sortedTemplates) - specData, err := NewAppIntentClient().GetAllIntentsByApp(eachApp.Metadata.Name, p, ca, v, gIntent) + specData, err := NewAppIntentClient().GetAllIntentsByApp(eachApp.Metadata.Name, p, ca, v, gIntent, di) if err != nil { deleteAppContext(context) return pkgerrors.Wrap(err, "Unable to get the intents for app") @@ -369,7 +369,7 @@ func (c InstantiationClient) Instantiate(p string, ca string, v string, di strin deleteAppContext(context) return pkgerrors.Wrap(err, "Error while verifying resources in app: ") } - + } jappOrderInstr, err := json.Marshal(appOrderInstr) if err != nil { diff --git a/src/orchestrator/pkg/module/instantiation_appcontext_helper.go b/src/orchestrator/pkg/module/instantiation_appcontext_helper.go index 692cdf1e..06e025c7 100644 --- a/src/orchestrator/pkg/module/instantiation_appcontext_helper.go +++ b/src/orchestrator/pkg/module/instantiation_appcontext_helper.go @@ -46,7 +46,7 @@ type contextForCompositeApp struct { } // makeAppContext creates an appContext for a compositeApp and returns the output as contextForCompositeApp -func makeAppContextForCompositeApp(p, ca, v, rName string) (contextForCompositeApp, error) { +func makeAppContextForCompositeApp(p, ca, v, rName, dig string) (contextForCompositeApp, error) { context := appcontext.AppContext{} ctxval, err := context.InitAppContext() if err != nil { @@ -56,14 +56,14 @@ func makeAppContextForCompositeApp(p, ca, v, rName string) (contextForCompositeA if err != nil { return contextForCompositeApp{}, pkgerrors.Wrap(err, "Error creating CompositeApp handle") } - err = context.AddCompositeAppMeta(appcontext.CompositeAppMeta{Project: p, CompositeApp: ca, Version: v, Release: rName}) + err = context.AddCompositeAppMeta(appcontext.CompositeAppMeta{Project: p, CompositeApp: ca, Version: v, Release: rName, DeploymentIntentGroup: dig}) if err != nil { return contextForCompositeApp{}, pkgerrors.Wrap(err, "Error Adding CompositeAppMeta") } m, err := context.GetCompositeAppMeta() - log.Info(":: The meta data stored in the runtime context :: ", log.Fields{"Project": m.Project, "CompositeApp": m.CompositeApp, "Version": m.Version, "Release": m.Release}) + log.Info(":: The meta data stored in the runtime context :: ", log.Fields{"Project": m.Project, "CompositeApp": m.CompositeApp, "Version": m.Version, "Release": m.Release, "DeploymentIntentGroup": m.DeploymentIntentGroup}) cca := contextForCompositeApp{context: context, ctxval: ctxval, compositeAppHandle: compositeHandle} diff --git a/src/ovnaction/api/api.go b/src/ovnaction/api/api.go index bffab0a4..36744cb0 100644 --- a/src/ovnaction/api/api.go +++ b/src/ovnaction/api/api.go @@ -75,39 +75,38 @@ func NewRouter(testClient interface{}) *mux.Router { netcontrolintentHandler := netcontrolintentHandler{ client: setClient(moduleClient.NetControlIntent, testClient).(moduleLib.NetControlIntentManager), } - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent", netcontrolintentHandler.createHandler).Methods("POST") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent", netcontrolintentHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{name}", netcontrolintentHandler.putHandler).Methods("PUT") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{name}", netcontrolintentHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{name}", netcontrolintentHandler.deleteHandler).Methods("DELETE") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{name}/apply", netcontrolintentHandler.applyHandler).Methods("POST") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent", netcontrolintentHandler.createHandler).Methods("POST") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent", netcontrolintentHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{name}", netcontrolintentHandler.putHandler).Methods("PUT") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{name}", netcontrolintentHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{name}", netcontrolintentHandler.deleteHandler).Methods("DELETE") workloadintentHandler := workloadintentHandler{ client: setClient(moduleClient.WorkloadIntent, testClient).(moduleLib.WorkloadIntentManager), } - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents", workloadintentHandler.createHandler).Methods("POST") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents", workloadintentHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{name}", workloadintentHandler.putHandler).Methods("PUT") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{name}", workloadintentHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{name}", workloadintentHandler.deleteHandler).Methods("DELETE") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/workload-intents", workloadintentHandler.createHandler).Methods("POST") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/workload-intents", workloadintentHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/workload-intents/{name}", workloadintentHandler.putHandler).Methods("PUT") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/workload-intents/{name}", workloadintentHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/workload-intents/{name}", workloadintentHandler.deleteHandler).Methods("DELETE") workloadifintentHandler := workloadifintentHandler{ client: setClient(moduleClient.WorkloadIfIntent, testClient).(moduleLib.WorkloadIfIntentManager), } - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces", workloadifintentHandler.createHandler).Methods("POST") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces", workloadifintentHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces/{name}", workloadifintentHandler.putHandler).Methods("PUT") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces/{name}", workloadifintentHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces/{name}", workloadifintentHandler.deleteHandler).Methods("DELETE") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces", workloadifintentHandler.createHandler).Methods("POST") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces", workloadifintentHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces/{name}", workloadifintentHandler.putHandler).Methods("PUT") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces/{name}", workloadifintentHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/workload-intents/{workload-intent}/interfaces/{name}", workloadifintentHandler.deleteHandler).Methods("DELETE") chainHandler := chainHandler{ client: setClient(moduleClient.Chain, testClient).(moduleLib.ChainManager), } - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains", chainHandler.createHandler).Methods("POST") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains", chainHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains/{name}", chainHandler.putHandler).Methods("PUT") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains/{name}", chainHandler.getHandler).Methods("GET") - router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/network-controller-intent/{net-control-intent}/network-chains/{name}", chainHandler.deleteHandler).Methods("DELETE") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/network-chains", chainHandler.createHandler).Methods("POST") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/network-chains", chainHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/network-chains/{name}", chainHandler.putHandler).Methods("PUT") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/network-chains/{name}", chainHandler.getHandler).Methods("GET") + router.HandleFunc("/projects/{project}/composite-apps/{composite-app-name}/{version}/deployment-intent-groups/{deployment-intent-group-name}/network-controller-intent/{net-control-intent}/network-chains/{name}", chainHandler.deleteHandler).Methods("DELETE") return router } diff --git a/src/ovnaction/api/chainhandler.go b/src/ovnaction/api/chainhandler.go index 52ed18e5..daf5b2eb 100644 --- a/src/ovnaction/api/chainhandler.go +++ b/src/ovnaction/api/chainhandler.go @@ -23,8 +23,8 @@ import ( "net/http" "strings" - moduleLib "github.com/onap/multicloud-k8s/src/ovnaction/pkg/module" "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation" + moduleLib "github.com/onap/multicloud-k8s/src/ovnaction/pkg/module" pkgerrors "github.com/pkg/errors" "github.com/gorilla/mux" @@ -141,6 +141,7 @@ func (h chainHandler) createHandler(w http.ResponseWriter, r *http.Request) { project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] netControlIntent := vars["net-control-intent"] err := json.NewDecoder(r.Body).Decode(&ch) @@ -166,7 +167,7 @@ func (h chainHandler) createHandler(w http.ResponseWriter, r *http.Request) { return } - ret, err := h.client.CreateChain(ch, project, compositeApp, compositeAppVersion, netControlIntent, false) + ret, err := h.client.CreateChain(ch, project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent, false) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -189,6 +190,7 @@ func (h chainHandler) putHandler(w http.ResponseWriter, r *http.Request) { project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] netControlIntent := vars["net-control-intent"] err := json.NewDecoder(r.Body).Decode(&ch) @@ -221,7 +223,7 @@ func (h chainHandler) putHandler(w http.ResponseWriter, r *http.Request) { return } - ret, err := h.client.CreateChain(ch, project, compositeApp, compositeAppVersion, netControlIntent, true) + ret, err := h.client.CreateChain(ch, project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent, true) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -244,18 +246,19 @@ func (h chainHandler) getHandler(w http.ResponseWriter, r *http.Request) { project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] netControlIntent := vars["net-control-intent"] var ret interface{} var err error if len(name) == 0 { - ret, err = h.client.GetChains(project, compositeApp, compositeAppVersion, netControlIntent) + ret, err = h.client.GetChains(project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } else { - ret, err = h.client.GetChain(name, project, compositeApp, compositeAppVersion, netControlIntent) + ret, err = h.client.GetChain(name, project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -278,9 +281,10 @@ func (h chainHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] netControlIntent := vars["net-control-intent"] - err := h.client.DeleteChain(name, project, compositeApp, compositeAppVersion, netControlIntent) + err := h.client.DeleteChain(name, project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/src/ovnaction/api/netcontrolintenthandler.go b/src/ovnaction/api/netcontrolintenthandler.go index 631f13c4..85318ccf 100644 --- a/src/ovnaction/api/netcontrolintenthandler.go +++ b/src/ovnaction/api/netcontrolintenthandler.go @@ -22,18 +22,15 @@ import ( "io" "net/http" + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation" moduleLib "github.com/onap/multicloud-k8s/src/ovnaction/pkg/module" pkgerrors "github.com/pkg/errors" - "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation" - "github.com/gorilla/mux" ) var netCntIntJSONFile string = "json-schemas/metadata.json" - - // Used to store backend implementations objects // Also simplifies mocking for unit testing purposes type netcontrolintentHandler struct { @@ -59,6 +56,7 @@ func (h netcontrolintentHandler) createHandler(w http.ResponseWriter, r *http.Re project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] err := json.NewDecoder(r.Body).Decode(&nci) @@ -72,11 +70,10 @@ func (h netcontrolintentHandler) createHandler(w http.ResponseWriter, r *http.Re } err, httpError := validation.ValidateJsonSchemaData(netCntIntJSONFile, nci) -if err != nil { - http.Error(w, err.Error(), httpError) - return -} - + if err != nil { + http.Error(w, err.Error(), httpError) + return + } // Name is required. if nci.Metadata.Name == "" { @@ -90,7 +87,7 @@ if err != nil { return } - ret, err := h.client.CreateNetControlIntent(nci, project, compositeApp, compositeAppVersion, false) + ret, err := h.client.CreateNetControlIntent(nci, project, compositeApp, compositeAppVersion, deployIntentGroup, false) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -113,6 +110,7 @@ func (h netcontrolintentHandler) putHandler(w http.ResponseWriter, r *http.Reque project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] err := json.NewDecoder(r.Body).Decode(&nci) @@ -144,7 +142,7 @@ func (h netcontrolintentHandler) putHandler(w http.ResponseWriter, r *http.Reque return } - ret, err := h.client.CreateNetControlIntent(nci, project, compositeApp, compositeAppVersion, true) + ret, err := h.client.CreateNetControlIntent(nci, project, compositeApp, compositeAppVersion, deployIntentGroup, true) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -167,17 +165,18 @@ func (h netcontrolintentHandler) getHandler(w http.ResponseWriter, r *http.Reque project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] var ret interface{} var err error if len(name) == 0 { - ret, err = h.client.GetNetControlIntents(project, compositeApp, compositeAppVersion) + ret, err = h.client.GetNetControlIntents(project, compositeApp, compositeAppVersion, deployIntentGroup) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } else { - ret, err = h.client.GetNetControlIntent(name, project, compositeApp, compositeAppVersion) + ret, err = h.client.GetNetControlIntent(name, project, compositeApp, compositeAppVersion, deployIntentGroup) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -200,42 +199,9 @@ func (h netcontrolintentHandler) deleteHandler(w http.ResponseWriter, r *http.Re project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] - err := h.client.DeleteNetControlIntent(name, project, compositeApp, compositeAppVersion) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusNoContent) -} - -// Apply handles POST operations to Apply a particular NetControlIntent to the App Context -// TODO: This is a test API - it can be removed once the orchestrator has been implemented to -// invoke the appcontext update via grpc. -func (h netcontrolintentHandler) applyHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - name := vars["name"] - project := vars["project"] - compositeApp := vars["composite-app-name"] - compositeAppVersion := vars["version"] - - var aci struct { - AppContextId string `json:"appContextId"` - } - - err := json.NewDecoder(r.Body).Decode(&aci) - - switch { - case err == io.EOF: - http.Error(w, "Empty body", http.StatusBadRequest) - return - case err != nil: - http.Error(w, err.Error(), http.StatusUnprocessableEntity) - return - } - - err = h.client.ApplyNetControlIntent(name, project, compositeApp, compositeAppVersion, aci.AppContextId) + err := h.client.DeleteNetControlIntent(name, project, compositeApp, compositeAppVersion, deployIntentGroup) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/src/ovnaction/api/workloadifintenthandler.go b/src/ovnaction/api/workloadifintenthandler.go index e7be6317..5c396378 100644 --- a/src/ovnaction/api/workloadifintenthandler.go +++ b/src/ovnaction/api/workloadifintenthandler.go @@ -22,8 +22,8 @@ import ( "io" "net/http" - moduleLib "github.com/onap/multicloud-k8s/src/ovnaction/pkg/module" "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation" + moduleLib "github.com/onap/multicloud-k8s/src/ovnaction/pkg/module" pkgerrors "github.com/pkg/errors" "github.com/gorilla/mux" @@ -90,6 +90,7 @@ func (h workloadifintentHandler) createHandler(w http.ResponseWriter, r *http.Re project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] netControlIntent := vars["net-control-intent"] workloadIntent := vars["workload-intent"] @@ -105,10 +106,10 @@ func (h workloadifintentHandler) createHandler(w http.ResponseWriter, r *http.Re } err, httpError := validation.ValidateJsonSchemaData(netIfJSONFile, wif) -if err != nil { - http.Error(w, err.Error(), httpError) - return -} + if err != nil { + http.Error(w, err.Error(), httpError) + return + } // Name is required. if wif.Metadata.Name == "" { @@ -127,7 +128,7 @@ if err != nil { return } - ret, err := h.client.CreateWorkloadIfIntent(wif, project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent, false) + ret, err := h.client.CreateWorkloadIfIntent(wif, project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent, workloadIntent, false) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -150,6 +151,7 @@ func (h workloadifintentHandler) putHandler(w http.ResponseWriter, r *http.Reque project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] netControlIntent := vars["net-control-intent"] workloadIntent := vars["workload-intent"] @@ -188,7 +190,7 @@ func (h workloadifintentHandler) putHandler(w http.ResponseWriter, r *http.Reque return } - ret, err := h.client.CreateWorkloadIfIntent(wif, project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent, true) + ret, err := h.client.CreateWorkloadIfIntent(wif, project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent, workloadIntent, true) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -211,19 +213,20 @@ func (h workloadifintentHandler) getHandler(w http.ResponseWriter, r *http.Reque project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] netControlIntent := vars["net-control-intent"] workloadIntent := vars["workload-intent"] var ret interface{} var err error if len(name) == 0 { - ret, err = h.client.GetWorkloadIfIntents(project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent) + ret, err = h.client.GetWorkloadIfIntents(project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent, workloadIntent) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } else { - ret, err = h.client.GetWorkloadIfIntent(name, project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent) + ret, err = h.client.GetWorkloadIfIntent(name, project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent, workloadIntent) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -246,10 +249,11 @@ func (h workloadifintentHandler) deleteHandler(w http.ResponseWriter, r *http.Re project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] netControlIntent := vars["net-control-intent"] workloadIntent := vars["workload-intent"] - err := h.client.DeleteWorkloadIfIntent(name, project, compositeApp, compositeAppVersion, netControlIntent, workloadIntent) + err := h.client.DeleteWorkloadIfIntent(name, project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent, workloadIntent) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/src/ovnaction/api/workloadintenthandler.go b/src/ovnaction/api/workloadintenthandler.go index acf4edbb..485f6f40 100644 --- a/src/ovnaction/api/workloadintenthandler.go +++ b/src/ovnaction/api/workloadintenthandler.go @@ -22,8 +22,8 @@ import ( "io" "net/http" - moduleLib "github.com/onap/multicloud-k8s/src/ovnaction/pkg/module" "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation" + moduleLib "github.com/onap/multicloud-k8s/src/ovnaction/pkg/module" pkgerrors "github.com/pkg/errors" "github.com/gorilla/mux" @@ -71,6 +71,7 @@ func (h workloadintentHandler) createHandler(w http.ResponseWriter, r *http.Requ project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] netControlIntent := vars["net-control-intent"] err := json.NewDecoder(r.Body).Decode(&wi) @@ -85,10 +86,10 @@ func (h workloadintentHandler) createHandler(w http.ResponseWriter, r *http.Requ } err, httpError := validation.ValidateJsonSchemaData(workloadIntJSONFile, wi) -if err != nil { - http.Error(w, err.Error(), httpError) - return -} + if err != nil { + http.Error(w, err.Error(), httpError) + return + } // Name is required. if wi.Metadata.Name == "" { @@ -102,7 +103,7 @@ if err != nil { return } - ret, err := h.client.CreateWorkloadIntent(wi, project, compositeApp, compositeAppVersion, netControlIntent, false) + ret, err := h.client.CreateWorkloadIntent(wi, project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent, false) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -125,6 +126,7 @@ func (h workloadintentHandler) putHandler(w http.ResponseWriter, r *http.Request project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] netControlIntent := vars["net-control-intent"] err := json.NewDecoder(r.Body).Decode(&wi) @@ -157,7 +159,7 @@ func (h workloadintentHandler) putHandler(w http.ResponseWriter, r *http.Request return } - ret, err := h.client.CreateWorkloadIntent(wi, project, compositeApp, compositeAppVersion, netControlIntent, true) + ret, err := h.client.CreateWorkloadIntent(wi, project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent, true) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -180,18 +182,19 @@ func (h workloadintentHandler) getHandler(w http.ResponseWriter, r *http.Request project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] netControlIntent := vars["net-control-intent"] var ret interface{} var err error if len(name) == 0 { - ret, err = h.client.GetWorkloadIntents(project, compositeApp, compositeAppVersion, netControlIntent) + ret, err = h.client.GetWorkloadIntents(project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } else { - ret, err = h.client.GetWorkloadIntent(name, project, compositeApp, compositeAppVersion, netControlIntent) + ret, err = h.client.GetWorkloadIntent(name, project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -214,9 +217,10 @@ func (h workloadintentHandler) deleteHandler(w http.ResponseWriter, r *http.Requ project := vars["project"] compositeApp := vars["composite-app-name"] compositeAppVersion := vars["version"] + deployIntentGroup := vars["deployment-intent-group-name"] netControlIntent := vars["net-control-intent"] - err := h.client.DeleteWorkloadIntent(name, project, compositeApp, compositeAppVersion, netControlIntent) + err := h.client.DeleteWorkloadIntent(name, project, compositeApp, compositeAppVersion, deployIntentGroup, netControlIntent) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/src/ovnaction/internal/action/action.go b/src/ovnaction/internal/action/action.go index c9b912fa..ae04cb0f 100644 --- a/src/ovnaction/internal/action/action.go +++ b/src/ovnaction/internal/action/action.go @@ -47,11 +47,12 @@ func UpdateAppContext(intentName, appContextId string) error { project := caMeta.Project compositeapp := caMeta.CompositeApp compositeappversion := caMeta.Version + deployIntentGroup := caMeta.DeploymentIntentGroup // Handle all Workload Intents for the Network Control Intent - wis, err := module.NewWorkloadIntentClient().GetWorkloadIntents(project, compositeapp, compositeappversion, intentName) + wis, err := module.NewWorkloadIntentClient().GetWorkloadIntents(project, compositeapp, compositeappversion, deployIntentGroup, intentName) if err != nil { - return pkgerrors.Wrapf(err, "Error getting Workload Intents for Network Control Intent %v for %v/%v%v not found", intentName, project, compositeapp, compositeappversion) + return pkgerrors.Wrapf(err, "Error getting Workload Intents for Network Control Intent %v for %v/%v%v/%v not found", intentName, project, compositeapp, deployIntentGroup, compositeappversion) } // Handle all intents (currently just Workload Interface intents) for each Workload Intent @@ -66,20 +67,22 @@ func UpdateAppContext(intentName, appContextId string) error { wifs, err := module.NewWorkloadIfIntentClient().GetWorkloadIfIntents(project, compositeapp, compositeappversion, + deployIntentGroup, intentName, wi.Metadata.Name) if err != nil { return pkgerrors.Wrapf(err, - "Error getting Workload Interface Intents for Workload Intent %v under Network Control Intent %v for %v/%v%v not found", - wi.Metadata.Name, intentName, project, compositeapp, compositeappversion) + "Error getting Workload Interface Intents for Workload Intent %v under Network Control Intent %v for %v/%v%v/%v not found", + wi.Metadata.Name, intentName, project, compositeapp, compositeappversion, deployIntentGroup) } if len(wifs) == 0 { log.Warn("No interface intents provided for workload intent", log.Fields{ - "project": project, - "composite app": compositeapp, - "composite app version": compositeappversion, - "network control intent": intentName, - "workload intent": wi.Metadata.Name, + "project": project, + "composite app": compositeapp, + "composite app version": compositeappversion, + "deployment intent group": deployIntentGroup, + "network control intent": intentName, + "workload intent": wi.Metadata.Name, }) continue } @@ -91,14 +94,15 @@ func UpdateAppContext(intentName, appContextId string) error { strings.Join([]string{wi.Spec.WorkloadResource, wi.Spec.Type}, "+")) if err != nil { log.Warn("App Context resource handle not found", log.Fields{ - "project": project, - "composite app": compositeapp, - "composite app version": compositeappversion, - "network control intent": intentName, - "workload name": wi.Metadata.Name, - "app": wi.Spec.AppName, - "resource": wi.Spec.WorkloadResource, - "resource type": wi.Spec.Type, + "project": project, + "composite app": compositeapp, + "composite app version": compositeappversion, + "deployment intent group": deployIntentGroup, + "network control intent": intentName, + "workload name": wi.Metadata.Name, + "app": wi.Spec.AppName, + "resource": wi.Spec.WorkloadResource, + "resource type": wi.Spec.Type, }) continue } diff --git a/src/ovnaction/pkg/module/chaining.go b/src/ovnaction/pkg/module/chaining.go index 45f061fa..bc2cac00 100644 --- a/src/ovnaction/pkg/module/chaining.go +++ b/src/ovnaction/pkg/module/chaining.go @@ -54,6 +54,7 @@ type ChainKey struct { Project string `json:"project"` CompositeApp string `json:"compositeapp"` CompositeAppVersion string `json:"compositeappversion"` + DigName string `json:"deploymentintentgroup"` NetControlIntent string `json:"netcontrolintent"` NetworkChain string `json:"networkchain"` } @@ -76,10 +77,10 @@ const ChainingKind = "NetworkChaining" // ChainManager is an interface exposing the Chain functionality type ChainManager interface { - CreateChain(ch Chain, pr, ca, caver, netctrlint string, exists bool) (Chain, error) - GetChain(name, pr, ca, caver, netctrlint string) (Chain, error) - GetChains(pr, ca, caver, netctrlint string) ([]Chain, error) - DeleteChain(name, pr, ca, caver, netctrlint string) error + CreateChain(ch Chain, pr, ca, caver, dig, netctrlint string, exists bool) (Chain, error) + GetChain(name, pr, ca, caver, dig, netctrlint string) (Chain, error) + GetChains(pr, ca, caver, dig, netctrlint string) ([]Chain, error) + DeleteChain(name, pr, ca, caver, dig, netctrlint string) error } // ChainClient implements the Manager @@ -100,24 +101,25 @@ func NewChainClient() *ChainClient { } // CreateChain - create a new Chain -func (v *ChainClient) CreateChain(ch Chain, pr, ca, caver, netctrlint string, exists bool) (Chain, error) { +func (v *ChainClient) CreateChain(ch Chain, pr, ca, caver, dig, netctrlint string, exists bool) (Chain, error) { //Construct key and tag to select the entry key := ChainKey{ Project: pr, CompositeApp: ca, CompositeAppVersion: caver, + DigName: dig, NetControlIntent: netctrlint, NetworkChain: ch.Metadata.Name, } //Check if the Network Control Intent exists - _, err := NewNetControlIntentClient().GetNetControlIntent(netctrlint, pr, ca, caver) + _, err := NewNetControlIntentClient().GetNetControlIntent(netctrlint, pr, ca, caver, dig) if err != nil { return Chain{}, pkgerrors.Errorf("Network Control Intent %v does not exist", netctrlint) } //Check if this Chain already exists - _, err = v.GetChain(ch.Metadata.Name, pr, ca, caver, netctrlint) + _, err = v.GetChain(ch.Metadata.Name, pr, ca, caver, dig, netctrlint) if err == nil && !exists { return Chain{}, pkgerrors.New("Chain already exists") } @@ -131,12 +133,13 @@ func (v *ChainClient) CreateChain(ch Chain, pr, ca, caver, netctrlint string, ex } // GetChain returns the Chain for corresponding name -func (v *ChainClient) GetChain(name, pr, ca, caver, netctrlint string) (Chain, error) { +func (v *ChainClient) GetChain(name, pr, ca, caver, dig, netctrlint string) (Chain, error) { //Construct key and tag to select the entry key := ChainKey{ Project: pr, CompositeApp: ca, CompositeAppVersion: caver, + DigName: dig, NetControlIntent: netctrlint, NetworkChain: name, } @@ -160,12 +163,13 @@ func (v *ChainClient) GetChain(name, pr, ca, caver, netctrlint string) (Chain, e } // GetChains returns all of the Chains for for the given network control intent -func (v *ChainClient) GetChains(pr, ca, caver, netctrlint string) ([]Chain, error) { +func (v *ChainClient) GetChains(pr, ca, caver, dig, netctrlint string) ([]Chain, error) { //Construct key and tag to select the entry key := ChainKey{ Project: pr, CompositeApp: ca, CompositeAppVersion: caver, + DigName: dig, NetControlIntent: netctrlint, NetworkChain: "", } @@ -189,13 +193,14 @@ func (v *ChainClient) GetChains(pr, ca, caver, netctrlint string) ([]Chain, erro } // DeleteChain deletes the Chain from the database -func (v *ChainClient) DeleteChain(name, pr, ca, caver, netctrlint string) error { +func (v *ChainClient) DeleteChain(name, pr, ca, caver, dig, netctrlint string) error { //Construct key and tag to select the entry key := ChainKey{ Project: pr, CompositeApp: ca, CompositeAppVersion: caver, + DigName: dig, NetControlIntent: netctrlint, NetworkChain: name, } diff --git a/src/ovnaction/pkg/module/netcontrolintent.go b/src/ovnaction/pkg/module/netcontrolintent.go index c005a935..eada4be1 100644 --- a/src/ovnaction/pkg/module/netcontrolintent.go +++ b/src/ovnaction/pkg/module/netcontrolintent.go @@ -17,17 +17,7 @@ package module import ( - "encoding/json" - "strings" - - jyaml "github.com/ghodss/yaml" - - nettypes "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1" - "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext" "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" - log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" pkgerrors "github.com/pkg/errors" ) @@ -43,15 +33,15 @@ type NetControlIntentKey struct { Project string `json:"project"` CompositeApp string `json:"compositeapp"` CompositeAppVersion string `json:"compositeappversion"` + DigName string `json:"deploymentintentgroup"` } // Manager is an interface exposing the NetControlIntent functionality type NetControlIntentManager interface { - CreateNetControlIntent(nci NetControlIntent, project, compositeapp, compositeappversion string, exists bool) (NetControlIntent, error) - GetNetControlIntent(name, project, compositeapp, compositeappversion string) (NetControlIntent, error) - GetNetControlIntents(project, compositeapp, compositeappversion string) ([]NetControlIntent, error) - DeleteNetControlIntent(name, project, compositeapp, compositeappversion string) error - ApplyNetControlIntent(name, project, compositeapp, compositeappversion, appContextId string) error + CreateNetControlIntent(nci NetControlIntent, project, compositeapp, compositeappversion, dig string, exists bool) (NetControlIntent, error) + GetNetControlIntent(name, project, compositeapp, compositeappversion, dig string) (NetControlIntent, error) + GetNetControlIntents(project, compositeapp, compositeappversion, dig string) ([]NetControlIntent, error) + DeleteNetControlIntent(name, project, compositeapp, compositeappversion, dig string) error } // NetControlIntentClient implements the Manager @@ -72,7 +62,7 @@ func NewNetControlIntentClient() *NetControlIntentClient { } // CreateNetControlIntent - create a new NetControlIntent -func (v *NetControlIntentClient) CreateNetControlIntent(nci NetControlIntent, project, compositeapp, compositeappversion string, exists bool) (NetControlIntent, error) { +func (v *NetControlIntentClient) CreateNetControlIntent(nci NetControlIntent, project, compositeapp, compositeappversion, dig string, exists bool) (NetControlIntent, error) { //Construct key and tag to select the entry key := NetControlIntentKey{ @@ -80,10 +70,11 @@ func (v *NetControlIntentClient) CreateNetControlIntent(nci NetControlIntent, pr Project: project, CompositeApp: compositeapp, CompositeAppVersion: compositeappversion, + DigName: dig, } //Check if this NetControlIntent already exists - _, err := v.GetNetControlIntent(nci.Metadata.Name, project, compositeapp, compositeappversion) + _, err := v.GetNetControlIntent(nci.Metadata.Name, project, compositeapp, compositeappversion, dig) if err == nil && !exists { return NetControlIntent{}, pkgerrors.New("NetControlIntent already exists") } @@ -97,7 +88,7 @@ func (v *NetControlIntentClient) CreateNetControlIntent(nci NetControlIntent, pr } // GetNetControlIntent returns the NetControlIntent for corresponding name -func (v *NetControlIntentClient) GetNetControlIntent(name, project, compositeapp, compositeappversion string) (NetControlIntent, error) { +func (v *NetControlIntentClient) GetNetControlIntent(name, project, compositeapp, compositeappversion, dig string) (NetControlIntent, error) { //Construct key and tag to select the entry key := NetControlIntentKey{ @@ -105,6 +96,7 @@ func (v *NetControlIntentClient) GetNetControlIntent(name, project, compositeapp Project: project, CompositeApp: compositeapp, CompositeAppVersion: compositeappversion, + DigName: dig, } value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) @@ -126,7 +118,7 @@ func (v *NetControlIntentClient) GetNetControlIntent(name, project, compositeapp } // GetNetControlIntentList returns all of the NetControlIntent for corresponding name -func (v *NetControlIntentClient) GetNetControlIntents(project, compositeapp, compositeappversion string) ([]NetControlIntent, error) { +func (v *NetControlIntentClient) GetNetControlIntents(project, compositeapp, compositeappversion, dig string) ([]NetControlIntent, error) { //Construct key and tag to select the entry key := NetControlIntentKey{ @@ -134,6 +126,7 @@ func (v *NetControlIntentClient) GetNetControlIntents(project, compositeapp, com Project: project, CompositeApp: compositeapp, CompositeAppVersion: compositeappversion, + DigName: dig, } var resp []NetControlIntent @@ -155,7 +148,7 @@ func (v *NetControlIntentClient) GetNetControlIntents(project, compositeapp, com } // Delete the NetControlIntent from database -func (v *NetControlIntentClient) DeleteNetControlIntent(name, project, compositeapp, compositeappversion string) error { +func (v *NetControlIntentClient) DeleteNetControlIntent(name, project, compositeapp, compositeappversion, dig string) error { //Construct key and tag to select the entry key := NetControlIntentKey{ @@ -163,6 +156,7 @@ func (v *NetControlIntentClient) DeleteNetControlIntent(name, project, composite Project: project, CompositeApp: compositeapp, CompositeAppVersion: compositeappversion, + DigName: dig, } err := db.DBconn.Remove(v.db.storeName, key) @@ -172,124 +166,3 @@ func (v *NetControlIntentClient) DeleteNetControlIntent(name, project, composite return nil } - -// (Test Routine) - Apply network-control-intent -func (v *NetControlIntentClient) ApplyNetControlIntent(name, project, compositeapp, compositeappversion, appContextId string) error { - // TODO: Handle all Network Chain Intents for the Network Control Intent - - // Handle all Workload Intents for the Network Control Intent - wis, err := NewWorkloadIntentClient().GetWorkloadIntents(project, compositeapp, compositeappversion, name) - if err != nil { - return pkgerrors.Wrapf(err, "Error getting Workload Intents for Network Control Intent %v for %v/%v%v not found", name, project, compositeapp, compositeappversion) - } - - // Setup the AppContext - var context appcontext.AppContext - _, err = context.LoadAppContext(appContextId) - if err != nil { - return pkgerrors.Wrapf(err, "Error getting AppContext with Id: %v for %v/%v%v", - appContextId, project, compositeapp, compositeappversion) - } - - // Handle all intents (currently just Interface intents) for each Workload Intent - for _, wi := range wis { - // The app/resource identified in the workload intent needs to be updated with two annotations. - // 1 - The "k8s.v1.cni.cncf.io/networks" annotation will have {"name": "ovn-networkobj", "namespace": "default"} added - // to it (preserving any existing values for this annotation. - // 2 - The "k8s.plugin.opnfv.org/nfn-network" annotation will add any network interfaces that are provided by the - // workload/interfaces intents. - - // Prepare the list of interfaces from the workload intent - wifs, err := NewWorkloadIfIntentClient().GetWorkloadIfIntents(project, - compositeapp, - compositeappversion, - name, - wi.Metadata.Name) - if err != nil { - return pkgerrors.Wrapf(err, - "Error getting Workload Interface Intents for Workload Intent %v under Network Control Intent %v for %v/%v%v not found", - wi.Metadata.Name, name, project, compositeapp, compositeappversion) - } - if len(wifs) == 0 { - log.Warn("No interface intents provided for workload intent", log.Fields{ - "project": project, - "composite app": compositeapp, - "composite app version": compositeappversion, - "network control intent": name, - "workload intent": wi.Metadata.Name, - }) - continue - } - - // Get all clusters for the current App from the AppContext - clusters, err := context.GetClusterNames(wi.Spec.AppName) - for _, c := range clusters { - rh, err := context.GetResourceHandle(wi.Spec.AppName, c, - strings.Join([]string{wi.Spec.WorkloadResource, wi.Spec.Type}, "+")) - if err != nil { - log.Warn("App Context resource handle not found", log.Fields{ - "project": project, - "composite app": compositeapp, - "composite app version": compositeappversion, - "network control intent": name, - "workload name": wi.Metadata.Name, - "app": wi.Spec.AppName, - "resource": wi.Spec.WorkloadResource, - "resource type": wi.Spec.Type, - }) - continue - } - r, err := context.GetValue(rh) - if err != nil { - log.Error("Error retrieving resource from App Context", log.Fields{ - "error": err, - "resource handle": rh, - }) - } - - // Unmarshal resource to K8S object - robj, err := runtime.Decode(scheme.Codecs.UniversalDeserializer(), []byte(r.(string))) - - // Add network annotation to object - netAnnot := nettypes.NetworkSelectionElement{ - Name: "ovn-networkobj", - Namespace: "default", - } - AddNetworkAnnotation(robj, netAnnot) - - // Add nfn interface annotations to object - var newNfnIfs []WorkloadIfIntentSpec - for _, i := range wifs { - newNfnIfs = append(newNfnIfs, i.Spec) - } - AddNfnAnnotation(robj, newNfnIfs) - - // Marshal object back to yaml format (via json - seems to eliminate most clutter) - j, err := json.Marshal(robj) - if err != nil { - log.Error("Error marshalling resource to JSON", log.Fields{ - "error": err, - }) - continue - } - y, err := jyaml.JSONToYAML(j) - if err != nil { - log.Error("Error marshalling resource to YAML", log.Fields{ - "error": err, - }) - continue - } - - // Update resource in AppContext - err = context.UpdateResourceValue(rh, string(y)) - if err != nil { - log.Error("Network updating app context resource handle", log.Fields{ - "error": err, - "resource handle": rh, - }) - } - } - } - - return nil -} diff --git a/src/ovnaction/pkg/module/workloadifintent.go b/src/ovnaction/pkg/module/workloadifintent.go index 55062564..cea336f6 100644 --- a/src/ovnaction/pkg/module/workloadifintent.go +++ b/src/ovnaction/pkg/module/workloadifintent.go @@ -41,6 +41,7 @@ type WorkloadIfIntentKey struct { Project string `json:"provider"` CompositeApp string `json:"compositeapp"` CompositeAppVersion string `json:"compositeappversion"` + DigName string `json:"deploymentintentgroup"` NetControlIntent string `json:"netcontrolintent"` WorkloadIntent string `json:"workloadintent"` WorkloadIfIntent string `json:"workloadifintent"` @@ -48,10 +49,10 @@ type WorkloadIfIntentKey struct { // Manager is an interface exposing the WorkloadIfIntent functionality type WorkloadIfIntentManager interface { - CreateWorkloadIfIntent(wi WorkloadIfIntent, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string, exists bool) (WorkloadIfIntent, error) - GetWorkloadIfIntent(name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) (WorkloadIfIntent, error) - GetWorkloadIfIntents(project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) ([]WorkloadIfIntent, error) - DeleteWorkloadIfIntent(name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) error + CreateWorkloadIfIntent(wi WorkloadIfIntent, project, compositeapp, compositeappversion, dig, netcontrolintent, workloadintent string, exists bool) (WorkloadIfIntent, error) + GetWorkloadIfIntent(name, project, compositeapp, compositeappversion, dig, netcontrolintent, workloadintent string) (WorkloadIfIntent, error) + GetWorkloadIfIntents(project, compositeapp, compositeappversion, dig, netcontrolintent, workloadintent string) ([]WorkloadIfIntent, error) + DeleteWorkloadIfIntent(name, project, compositeapp, compositeappversion, dig, netcontrolintent, workloadintent string) error } // WorkloadIfIntentClient implements the Manager @@ -72,26 +73,27 @@ func NewWorkloadIfIntentClient() *WorkloadIfIntentClient { } // CreateWorkloadIfIntent - create a new WorkloadIfIntent -func (v *WorkloadIfIntentClient) CreateWorkloadIfIntent(wif WorkloadIfIntent, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string, exists bool) (WorkloadIfIntent, error) { +func (v *WorkloadIfIntentClient) CreateWorkloadIfIntent(wif WorkloadIfIntent, project, compositeapp, compositeappversion, dig, netcontrolintent, workloadintent string, exists bool) (WorkloadIfIntent, error) { //Construct key and tag to select the entry key := WorkloadIfIntentKey{ Project: project, CompositeApp: compositeapp, CompositeAppVersion: compositeappversion, + DigName: dig, NetControlIntent: netcontrolintent, WorkloadIntent: workloadintent, WorkloadIfIntent: wif.Metadata.Name, } //Check if the Workload Intent exists - _, err := NewWorkloadIntentClient().GetWorkloadIntent(workloadintent, project, compositeapp, compositeappversion, netcontrolintent) + _, err := NewWorkloadIntentClient().GetWorkloadIntent(workloadintent, project, compositeapp, compositeappversion, dig, netcontrolintent) if err != nil { return WorkloadIfIntent{}, pkgerrors.Errorf("Workload Intent %v does not exist", workloadintent) } //Check if this WorkloadIfIntent already exists - _, err = v.GetWorkloadIfIntent(wif.Metadata.Name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent) + _, err = v.GetWorkloadIfIntent(wif.Metadata.Name, project, compositeapp, compositeappversion, dig, netcontrolintent, workloadintent) if err == nil && !exists { return WorkloadIfIntent{}, pkgerrors.New("WorkloadIfIntent already exists") } @@ -105,13 +107,14 @@ func (v *WorkloadIfIntentClient) CreateWorkloadIfIntent(wif WorkloadIfIntent, pr } // GetWorkloadIfIntent returns the WorkloadIfIntent for corresponding name -func (v *WorkloadIfIntentClient) GetWorkloadIfIntent(name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) (WorkloadIfIntent, error) { +func (v *WorkloadIfIntentClient) GetWorkloadIfIntent(name, project, compositeapp, compositeappversion, dig, netcontrolintent, workloadintent string) (WorkloadIfIntent, error) { //Construct key and tag to select the entry key := WorkloadIfIntentKey{ Project: project, CompositeApp: compositeapp, CompositeAppVersion: compositeappversion, + DigName: dig, NetControlIntent: netcontrolintent, WorkloadIntent: workloadintent, WorkloadIfIntent: name, @@ -136,13 +139,14 @@ func (v *WorkloadIfIntentClient) GetWorkloadIfIntent(name, project, compositeapp } // GetWorkloadIfIntentList returns all of the WorkloadIfIntent for corresponding name -func (v *WorkloadIfIntentClient) GetWorkloadIfIntents(project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) ([]WorkloadIfIntent, error) { +func (v *WorkloadIfIntentClient) GetWorkloadIfIntents(project, compositeapp, compositeappversion, dig, netcontrolintent, workloadintent string) ([]WorkloadIfIntent, error) { //Construct key and tag to select the entry key := WorkloadIfIntentKey{ Project: project, CompositeApp: compositeapp, CompositeAppVersion: compositeappversion, + DigName: dig, NetControlIntent: netcontrolintent, WorkloadIntent: workloadintent, WorkloadIfIntent: "", @@ -167,13 +171,14 @@ func (v *WorkloadIfIntentClient) GetWorkloadIfIntents(project, compositeapp, com } // Delete the WorkloadIfIntent from database -func (v *WorkloadIfIntentClient) DeleteWorkloadIfIntent(name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) error { +func (v *WorkloadIfIntentClient) DeleteWorkloadIfIntent(name, project, compositeapp, compositeappversion, dig, netcontrolintent, workloadintent string) error { //Construct key and tag to select the entry key := WorkloadIfIntentKey{ Project: project, CompositeApp: compositeapp, CompositeAppVersion: compositeappversion, + DigName: dig, NetControlIntent: netcontrolintent, WorkloadIntent: workloadintent, WorkloadIfIntent: name, diff --git a/src/ovnaction/pkg/module/workloadintent.go b/src/ovnaction/pkg/module/workloadintent.go index e6916954..b1ca9d02 100644 --- a/src/ovnaction/pkg/module/workloadintent.go +++ b/src/ovnaction/pkg/module/workloadintent.go @@ -39,16 +39,17 @@ type WorkloadIntentKey struct { Project string `json:"provider"` CompositeApp string `json:"compositeapp"` CompositeAppVersion string `json:"compositeappversion"` + DigName string `json:"deploymentintentgroup"` NetControlIntent string `json:"netcontrolintent"` WorkloadIntent string `json:"workloadintent"` } // Manager is an interface exposing the WorkloadIntent functionality type WorkloadIntentManager interface { - CreateWorkloadIntent(wi WorkloadIntent, project, compositeapp, compositeappversion, netcontrolintent string, exists bool) (WorkloadIntent, error) - GetWorkloadIntent(name, project, compositeapp, compositeappversion, netcontrolintent string) (WorkloadIntent, error) - GetWorkloadIntents(project, compositeapp, compositeappversion, netcontrolintent string) ([]WorkloadIntent, error) - DeleteWorkloadIntent(name, project, compositeapp, compositeappversion, netcontrolintent string) error + CreateWorkloadIntent(wi WorkloadIntent, project, compositeapp, compositeappversion, dig, netcontrolintent string, exists bool) (WorkloadIntent, error) + GetWorkloadIntent(name, project, compositeapp, compositeappversion, dig, netcontrolintent string) (WorkloadIntent, error) + GetWorkloadIntents(project, compositeapp, compositeappversion, dig, netcontrolintent string) ([]WorkloadIntent, error) + DeleteWorkloadIntent(name, project, compositeapp, compositeappversion, dig, netcontrolintent string) error } // WorkloadIntentClient implements the Manager @@ -69,25 +70,26 @@ func NewWorkloadIntentClient() *WorkloadIntentClient { } // CreateWorkloadIntent - create a new WorkloadIntent -func (v *WorkloadIntentClient) CreateWorkloadIntent(wi WorkloadIntent, project, compositeapp, compositeappversion, netcontrolintent string, exists bool) (WorkloadIntent, error) { +func (v *WorkloadIntentClient) CreateWorkloadIntent(wi WorkloadIntent, project, compositeapp, compositeappversion, dig, netcontrolintent string, exists bool) (WorkloadIntent, error) { //Construct key and tag to select the entry key := WorkloadIntentKey{ Project: project, CompositeApp: compositeapp, CompositeAppVersion: compositeappversion, + DigName: dig, NetControlIntent: netcontrolintent, WorkloadIntent: wi.Metadata.Name, } //Check if the Network Control Intent exists - _, err := NewNetControlIntentClient().GetNetControlIntent(netcontrolintent, project, compositeapp, compositeappversion) + _, err := NewNetControlIntentClient().GetNetControlIntent(netcontrolintent, project, compositeapp, compositeappversion, dig) if err != nil { return WorkloadIntent{}, pkgerrors.Errorf("Network Control Intent %v does not exist", netcontrolintent) } //Check if this WorkloadIntent already exists - _, err = v.GetWorkloadIntent(wi.Metadata.Name, project, compositeapp, compositeappversion, netcontrolintent) + _, err = v.GetWorkloadIntent(wi.Metadata.Name, project, compositeapp, compositeappversion, dig, netcontrolintent) if err == nil && !exists { return WorkloadIntent{}, pkgerrors.New("WorkloadIntent already exists") } @@ -101,13 +103,14 @@ func (v *WorkloadIntentClient) CreateWorkloadIntent(wi WorkloadIntent, project, } // GetWorkloadIntent returns the WorkloadIntent for corresponding name -func (v *WorkloadIntentClient) GetWorkloadIntent(name, project, compositeapp, compositeappversion, netcontrolintent string) (WorkloadIntent, error) { +func (v *WorkloadIntentClient) GetWorkloadIntent(name, project, compositeapp, compositeappversion, dig, netcontrolintent string) (WorkloadIntent, error) { //Construct key and tag to select the entry key := WorkloadIntentKey{ Project: project, CompositeApp: compositeapp, CompositeAppVersion: compositeappversion, + DigName: dig, NetControlIntent: netcontrolintent, WorkloadIntent: name, } @@ -131,13 +134,14 @@ func (v *WorkloadIntentClient) GetWorkloadIntent(name, project, compositeapp, co } // GetWorkloadIntentList returns all of the WorkloadIntent for corresponding name -func (v *WorkloadIntentClient) GetWorkloadIntents(project, compositeapp, compositeappversion, netcontrolintent string) ([]WorkloadIntent, error) { +func (v *WorkloadIntentClient) GetWorkloadIntents(project, compositeapp, compositeappversion, dig, netcontrolintent string) ([]WorkloadIntent, error) { //Construct key and tag to select the entry key := WorkloadIntentKey{ Project: project, CompositeApp: compositeapp, CompositeAppVersion: compositeappversion, + DigName: dig, NetControlIntent: netcontrolintent, WorkloadIntent: "", } @@ -161,13 +165,14 @@ func (v *WorkloadIntentClient) GetWorkloadIntents(project, compositeapp, composi } // Delete the WorkloadIntent from database -func (v *WorkloadIntentClient) DeleteWorkloadIntent(name, project, compositeapp, compositeappversion, netcontrolintent string) error { +func (v *WorkloadIntentClient) DeleteWorkloadIntent(name, project, compositeapp, compositeappversion, dig, netcontrolintent string) error { //Construct key and tag to select the entry key := WorkloadIntentKey{ Project: project, CompositeApp: compositeapp, CompositeAppVersion: compositeappversion, + DigName: dig, NetControlIntent: netcontrolintent, WorkloadIntent: name, } 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 35e6c4e2..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 } @@ -252,7 +290,6 @@ Loop: break Loop } else { logutils.Info("Cluster is not reachable - keep trying::", logutils.Fields{"cluster": cluster}) - go checkReachable() } case <-ch: statusFailed := resourcestatus.ResourceStatus{ @@ -279,6 +316,7 @@ Loop: } resStateUpdated = true } + go checkReachable() break } } diff --git a/src/tools/emcoctl/cmd/utils.go b/src/tools/emcoctl/cmd/utils.go index 62b33755..5e063d12 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) >= 6 && s[5] == "network-controller-intent" { + if len(s) >= 3 && s[2] == "logical-clouds" { + baseUrl = GetDcmURL() + break + } + if len(s) >= 8 && s[7] == "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 diff --git a/src/tools/emcoctl/examples/test.yaml b/src/tools/emcoctl/examples/test.yaml index e54ff36e..f660f748 100644 --- a/src/tools/emcoctl/examples/test.yaml +++ b/src/tools/emcoctl/examples/test.yaml @@ -8,8 +8,8 @@ metadata : userData1: test1 userData2: test2 spec: - host: localhost - port: 9031 + host: rsync + port: 9041 --- #creating cluster provider @@ -33,7 +33,7 @@ metadata : userData1: test1 userData2: test2 file: - /home/otc/.kube/config + /home/vagrant/.kube/config --- #Add label cluster @@ -137,23 +137,51 @@ file: --- +#create deployment intent group +version: emco/v2 +resourceContext: + anchor: projects/proj1/composite-apps/collection-composite-app/v1/deployment-intent-groups +metadata : + name: collection-deployment-intent-group + description: "description" + userData1: test1 + userData2: test2 +spec: + profile: collection-composite-profile + version: r1 + logical-cloud: NA + override-values: [] + +--- +#create intent in deployment intent group +version: emco/v2 +resourceContext: + anchor: projects/proj1/composite-apps/collection-composite-app/v1/deployment-intent-groups/collection-deployment-intent-group/intents +metadata : + name: collection-deployment-intent + description: "description" + userData1: test1 + userData2: test2 +spec: + intent: + genericPlacementIntent: collection-placement-intent + +--- #create the generic placement intent version: emco/v2 resourceContext: - anchor: projects/proj1/composite-apps/collection-composite-app/v1/generic-placement-intents + anchor: projects/proj1/composite-apps/collection-composite-app/v1/deployment-intent-groups/collection-deployment-intent-group/generic-placement-intents metadata : name: collection-placement-intent description: "description for app" userData1: test1 userData2: test2 -spec: - logical-cloud: NA --- #add the prometheus app placement intent to the generic placement intent version: emco/v2 resourceContext: - anchor: projects/proj1/composite-apps/collection-composite-app/v1/generic-placement-intents/collection-placement-intent/app-intents + anchor: projects/proj1/composite-apps/collection-composite-app/v1/deployment-intent-groups/collection-deployment-intent-group/generic-placement-intents/collection-placement-intent/app-intents metadata: name: prometheus-placement-intent description: description of placement_intent @@ -169,7 +197,7 @@ spec: #add the prometheus app placement intent to the generic placement intent version: emco/v2 resourceContext: - anchor: projects/proj1/composite-apps/collection-composite-app/v1/generic-placement-intents/collection-placement-intent/app-intents + anchor: projects/proj1/composite-apps/collection-composite-app/v1/deployment-intent-groups/collection-deployment-intent-group/generic-placement-intents/collection-placement-intent/app-intents metadata: name: collectd-placement-intent description: description of placement_intent @@ -183,35 +211,6 @@ spec: cluster-label-name: edge-cluster --- -#create deployment intent group -version: emco/v2 -resourceContext: - anchor: projects/proj1/composite-apps/collection-composite-app/v1/deployment-intent-groups -metadata : - name: collection-deployment-intent-group - description: "description" - userData1: test1 - userData2: test2 -spec: - profile: collection-composite-profile - version: r1 - override-values: [] - ---- -#create intent in deployment intent group -version: emco/v2 -resourceContext: - anchor: projects/proj1/composite-apps/collection-composite-app/v1/deployment-intent-groups/collection-deployment-intent-group/intents -metadata : - name: collection-deployment-intent - description: "description" - userData1: test1 - userData2: test2 -spec: - intent: - genericPlacementIntent: collection-placement-intent - ---- #Approve version: emco/v2 resourceContext: diff --git a/src/tools/emcoctl/examples/vfw.yaml b/src/tools/emcoctl/examples/vfw.yaml index c84a1bab..251c892d 100644 --- a/src/tools/emcoctl/examples/vfw.yaml +++ b/src/tools/emcoctl/examples/vfw.yaml @@ -3,7 +3,7 @@ version: emco/v2 resourceContext: anchor: controllers metadata : - name: rsync + name: rsync spec: host: "192.168.121.6" port: 30546 @@ -14,10 +14,10 @@ version: emco/v2 resourceContext: anchor: controllers metadata : - name: ovnaction + name: ovnaction spec: - host: "192.168.121.6" - port: 32259 + host: "ovnaction" + port: 9053 type: "action" priority: 1 @@ -28,7 +28,7 @@ version: emco/v2 resourceContext: anchor: cluster-providers metadata : - name: vfw-cluster-provider + name: vfw-cluster-provider --- #creating cluster @@ -36,7 +36,7 @@ version: emco/v2 resourceContext: anchor: cluster-providers/vfw-cluster-provider/clusters metadata : - name: edge01 + name: edge01 file: /home/otc/.kube/config @@ -65,7 +65,7 @@ version: emco/v2 resourceContext: anchor: cluster-providers/vfw-cluster-provider/clusters/edge01/networks metadata: - name: emco-unprotected-net + name: unprotected-private-net spec: cniType: ovn4nfv ipv4Subnets: @@ -184,20 +184,52 @@ file: /opt/csar/cb009bfe-bbee-11e8-9766-525400435678/profile.tar.gz --- -#create the generic placement intent +#create deployment intent group version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/generic-placement-intents + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups metadata : - name: fw-placement-intent + name: vfw_deployment_intent_group spec: + profile: vfw_composite-profile + version: r1 logical-cloud: NA + override-values: + - app-name: packetgen + values: + ".Values.service.ports.nodePort": '30888' + - app-name: firewall + values: + ".Values.global.dcaeCollectorIp": 1.2.3.4 + ".Values.global.dcaeCollectorPort": '8888' + - app-name: sink + values: + ".Values.service.ports.nodePort": '30677' + +--- +version: emco/v2 +resourceContext: + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/intents +metadata : + name: fw-deployment-intent +spec: + intent: + genericPlacementIntent: fw-placement-intent + ovnaction: vfw_ovnaction_intent + +--- +#create the generic placement intent +version: emco/v2 +resourceContext: + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/generic-placement-intents +metadata : + name: fw-placement-intent --- #add the packetgen app placement intent to the generic placement intent version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/generic-placement-intents/fw-placement-intent/app-intents + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/generic-placement-intents/fw-placement-intent/app-intents metadata: name: packetgen-placement-intent spec: @@ -210,7 +242,7 @@ spec: #add the firewall app placement intent to the generic placement intent version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/generic-placement-intents/fw-placement-intent/app-intents + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/generic-placement-intents/fw-placement-intent/app-intents metadata: name: firewall-placement-intent spec: @@ -224,7 +256,7 @@ spec: #add the sink app placement intent to the generic placement intent version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/generic-placement-intents/fw-placement-intent/app-intents + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/generic-placement-intents/fw-placement-intent/app-intents metadata: name: sink-placement-intent spec: @@ -235,20 +267,20 @@ spec: cluster-label-name: LabelA --- -#creating cluster provider +#creating network intents version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/network-controller-intent + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/network-controller-intent metadata : - name: vfw_ovnaction_intent + name: vfw_ovnaction_intent --- # version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/network-controller-intent/vfw_ovnaction_intent/workload-intents + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/network-controller-intent/vfw_ovnaction_intent/workload-intents metadata : - name: packetgen_workload_intent + name: packetgen_workload_intent spec: application-name: packetgen workload-resource: r1-packetgen @@ -258,9 +290,9 @@ spec: # version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/network-controller-intent/vfw_ovnaction_intent/workload-intents + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/network-controller-intent/vfw_ovnaction_intent/workload-intents metadata : - name: firewall_workload_intent + name: firewall_workload_intent spec: application-name: firewall workload-resource: r1-firewall @@ -270,9 +302,9 @@ spec: # version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/network-controller-intent/vfw_ovnaction_intent/workload-intents + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/network-controller-intent/vfw_ovnaction_intent/workload-intents metadata : - name: sink_workload_intent + name: sink_workload_intent spec: application-name: sink workload-resource: r1-sink @@ -282,9 +314,9 @@ spec: # version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/network-controller-intent/vfw_ovnaction_intent/workload-intents/packetgen_workload_intent/interfaces + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/network-controller-intent/vfw_ovnaction_intent/workload-intents/packetgen_workload_intent/interfaces metadata : - name: packetgen_unprotected_if + name: packetgen_unprotected_if spec: interface: eth1 name: unprotected-private-net @@ -295,9 +327,9 @@ spec: # version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/network-controller-intent/vfw_ovnaction_intent/workload-intents/packetgen_workload_intent/interfaces + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/network-controller-intent/vfw_ovnaction_intent/workload-intents/packetgen_workload_intent/interfaces metadata : - name: packetgen_emco_if + name: packetgen_emco_if spec: interface: eth2 name: emco-private-net @@ -308,9 +340,9 @@ spec: # version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/network-controller-intent/vfw_ovnaction_intent/workload-intents/firewall_workload_intent/interfaces + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/network-controller-intent/vfw_ovnaction_intent/workload-intents/firewall_workload_intent/interfaces metadata : - name: firewall_emco_if + name: firewall_emco_if spec: interface: eth3 name: emco-private-net @@ -321,9 +353,9 @@ spec: # version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/network-controller-intent/vfw_ovnaction_intent/workload-intents/firewall_workload_intent/interfaces + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/network-controller-intent/vfw_ovnaction_intent/workload-intents/firewall_workload_intent/interfaces metadata : - name: firewall_unprotected_if + name: firewall_unprotected_if spec: interface: eth1 name: unprotected-private-net @@ -334,9 +366,9 @@ spec: # version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/network-controller-intent/vfw_ovnaction_intent/workload-intents/firewall_workload_intent/interfaces + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/network-controller-intent/vfw_ovnaction_intent/workload-intents/firewall_workload_intent/interfaces metadata : - name: firewall_protected_if + name: firewall_protected_if spec: interface: eth2 name: protected-private-net @@ -347,9 +379,9 @@ spec: # version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/network-controller-intent/vfw_ovnaction_intent/workload-intents/sink_workload_intent/interfaces + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/network-controller-intent/vfw_ovnaction_intent/workload-intents/sink_workload_intent/interfaces metadata : - name: sink_protected_if + name: sink_protected_if spec: interface: eth1 name: protected-private-net @@ -360,9 +392,9 @@ spec: # version: emco/v2 resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/network-controller-intent/vfw_ovnaction_intent/workload-intents/sink_workload_intent/interfaces + anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/network-controller-intent/vfw_ovnaction_intent/workload-intents/sink_workload_intent/interfaces metadata : - name: sink_emco_if + name: sink_emco_if spec: interface: eth2 name: emco-private-net @@ -370,39 +402,6 @@ spec: ipAddress: 10.10.20.4 --- -#create deployment intent group -version: emco/v2 -resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups -metadata : - name: vfw_deployment_intent_group -spec: - profile: vfw_composite-profile - version: r1 - override-values: - - app-name: packetgen - values: - ".Values.service.ports.nodePort": '30888' - - app-name: firewall - values: - ".Values.global.dcaeCollectorIp": 1.2.3.4 - ".Values.global.dcaeCollectorPort": '8888' - - app-name: sink - values: - ".Values.service.ports.nodePort": '30677' - ---- -version: emco/v2 -resourceContext: - anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/intents -metadata : - name: fw-deployment-intent -spec: - intent: - genericPlacementIntent: fw-placement-intent - ovnaction: vfw_ovnaction_intent - ---- version: emco/v2 resourceContext: anchor: projects/testvfw/composite-apps/compositevfw/v1/deployment-intent-groups/vfw_deployment_intent_group/approve |