summaryrefslogtreecommitdiffstats
path: root/src/dcm
diff options
context:
space:
mode:
Diffstat (limited to 'src/dcm')
-rw-r--r--src/dcm/api/api.go4
-rw-r--r--src/dcm/api/clusterHandler.go10
-rw-r--r--src/dcm/api/keyValueHandler.go10
-rw-r--r--src/dcm/api/logicalCloudHandler.go75
-rw-r--r--src/dcm/api/quotaHandler.go10
-rw-r--r--src/dcm/api/userPermissionsHandler.go12
-rw-r--r--src/dcm/config.json14
-rw-r--r--src/dcm/go.mod2
-rw-r--r--src/dcm/pkg/module/apply.go268
-rw-r--r--src/dcm/pkg/module/cluster.go9
-rw-r--r--src/dcm/pkg/module/keyvalue.go4
-rw-r--r--src/dcm/pkg/module/logicalcloud.go53
-rw-r--r--src/dcm/pkg/module/logicalcloud_test.go16
-rw-r--r--src/dcm/pkg/module/quota.go10
-rw-r--r--src/dcm/pkg/module/userpermissions.go4
15 files changed, 448 insertions, 53 deletions
diff --git a/src/dcm/api/api.go b/src/dcm/api/api.go
index de1d5c97..0f68a517 100644
--- a/src/dcm/api/api.go
+++ b/src/dcm/api/api.go
@@ -44,6 +44,7 @@ func NewRouter(
quotaClient = module.NewQuotaClient()
}
+ // Set up Logical Cloud API
logicalCloudHandler := logicalCloudHandler{client: logicalCloudClient,
clusterClient: clusterClient,
quotaClient: quotaClient,
@@ -67,6 +68,9 @@ func NewRouter(
lcRouter.HandleFunc(
"/logical-clouds/{logical-cloud-name}/apply",
logicalCloudHandler.applyHandler).Methods("POST")
+ lcRouter.HandleFunc(
+ "/logical-clouds/{logical-cloud-name}/terminate",
+ logicalCloudHandler.terminateHandler).Methods("POST")
// To Do
// get kubeconfig
/*lcRouter.HandleFunc(
diff --git a/src/dcm/api/clusterHandler.go b/src/dcm/api/clusterHandler.go
index f4a3abdc..d0c1e62c 100644
--- a/src/dcm/api/clusterHandler.go
+++ b/src/dcm/api/clusterHandler.go
@@ -91,6 +91,10 @@ func (h clusterHandler) getHandler(w http.ResponseWriter, r *http.Request) {
} 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)
return
}
@@ -131,12 +135,16 @@ func (h clusterHandler) updateHandler(w http.ResponseWriter, r *http.Request) {
ret, err := h.client.UpdateCluster(project, logicalCloud, name, v)
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")
- w.WriteHeader(http.StatusCreated)
+ w.WriteHeader(http.StatusOK)
err = json.NewEncoder(w).Encode(ret)
if err != nil {
http.Error(w, err.Error(),
diff --git a/src/dcm/api/keyValueHandler.go b/src/dcm/api/keyValueHandler.go
index c67504f2..a4a4f14a 100644
--- a/src/dcm/api/keyValueHandler.go
+++ b/src/dcm/api/keyValueHandler.go
@@ -90,6 +90,10 @@ func (h keyValueHandler) getHandler(w http.ResponseWriter, r *http.Request) {
} 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)
return
}
@@ -130,12 +134,16 @@ func (h keyValueHandler) updateHandler(w http.ResponseWriter, r *http.Request) {
ret, err := h.client.UpdateKVPair(project, logicalCloud, name, v)
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")
- w.WriteHeader(http.StatusCreated)
+ w.WriteHeader(http.StatusOK)
err = json.NewEncoder(w).Encode(ret)
if err != nil {
http.Error(w, err.Error(),
diff --git a/src/dcm/api/logicalCloudHandler.go b/src/dcm/api/logicalCloudHandler.go
index d9a3e5f5..fb0f0c63 100644
--- a/src/dcm/api/logicalCloudHandler.go
+++ b/src/dcm/api/logicalCloudHandler.go
@@ -25,6 +25,7 @@ import (
"github.com/gorilla/mux"
"github.com/onap/multicloud-k8s/src/dcm/pkg/module"
+ pkgerrors "github.com/pkg/errors"
)
// logicalCloudHandler is used to store backend implementations objects
@@ -91,6 +92,10 @@ func (h logicalCloudHandler) getHandler(w http.ResponseWriter, r *http.Request)
} 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)
return
}
@@ -129,6 +134,10 @@ func (h logicalCloudHandler) updateHandler(w http.ResponseWriter, r *http.Reques
ret, err := h.client.Update(project, name, v)
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
@@ -150,6 +159,10 @@ func (h logicalCloudHandler) deleteHandler(w http.ResponseWriter, r *http.Reques
err := h.client.Delete(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
}
@@ -165,14 +178,29 @@ func (h logicalCloudHandler) applyHandler(w http.ResponseWriter, r *http.Request
// Get logical cloud
lc, err := h.client.Get(project, name)
if err != nil {
+ if err.Error() == "Logical Cloud does not exist" {
+ http.Error(w, err.Error(), http.StatusNotFound)
+ return
+ }
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
+ _, ctxVal, err := h.client.GetLogicalCloudContext(name)
+ if ctxVal != "" {
+ err = pkgerrors.New("Logical Cloud already applied")
+ http.Error(w, err.Error(), http.StatusConflict)
+ return
+ }
+
// Get Clusters
clusters, err := h.clusterClient.GetAllClusters(project, name)
if err != nil {
+ if err.Error() == "No Cluster References associated" {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -192,3 +220,50 @@ func (h logicalCloudHandler) applyHandler(w http.ResponseWriter, r *http.Request
return
}
+
+func (h logicalCloudHandler) terminateHandler(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ project := vars["project-name"]
+ name := vars["logical-cloud-name"]
+
+ // Get logical cloud
+ lc, err := h.client.Get(project, name)
+ if err != nil {
+ if err.Error() == "Logical Cloud does not exist" {
+ http.Error(w, err.Error(), http.StatusNotFound)
+ return
+ }
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ _, ctxVal, err := h.client.GetLogicalCloudContext(name)
+ if ctxVal == "" {
+ err = pkgerrors.New("Logical Cloud hasn't been applied yet")
+ http.Error(w, err.Error(), http.StatusConflict)
+ return
+ }
+
+ // Get Clusters
+ clusters, err := h.clusterClient.GetAllClusters(project, name)
+
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ //Get Quotas
+ quotas, err := h.quotaClient.GetAllQuotas(project, name)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ err = module.DestroyEtcdContext(lc, clusters, quotas)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ return
+}
diff --git a/src/dcm/api/quotaHandler.go b/src/dcm/api/quotaHandler.go
index deb18e18..fd9b40f8 100644
--- a/src/dcm/api/quotaHandler.go
+++ b/src/dcm/api/quotaHandler.go
@@ -91,6 +91,10 @@ func (h quotaHandler) getHandler(w http.ResponseWriter, r *http.Request) {
} 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)
return
}
@@ -131,12 +135,16 @@ func (h quotaHandler) updateHandler(w http.ResponseWriter, r *http.Request) {
ret, err := h.client.UpdateQuota(project, logicalCloud, name, v)
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")
- w.WriteHeader(http.StatusCreated)
+ w.WriteHeader(http.StatusOK)
err = json.NewEncoder(w).Encode(ret)
if err != nil {
http.Error(w, err.Error(),
diff --git a/src/dcm/api/userPermissionsHandler.go b/src/dcm/api/userPermissionsHandler.go
index 156c390f..3ac955fa 100644
--- a/src/dcm/api/userPermissionsHandler.go
+++ b/src/dcm/api/userPermissionsHandler.go
@@ -89,8 +89,12 @@ func (h userPermissionHandler) getHandler(w http.ResponseWriter, r *http.Request
return
}
} else {
- ret, err = h.client.GetAllUserPerms(project, logicalCloud)
+ 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
}
@@ -131,12 +135,16 @@ func (h userPermissionHandler) updateHandler(w http.ResponseWriter, r *http.Requ
ret, err := h.client.UpdateUserPerm(project, logicalCloud, name, v)
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")
- w.WriteHeader(http.StatusCreated)
+ w.WriteHeader(http.StatusOK)
err = json.NewEncoder(w).Encode(ret)
if err != nil {
http.Error(w, err.Error(),
diff --git a/src/dcm/config.json b/src/dcm/config.json
new file mode 100644
index 00000000..65a18acb
--- /dev/null
+++ b/src/dcm/config.json
@@ -0,0 +1,14 @@
+{
+ "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": "",
+ "etcd-ip": "172.18.0.3",
+ "etcd-cert": "",
+ "etcd-key": "",
+ "etcd-ca-file": ""
+}
diff --git a/src/dcm/go.mod b/src/dcm/go.mod
index 35f64d80..1f04ac12 100644
--- a/src/dcm/go.mod
+++ b/src/dcm/go.mod
@@ -8,6 +8,8 @@ require (
github.com/russross/blackfriday/v2 v2.0.1
github.com/stretchr/testify v1.5.1
gopkg.in/yaml.v2 v2.2.8
+ k8s.io/api v0.18.2
+ k8s.io/apimachinery v0.18.2
k8s.io/kubernetes v1.16.9
)
diff --git a/src/dcm/pkg/module/apply.go b/src/dcm/pkg/module/apply.go
index dbcbf8ac..a866934a 100644
--- a/src/dcm/pkg/module/apply.go
+++ b/src/dcm/pkg/module/apply.go
@@ -28,11 +28,20 @@ import (
"strings"
"github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext"
+ "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext/subresources"
+ "github.com/onap/multicloud-k8s/src/orchestrator/pkg/grpc/installappclient"
+ "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db"
log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils"
+ "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module/controller"
pkgerrors "github.com/pkg/errors"
"gopkg.in/yaml.v2"
+ certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
+// rsyncName denotes the name of the rsync controller
+const rsyncName = "rsync"
+
type Resource struct {
ApiVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
@@ -51,8 +60,10 @@ type MetaDatas struct {
type Specs struct {
Request string `yaml:"request,omitempty"`
Usages []string `yaml:"usages,omitempty"`
- //Hard logicalcloud.QSpec `yaml:"hard,omitempty"`
- Hard QSpec `yaml:"hard,omitempty"`
+ // TODO: validate quota keys
+ // //Hard logicalcloud.QSpec `yaml:"hard,omitempty"`
+ // Hard QSpec `yaml:"hard,omitempty"`
+ Hard map[string]string `yaml:"hard,omitempty"`
}
type RoleRules struct {
@@ -147,12 +158,10 @@ func createRoleBinding(logicalcloud LogicalCloud) (string, error) {
}
return string(rBData), nil
-
}
func createQuota(quota []Quota, namespace string) (string, error) {
lcQuota := quota[0]
-
q := Resource{
ApiVersion: "v1",
Kind: "ResourceQuota",
@@ -171,23 +180,22 @@ func createQuota(quota []Quota, namespace string) (string, error) {
}
return string(qData), nil
-
}
-func createUserCSR(logicalcloud LogicalCloud) (string, error) {
+func createUserCSR(logicalcloud LogicalCloud) (string, string, error) {
KEYSIZE := 4096
userName := logicalcloud.Specification.User.UserName
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
@@ -200,8 +208,8 @@ func createUserCSR(logicalcloud LogicalCloud) (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: strings.Join([]string{logicalcloud.MetaData.LogicalCloudName, "-user-csr"}, ""),
+ // Namespace: logicalcloud.Specification.NameSpace,
},
Specification: Specs{
Request: base64.StdEncoding.EncodeToString(csr),
@@ -211,27 +219,98 @@ func createUserCSR(logicalcloud LogicalCloud) (string, error) {
csrData, err := yaml.Marshal(&csrObj)
if err != nil {
- return "", err
+ return "", "", err
}
- return string(csrData), nil
+ keyData := base64.StdEncoding.EncodeToString(pem.EncodeToMemory(
+ &pem.Block{
+ Type: "RSA PRIVATE KEY",
+ Bytes: x509.MarshalPKCS1PrivateKey(key),
+ },
+ ))
+ if err != nil {
+ return "", "", err
+ }
+ return string(csrData), string(keyData), nil
}
-// TODO:
-// Install istio
-// Store user key for user creation
-// Code to run kubectl commands for user
-// kubectl certificate approve lc1-user-cert
-// kubectl get csr lc1-user-cert -o jsonpath='{.status.certificate}' | base64 --decode > user.crt
-// kubectl config set-credentials user --client-certificate=<user.crt> --client-key=<user.key>
-// kubectl config set-context user-context --cluster=cluster-name --namespace=lc1 --user=user
+func createApprovalSubresource(logicalcloud LogicalCloud) (string, error) {
+ subresource := subresources.ApprovalSubresource{
+ Message: "Approved for Logical Cloud authentication",
+ Reason: "LogicalCloud",
+ Type: string(certificatesv1beta1.CertificateApproved),
+ LastUpdateTime: metav1.Now().Format("2006-01-02T15:04:05Z"),
+ }
+ csrData, err := json.Marshal(subresource)
+ return string(csrData), err
+}
+
+/*
+queryDBAndSetRsyncInfo queries the MCO db to find the record the sync controller
+and then sets the RsyncInfo global variable.
+*/
+func queryDBAndSetRsyncInfo() (installappclient.RsyncInfo, error) {
+ client := controller.NewControllerClient()
+ vals, _ := client.GetControllers()
+ for _, v := range vals {
+ if v.Metadata.Name == rsyncName {
+ log.Info("Initializing RPC connection to resource synchronizer", log.Fields{
+ "Controller": v.Metadata.Name,
+ })
+ rsyncInfo := installappclient.NewRsyncInfo(v.Metadata.Name, v.Spec.Host, v.Spec.Port)
+ return rsyncInfo, nil
+ }
+ }
+ return installappclient.RsyncInfo{}, pkgerrors.Errorf("queryRsyncInfoInMCODB Failed - Could not get find rsync by name : %v", rsyncName)
+}
+
+/*
+callRsyncInstall method shall take in the app context id and invokes the rsync service via grpc
+*/
+func callRsyncInstall(contextid interface{}) error {
+ rsyncInfo, err := queryDBAndSetRsyncInfo()
+ log.Info("Calling the Rsync ", log.Fields{
+ "RsyncName": rsyncInfo.RsyncName,
+ })
+ if err != nil {
+ return err
+ }
+
+ appContextID := fmt.Sprintf("%v", contextid)
+ err = installappclient.InvokeInstallApp(appContextID)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+/*
+callRsyncUninstall method shall take in the app context id and invokes the rsync service via grpc
+*/
+func callRsyncUninstall(contextid interface{}) error {
+ rsyncInfo, err := queryDBAndSetRsyncInfo()
+ log.Info("Calling the Rsync ", log.Fields{
+ "RsyncName": rsyncInfo.RsyncName,
+ })
+ if err != nil {
+ return err
+ }
+
+ appContextID := fmt.Sprintf("%v", contextid)
+ err = installappclient.InvokeUninstallApp(appContextID)
+ if err != nil {
+ return err
+ }
+ return nil
+}
func CreateEtcdContext(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"}, "")
@@ -261,11 +340,13 @@ func CreateEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster,
return pkgerrors.Wrap(err, "Error Creating Quota YAML for logical cloud")
}
- csr, err := createUserCSR(logicalcloud)
+ csr, key, err := createUserCSR(logicalcloud)
if err != nil {
- return pkgerrors.Wrap(err, "Error Creating User CSR for logical cloud")
+ return pkgerrors.Wrap(err, "Error Creating User CSR and Key for logical cloud")
}
+ approval, err := createApprovalSubresource(logicalcloud)
+
context := appcontext.AppContext{}
ctxVal, err := context.InitAppContext()
if err != nil {
@@ -322,7 +403,7 @@ func CreateEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster,
}
// Add csr resource to each cluster
- _, err = context.AddResource(clusterHandle, csrName, csr)
+ csrHandle, err := context.AddResource(clusterHandle, csrName, csr)
if err != nil {
cleanuperr := context.DeleteCompositeApp()
if cleanuperr != nil {
@@ -335,6 +416,36 @@ func CreateEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster,
return pkgerrors.Wrap(err, "Error adding CSR Resource to AppContext")
}
+ // 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")
+ }
+
+ // 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")
+ }
+
// Add Role resource to each cluster
_, err = context.AddResource(clusterHandle, roleName, role)
if err != nil {
@@ -377,16 +488,29 @@ func CreateEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster,
return pkgerrors.Wrap(err, "Error adding quota Resource to AppContext")
}
+ // Add Subresource Order and Subresource Dependency
+ subresOrder, err := json.Marshal(map[string][]string{"subresorder": []string{"approval"}})
+ if err != nil {
+ return pkgerrors.Wrap(err, "Error creating subresource order JSON")
+ }
+ subresDependency, err := json.Marshal(map[string]map[string]string{"subresdependency": map[string]string{"approval": "go"}})
+
// Add Resource Order and Resource Dependency
resOrder, err := json.Marshal(map[string][]string{"resorder": []string{namespaceName, quotaName, csrName, roleName, roleBindingName}})
if err != nil {
return pkgerrors.Wrap(err, "Error creating resource order JSON")
}
-
resDependency, err := json.Marshal(map[string]map[string]string{"resdependency": map[string]string{namespaceName: "go",
quotaName: strings.Join([]string{"wait on ", namespaceName}, ""), csrName: strings.Join([]string{"wait on ", quotaName}, ""),
roleName: strings.Join([]string{"wait on ", csrName}, ""), roleBindingName: strings.Join([]string{"wait on ", roleName}, "")}})
+ // Add App Order and App Dependency
+ appOrder, err := json.Marshal(map[string][]string{"apporder": []string{APP}})
+ if err != nil {
+ 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")
}
@@ -417,8 +541,104 @@ func CreateEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster,
return pkgerrors.Wrap(err, "Error adding instruction dependency to AppContext")
}
+ _, 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")
+ }
+
+ _, 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")
+ }
+
+ // Add App-level Order and Dependency
+ _, err = context.AddInstruction(handle, "app", "order", string(appOrder))
+ _, err = context.AddInstruction(handle, "app", "dependency", string(appDependency))
+ }
+ // 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")
+ }
+
+ // call resource synchronizer to instantiate the CRs in the cluster
+ err = callRsyncInstall(ctxVal)
+ if err != nil {
+ return err
}
return nil
}
+
+// TODO: rename these methods
+// DestroyEtcdContext remove from rsync then delete appcontext and all resources
+func DestroyEtcdContext(logicalcloud LogicalCloud, clusterList []Cluster,
+ quotaList []Quota) error {
+
+ logicalCloudName := logicalcloud.MetaData.LogicalCloudName
+ // project := "test-project" // FIXME(igordc): temporary, need to do some rework in the LC structs
+
+ _, ctxVal, err := NewLogicalCloudClient().GetLogicalCloudContext(logicalCloudName)
+ if err != nil {
+ return pkgerrors.Wrapf(err, "Error finding AppContext for Logical Cloud: %v", logicalCloudName)
+ }
+
+ // call resource synchronizer to delete the CRs from every cluster of the logical cloud
+ err = callRsyncUninstall(ctxVal)
+ if err != nil {
+ return err
+ }
+
+ // TODO: status handling for logical cloud after terminate:
+ // rsync updates the status of the appcontext to Terminated
+ // dcm should launch thread to observe status of appcontext before concluding logical cloud is terminated
+ // dcm should somewhat mimic the status tracking of rsync
+ // logical cloud might be in a non-applied non-terminated state for a long period of time.........
+
+ // // remove the app context
+ // err = context.DeleteCompositeApp()
+ // if err != nil {
+ // return pkgerrors.Wrap(err, "Error deleting AppContext CompositeApp")
+ // }
+
+ // remove the app context field from the cluster db record
+ // lckey := LogicalCloudKey{
+ // LogicalCloudName: logicalcloud.MetaData.LogicalCloudName,
+ // Project: project,
+ // }
+ // err = db.DBconn.RemoveTag("orchestrator", lckey, "lccontext")
+ // if err != nil {
+ // log.Warn("Error removing AppContext from Logical Cloud", log.Fields{
+ // "logical-cloud": logicalCloudName,
+ // })
+ // }
+
+ return nil
+}
diff --git a/src/dcm/pkg/module/cluster.go b/src/dcm/pkg/module/cluster.go
index 206d79a6..85b20117 100644
--- a/src/dcm/pkg/module/cluster.go
+++ b/src/dcm/pkg/module/cluster.go
@@ -133,7 +133,7 @@ func (v *ClusterClient) GetCluster(project, logicalCloud, clusterReference strin
return cl, nil
}
- return Cluster{}, pkgerrors.New("Error getting Cluster")
+ return Cluster{}, pkgerrors.New("Cluster Reference does not exist")
}
// GetAll returns all cluster references in the logical cloud
@@ -149,6 +149,9 @@ func (v *ClusterClient) GetAllClusters(project, logicalCloud string) ([]Cluster,
if err != nil {
return []Cluster{}, pkgerrors.Wrap(err, "Get All Cluster references")
}
+ if len(values) == 0 {
+ return []Cluster{}, pkgerrors.New("No Cluster References associated")
+ }
for _, value := range values {
cl := Cluster{}
@@ -188,12 +191,12 @@ func (v *ClusterClient) UpdateCluster(project, logicalCloud, clusterReference st
//Check for name mismatch in cluster reference
if c.MetaData.ClusterReference != clusterReference {
- return Cluster{}, pkgerrors.New("Update Error - Cluster reference mismatch")
+ return Cluster{}, pkgerrors.New("Cluster Reference mismatch")
}
//Check if this Cluster reference exists
_, err := v.GetCluster(project, logicalCloud, clusterReference)
if err != nil {
- return Cluster{}, pkgerrors.New("Update Error - Cluster reference doesn't exist")
+ return Cluster{}, pkgerrors.New("Cluster Reference does not exist")
}
err = v.util.DBInsert(v.storeName, key, nil, v.tagMeta, c)
if err != nil {
diff --git a/src/dcm/pkg/module/keyvalue.go b/src/dcm/pkg/module/keyvalue.go
index 37c74a84..0127a6f4 100644
--- a/src/dcm/pkg/module/keyvalue.go
+++ b/src/dcm/pkg/module/keyvalue.go
@@ -133,7 +133,7 @@ func (v *KeyValueClient) GetKVPair(project, logicalCloud, kvPairName string) (Ke
return kv, nil
}
- return KeyValue{}, pkgerrors.New("Error getting Key Value")
+ return KeyValue{}, pkgerrors.New("Key Value does not exist")
}
// Get All lists all key value pairs
@@ -194,7 +194,7 @@ func (v *KeyValueClient) UpdateKVPair(project, logicalCloud, kvPairName string,
//Check if this Key Value exists
_, err := v.GetKVPair(project, logicalCloud, kvPairName)
if err != nil {
- return KeyValue{}, pkgerrors.New("Update Error - Key Value Pair doesn't exist")
+ return KeyValue{}, pkgerrors.New("KV Pair does not exist")
}
err = v.util.DBInsert(v.storeName, key, nil, v.tagMeta, c)
if err != nil {
diff --git a/src/dcm/pkg/module/logicalcloud.go b/src/dcm/pkg/module/logicalcloud.go
index 51ee387d..61d7b7a5 100644
--- a/src/dcm/pkg/module/logicalcloud.go
+++ b/src/dcm/pkg/module/logicalcloud.go
@@ -17,6 +17,7 @@
package module
import (
+ "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext"
"github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db"
"github.com/onap/multicloud-k8s/src/orchestrator/pkg/module"
@@ -72,6 +73,7 @@ type LogicalCloudManager interface {
GetAll(project string) ([]LogicalCloud, error)
Delete(project, name string) error
Update(project, name string, c LogicalCloud) (LogicalCloud, error)
+ GetLogicalCloudContext(name string) (appcontext.AppContext, string, error)
}
// Interface facilitates unit testing by mocking functions
@@ -87,9 +89,10 @@ type Utility interface {
// LogicalCloudClient implements the LogicalCloudManager
// It will also be used to maintain some localized state
type LogicalCloudClient struct {
- storeName string
- tagMeta string
- util Utility
+ storeName string
+ tagMeta string
+ tagContext string
+ util Utility
}
// Added for unit testing; implements Utility interface
@@ -145,7 +148,7 @@ func (v *LogicalCloudClient) Get(project, logicalCloudName string) (LogicalCloud
}
value, err := v.util.DBFind(v.storeName, key, v.tagMeta)
if err != nil {
- return LogicalCloud{}, pkgerrors.Wrap(err, "Get Logical Cloud")
+ return LogicalCloud{}, pkgerrors.Wrap(err, "Error getting Logical Cloud")
}
//value is a byte array
@@ -153,12 +156,12 @@ func (v *LogicalCloudClient) Get(project, logicalCloudName string) (LogicalCloud
lc := LogicalCloud{}
err = v.util.DBUnmarshal(value[0], &lc)
if err != nil {
- return LogicalCloud{}, pkgerrors.Wrap(err, "Unmarshaling value")
+ return LogicalCloud{}, pkgerrors.Wrap(err, "Error unmarshaling value")
}
return lc, nil
}
- return LogicalCloud{}, pkgerrors.New("Error getting Logical Cloud")
+ return LogicalCloud{}, pkgerrors.New("Logical Cloud does not exist")
}
// GetAll returns Logical Clouds in the project
@@ -196,7 +199,12 @@ func (v *LogicalCloudClient) Delete(project, logicalCloudName string) error {
Project: project,
LogicalCloudName: logicalCloudName,
}
- err := v.util.DBRemove(v.storeName, key)
+ //Check if this Logical Cloud exists
+ _, err := v.Get(project, logicalCloudName)
+ if err != nil {
+ return pkgerrors.New("Logical Cloud does not exist")
+ }
+ err = v.util.DBRemove(v.storeName, key)
if err != nil {
return pkgerrors.Wrap(err, "Delete Logical Cloud")
}
@@ -213,12 +221,12 @@ func (v *LogicalCloudClient) Update(project, logicalCloudName string, c LogicalC
}
// Check for mismatch, logicalCloudName and payload logical cloud name
if c.MetaData.LogicalCloudName != logicalCloudName {
- return LogicalCloud{}, pkgerrors.New("Update Error - Logical Cloud name mismatch")
+ return LogicalCloud{}, pkgerrors.New("Logical Cloud name mismatch")
}
//Check if this Logical Cloud exists
_, err := v.Get(project, logicalCloudName)
if err != nil {
- return LogicalCloud{}, pkgerrors.New("Update Error - Logical Cloud doesn't exist")
+ return LogicalCloud{}, pkgerrors.New("Logical Cloud does not exist")
}
err = v.util.DBInsert(v.storeName, key, nil, v.tagMeta, c)
if err != nil {
@@ -227,6 +235,33 @@ func (v *LogicalCloudClient) Update(project, logicalCloudName string, c LogicalC
return c, nil
}
+// GetClusterContext returns the AppContext for corresponding provider and name
+func (v *LogicalCloudClient) GetLogicalCloudContext(name string) (appcontext.AppContext, string, error) {
+ //Construct key and tag to select the entry
+ key := LogicalCloudKey{
+ LogicalCloudName: name,
+ Project: "test-project", // FIXME(igordc): temporary, need to do some rework in the LC structs
+ }
+
+ value, err := db.DBconn.Find(v.storeName, key, v.tagContext)
+ if err != nil {
+ return appcontext.AppContext{}, "", pkgerrors.Wrap(err, "Get Logical Cloud Context")
+ }
+
+ //value is a byte array
+ if value != nil {
+ ctxVal := string(value[0])
+ var lcc appcontext.AppContext
+ _, err = lcc.LoadAppContext(ctxVal)
+ if err != nil {
+ return appcontext.AppContext{}, "", pkgerrors.Wrap(err, "Reinitializing Logical Cloud AppContext")
+ }
+ return lcc, ctxVal, nil
+ }
+
+ return appcontext.AppContext{}, "", pkgerrors.New("Error getting Logical Cloud AppContext")
+}
+
func (d DBService) DBInsert(storeName string, key db.Key, query interface{}, meta string, c interface{}) error {
err := db.DBconn.Insert(storeName, key, nil, meta, c)
diff --git a/src/dcm/pkg/module/logicalcloud_test.go b/src/dcm/pkg/module/logicalcloud_test.go
index fb205753..4700eff0 100644
--- a/src/dcm/pkg/module/logicalcloud_test.go
+++ b/src/dcm/pkg/module/logicalcloud_test.go
@@ -78,7 +78,7 @@ func TestCreateLogicalCloud(t *testing.T) {
myMocks.On("DBInsert", "test_dcm", key, nil, "test_meta", lc).Return(nil)
myMocks.On("DBFind", "test_dcm", key, "test_meta").Return(data1, err1)
- lcClient := LogicalCloudClient{"test_dcm", "test_meta", myMocks}
+ lcClient := LogicalCloudClient{"test_dcm", "test_meta", "test_context", myMocks}
_, err := lcClient.Create("test_project", lc)
if err != nil {
t.Errorf("Some error occured!")
@@ -101,7 +101,7 @@ func TestGetLogicalCloud(t *testing.T) {
myMocks.On("DBFind", "test_dcm", key, "test_meta").Return(data1, nil)
myMocks.On("DBUnmarshal", data2).Return(nil)
- lcClient := LogicalCloudClient{"test_dcm", "test_meta", myMocks}
+ lcClient := LogicalCloudClient{"test_dcm", "test_meta", "test_context", myMocks}
_, err := lcClient.Get("test_project", "test_asdf")
if err != nil {
t.Errorf("Some error occured!")
@@ -117,9 +117,17 @@ func TestDeleteLogicalCloud(t *testing.T) {
myMocks := new(mockValues)
+ data1 := [][]byte{
+ []byte("abc"),
+ }
+ data2 := []byte("abc")
+
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)
+ // TODO also test for when the logical cloud doesn't exist
- lcClient := LogicalCloudClient{"test_dcm", "test_meta", myMocks}
+ lcClient := LogicalCloudClient{"test_dcm", "test_meta", "test_context", myMocks}
err := lcClient.Delete("test_project", "test_asdf")
if err != nil {
t.Errorf("Some error occured!")
@@ -148,7 +156,7 @@ func TestUpdateLogicalCloud(t *testing.T) {
myMocks.On("DBInsert", "test_dcm", key, nil, "test_meta", lc).Return(nil)
myMocks.On("DBFind", "test_dcm", key, "test_meta").Return(data1, nil)
myMocks.On("DBUnmarshal", data2).Return(nil)
- lcClient := LogicalCloudClient{"test_dcm", "test_meta", myMocks}
+ lcClient := LogicalCloudClient{"test_dcm", "test_meta", "test_context", myMocks}
_, err := lcClient.Update("test_project", "test_asdf", lc)
if err != nil {
t.Errorf("Some error occured!")
diff --git a/src/dcm/pkg/module/quota.go b/src/dcm/pkg/module/quota.go
index cbd9c8b7..c961fdfc 100644
--- a/src/dcm/pkg/module/quota.go
+++ b/src/dcm/pkg/module/quota.go
@@ -22,8 +22,9 @@ import (
// Quota contains the parameters needed for a Quota
type Quota struct {
- MetaData QMetaDataList `json:"metadata"`
- Specification QSpec `json:"spec"`
+ MetaData QMetaDataList `json:"metadata"`
+ // Specification QSpec `json:"spec"`
+ Specification map[string]string `json:"spec"`
}
// MetaData contains the parameters needed for metadata
@@ -32,6 +33,7 @@ type QMetaDataList struct {
Description string `json:"description"`
}
+// TODO: use QSpec fields to validate quota keys
// Spec contains the parameters needed for spec
type QSpec struct {
LimitsCPU string `json:"limits.cpu"`
@@ -152,7 +154,7 @@ func (v *QuotaClient) GetQuota(project, logicalCloud, quotaName string) (Quota,
return q, nil
}
- return Quota{}, pkgerrors.New("Error getting Quota")
+ return Quota{}, pkgerrors.New("Cluster Quota does not exist")
}
// GetAll returns all cluster quotas in the logical cloud
@@ -211,7 +213,7 @@ func (v *QuotaClient) UpdateQuota(project, logicalCloud, quotaName string, c Quo
//Check if this Quota exists
_, err := v.GetQuota(project, logicalCloud, quotaName)
if err != nil {
- return Quota{}, pkgerrors.New("Update Error - Quota doesn't exist")
+ return Quota{}, pkgerrors.New("Cluster Quota does not exist")
}
err = v.util.DBInsert(v.storeName, key, nil, v.tagMeta, c)
if err != nil {
diff --git a/src/dcm/pkg/module/userpermissions.go b/src/dcm/pkg/module/userpermissions.go
index 2cff712b..4c918f0f 100644
--- a/src/dcm/pkg/module/userpermissions.go
+++ b/src/dcm/pkg/module/userpermissions.go
@@ -124,7 +124,7 @@ func (v *UserPermissionClient) GetUserPerm(project, logicalCloud, userPermName s
return up, nil
}
- return UserPermission{}, pkgerrors.New("Error getting User Permission")
+ return UserPermission{}, pkgerrors.New("User Permission does not exist")
}
// GetAll lists all user permissions
@@ -184,7 +184,7 @@ func (v *UserPermissionClient) UpdateUserPerm(project, logicalCloud, userPermNam
_, err := v.GetUserPerm(project, logicalCloud, userPermName)
if err != nil {
return UserPermission{}, pkgerrors.New(
- "Update Error - User Permission doesn't exist")
+ "User Permission does not exist")
}
err = v.util.DBInsert(v.storeName, key, nil, v.tagMeta, c)
if err != nil {