Add StateInfo structure synced resources 67/110467/6
authorEric Multanen <eric.w.multanen@intel.com>
Wed, 22 Jul 2020 21:11:05 +0000 (14:11 -0700)
committerEric Multanen <eric.w.multanen@intel.com>
Mon, 3 Aug 2020 22:40:09 +0000 (15:40 -0700)
Add a StateInfo structure to the Cluster and
Deployment-Intent-Group resources to keep track of
the lifecycle state of these resources.  Moved the
appcontext id that was being kept into this structure
as well.  Enabled the approve state (and API) for
the deployment intent group.

Issue-ID: MULTICLOUD-1042
Signed-off-by: Eric Multanen <eric.w.multanen@intel.com>
Change-Id: I36602d8a0658d9d6d37b8799f9a372a7d1042496

20 files changed:
docs/emco_apis.yaml
kud/tests/m3db-operator-test.sh
kud/tests/plugin_collection_v2.sh
kud/tests/prometheus-test.sh
kud/tests/sanity-check-for-v2.sh
kud/tests/vfw-test.sh
src/clm/api/clusterhandler_test.go
src/clm/go.mod
src/clm/pkg/cluster/cluster.go
src/ncm/pkg/module/types/module_definitions.go
src/ncm/pkg/networkintents/network.go
src/ncm/pkg/networkintents/providernet.go
src/ncm/pkg/scheduler/scheduler.go
src/orchestrator/api/api.go
src/orchestrator/api/instantiation_handler.go
src/orchestrator/go.mod
src/orchestrator/pkg/module/deployment_intent_groups.go
src/orchestrator/pkg/module/instantiation.go
src/orchestrator/pkg/state/state_helper.go [new file with mode: 0644]
src/orchestrator/pkg/state/types.go [new file with mode: 0644]

index 643ac7b..419c131 100644 (file)
@@ -1284,7 +1284,7 @@ paths:
       requestBody:
         content: {}
 
-  /projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/destroy:
+  /projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/terminate:
     parameters:
       - $ref: '#/components/parameters/projectName'
       - $ref: '#/components/parameters/compositeAppName'
@@ -1293,9 +1293,9 @@ paths:
     post:
       tags:
         - Deployment Lifecycle
-      summary: Destroy a Deployment
-      description: Destroy a  Deployment
-      operationId: destroyDeploymentIntentGroup
+      summary: Terminate a Deployment
+      description: Terminate a  Deployment
+      operationId: terminateDeploymentIntentGroup
       responses:
         '200':
           description: Success
@@ -3277,4 +3277,4 @@ components:
       required: true
       schema:
         type: string
-        maxLength: 128
\ No newline at end of file
+        maxLength: 128
index 1962c3f..d5ea90d 100755 (executable)
@@ -366,7 +366,7 @@ function deleteData {
     deleteOrchestratorData
 }
 function instantiate {
-    call_api -d "{ }" "${base_url_orchestrator}/projects/${projectname}/composite-apps/${vfw_compositeapp_name}/${vfw_compositeapp_version}/deployment-intent-groups/${deployment_intent_group_name}/approve"
+    call_api -d "{ }" "${base_url_orchestrator}/projects/${projectname}/composite-apps/${vfw_compositeapp_name}/${vfw_compositeapp_version}/deployment-intent-groups/${deployment_intent_group_name}/approve"
     call_api -d "{ }" "${base_url_orchestrator}/projects/${projectname}/composite-apps/${operators_compositeapp_name}/${compositeapp_version}/deployment-intent-groups/${deployment_intent_group_name}/instantiate"
 }
 
index a6f9f8b..84f5ca2 100755 (executable)
@@ -563,5 +563,6 @@ call_api -d "${payload}" "${base_url}/controllers"
 
 #BEGIN: Instantiation
 print_msg "Getting the sorted templates for each of the apps.."
+call_api -d "" "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/deployment-intent-groups/${deploymentIntentGroupName}/approve"
 call_api -d "" "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/deployment-intent-groups/${deploymentIntentGroupName}/instantiate"
 # END: Instantiation
index d9c38a1..ca995ba 100755 (executable)
@@ -580,7 +580,7 @@ function deleteData {
 # }
 
 function instantiate {
-    call_api -d "{ }" "${base_url_orchestrator}/projects/${projectname}/composite-apps/${vfw_compositeapp_name}/${vfw_compositeapp_version}/deployment-intent-groups/${deployment_intent_group_name}/approve"
+    call_api -d "{ }" "${base_url_orchestrator}/projects/${projectname}/composite-apps/${vfw_compositeapp_name}/${vfw_compositeapp_version}/deployment-intent-groups/${deployment_intent_group_name}/approve"
     call_api -d "{ }" "${base_url_orchestrator}/projects/${projectname}/composite-apps/${collection_compositeapp_name}/${compositeapp_version}/deployment-intent-groups/${deployment_intent_group_name}/instantiate"
 }
 
index b8d0779..d350f71 100755 (executable)
@@ -460,6 +460,7 @@ function deleteData {
 }
 
 function instantiate {
+    call_api -d "{ }" "${base_url_orchestrator}/projects/${projectname}/composite-apps/${collection_compositeapp_name}/${compositeapp_version}/deployment-intent-groups/${deployment_intent_group_name}/approve"
     call_api -d "{ }" "${base_url_orchestrator}/projects/${projectname}/composite-apps/${collection_compositeapp_name}/${compositeapp_version}/deployment-intent-groups/${deployment_intent_group_name}/instantiate"
 }
 
index b14ad95..f4f96b2 100755 (executable)
@@ -976,7 +976,7 @@ function terminateVfw {
 }
 
 function instantiateVfw {
-    call_api -d "{ }" "${base_url_orchestrator}/projects/${projectname}/composite-apps/${vfw_compositeapp_name}/${vfw_compositeapp_version}/deployment-intent-groups/${deployment_intent_group_name}/approve"
+    call_api -d "{ }" "${base_url_orchestrator}/projects/${projectname}/composite-apps/${vfw_compositeapp_name}/${vfw_compositeapp_version}/deployment-intent-groups/${deployment_intent_group_name}/approve"
     call_api -d "{ }" "${base_url_orchestrator}/projects/${projectname}/composite-apps/${vfw_compositeapp_name}/${vfw_compositeapp_version}/deployment-intent-groups/${deployment_intent_group_name}/instantiate"
 }
 
index 4bbc91b..076718d 100644 (file)
@@ -28,8 +28,8 @@ import (
        "testing"
 
        "github.com/onap/multicloud-k8s/src/clm/pkg/cluster"
-       "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext"
        types "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module/types"
+       "github.com/onap/multicloud-k8s/src/orchestrator/pkg/state"
 
        pkgerrors "github.com/pkg/errors"
 )
@@ -43,7 +43,7 @@ type mockClusterManager struct {
        ClusterProviderItems []cluster.ClusterProvider
        ClusterItems         []cluster.Cluster
        ClusterContentItems  []cluster.ClusterContent
-       ClusterContextItems  []appcontext.AppContext
+       ClusterStateInfo     []state.StateInfo
        ClusterLabelItems    []cluster.ClusterLabel
        ClusterKvPairsItems  []cluster.ClusterKvPairs
        ClusterList          []string
@@ -102,12 +102,12 @@ func (m *mockClusterManager) GetClusterContent(provider, name string) (cluster.C
        return m.ClusterContentItems[0], nil
 }
 
-func (m *mockClusterManager) GetClusterContext(provider, name string) (appcontext.AppContext, string, error) {
+func (m *mockClusterManager) GetClusterState(provider, name string) (state.StateInfo, error) {
        if m.Err != nil {
-               return appcontext.AppContext{}, "", m.Err
+               return state.StateInfo{}, m.Err
        }
 
-       return m.ClusterContextItems[0], "", nil
+       return m.ClusterStateInfo[0], nil
 }
 
 func (m *mockClusterManager) GetClusters(provider string) ([]cluster.Cluster, error) {
index 0e65556..1d174b1 100644 (file)
@@ -2,25 +2,24 @@ module github.com/onap/multicloud-k8s/src/clm
 
 require (
        github.com/ghodss/yaml v1.0.0
-       github.com/go-stack/stack v1.8.0 // indirect
        github.com/golang/snappy v0.0.1 // indirect
        github.com/gorilla/handlers v1.3.0
-       github.com/gorilla/mux v1.6.2
+       github.com/gorilla/mux v1.7.3
        github.com/k8snetworkplumbingwg/network-attachment-definition-client v0.0.0-20200127152046-0ee521d56061
-       github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200601021239-7959bd4c6fd4
+       github.com/onap/multicloud-k8s/src/orchestrator v0.0.0-20200721211210-783ed87fb39a
        github.com/opencontainers/go-digest v1.0.0 // indirect
-       github.com/pkg/errors v0.8.1
-       github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect
-       github.com/xdg/stringprep v1.0.0 // indirect
-       google.golang.org/grpc v1.27.1
+       github.com/pkg/errors v0.9.1
+       google.golang.org/grpc v1.28.0
        gopkg.in/yaml.v2 v2.2.8
        k8s.io/api v0.0.0-20190831074750-7364b6bdad65
-       k8s.io/apimachinery v0.0.0-20190831074630-461753078381
+       k8s.io/apimachinery v0.18.2
        k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible
        k8s.io/kubernetes v1.14.1
 )
 
 replace (
+       github.com/onap/multicloud-k8s/src/orchestrator => ../orchestrator
+       github.com/onap/multicloud-k8s/src/clm => ../clm
        k8s.io/api => k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b
        k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8
        k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d
index ac7f31f..9505bd9 100644 (file)
@@ -17,9 +17,9 @@
 package cluster
 
 import (
-       appcontext "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext"
        "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db"
        mtypes "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module/types"
+       "github.com/onap/multicloud-k8s/src/orchestrator/pkg/state"
 
        pkgerrors "github.com/pkg/errors"
 )
@@ -28,7 +28,7 @@ type clientDbInfo struct {
        storeName  string // name of the mongodb collection to use for client documents
        tagMeta    string // attribute key name for the json data of a client document
        tagContent string // attribute key name for the file data of a client document
-       tagContext string // attribute key name for context object in App Context
+       tagState   string // attribute key name for StateInfo object in the cluster
 }
 
 // ClusterProvider contains the parameters needed for ClusterProviders
@@ -101,7 +101,7 @@ type ClusterManager interface {
        CreateCluster(provider string, pr Cluster, qr ClusterContent) (Cluster, error)
        GetCluster(provider, name string) (Cluster, error)
        GetClusterContent(provider, name string) (ClusterContent, error)
-       GetClusterContext(provider, name string) (appcontext.AppContext, string, error)
+       GetClusterState(provider, name string) (state.StateInfo, error)
        GetClusters(provider string) ([]Cluster, error)
        GetClustersWithLabel(provider, label string) ([]string, error)
        DeleteCluster(provider, name string) error
@@ -129,7 +129,7 @@ func NewClusterClient() *ClusterClient {
                        storeName:  "cluster",
                        tagMeta:    "clustermetadata",
                        tagContent: "clustercontent",
-                       tagContext: "clustercontext",
+                       tagState:   "stateInfo",
                },
        }
 }
@@ -254,6 +254,17 @@ func (v *ClusterClient) CreateCluster(provider string, p Cluster, q ClusterConte
                return Cluster{}, pkgerrors.Wrap(err, "Creating DB Entry")
        }
 
+       // Add the stateInfo record
+       stateInfo := state.StateInfo{
+               State:     state.StateEnum.Created,
+               ContextId: "",
+       }
+
+       err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagState, stateInfo)
+       if err != nil {
+               return Cluster{}, pkgerrors.Wrap(err, "Creating cluster StateInfo")
+       }
+
        return p, nil
 }
 
@@ -309,31 +320,29 @@ func (v *ClusterClient) GetClusterContent(provider, name string) (ClusterContent
        return ClusterContent{}, pkgerrors.New("Error getting Cluster Content")
 }
 
-// GetClusterContext returns the AppContext for corresponding provider and name
-func (v *ClusterClient) GetClusterContext(provider, name string) (appcontext.AppContext, string, error) {
+// GetClusterState returns the StateInfo structure for corresponding cluster provider and cluster
+func (v *ClusterClient) GetClusterState(provider, name string) (state.StateInfo, error) {
        //Construct key and tag to select the entry
        key := ClusterKey{
                ClusterProviderName: provider,
                ClusterName:         name,
        }
 
-       value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagContext)
+       result, err := db.DBconn.Find(v.db.storeName, key, v.db.tagState)
        if err != nil {
-               return appcontext.AppContext{}, "", pkgerrors.Wrap(err, "Get Cluster Context")
+               return state.StateInfo{}, pkgerrors.Wrap(err, "Get Cluster StateInfo")
        }
 
-       //value is a byte array
-       if value != nil {
-               ctxVal := string(value[0])
-               var cc appcontext.AppContext
-               _, err = cc.LoadAppContext(ctxVal)
+       if result != nil {
+               s := state.StateInfo{}
+               err = db.DBconn.Unmarshal(result[0], &s)
                if err != nil {
-                       return appcontext.AppContext{}, "", pkgerrors.Wrap(err, "Reinitializing Cluster AppContext")
+                       return state.StateInfo{}, pkgerrors.Wrap(err, "Unmarshalling Cluster StateInfo")
                }
-               return cc, ctxVal, nil
+               return s, nil
        }
 
-       return appcontext.AppContext{}, "", pkgerrors.New("Error getting Cluster AppContext")
+       return state.StateInfo{}, pkgerrors.New("Error getting Cluster StateInfo")
 }
 
 // GetClusters returns all the Clusters for corresponding provider
@@ -393,9 +402,9 @@ func (v *ClusterClient) DeleteCluster(provider, name string) error {
                ClusterProviderName: provider,
                ClusterName:         name,
        }
-       _, _, err := v.GetClusterContext(provider, name)
-       if err == nil {
-               return pkgerrors.Errorf("Cannot delete cluster until context is deleted: %v, %v", provider, name)
+       s, err := v.GetClusterState(provider, name)
+       if err == nil && s.State == state.StateEnum.Applied {
+               return pkgerrors.Errorf("Cluster network intents must be terminated before it can be deleted: " + name)
        }
 
        err = db.DBconn.Remove(v.db.storeName, key)
index 0dd657a..0c85cdb 100644 (file)
@@ -20,5 +20,5 @@ type ClientDbInfo struct {
        StoreName  string // name of the mongodb collection to use for client documents
        TagMeta    string // attribute key name for the json data of a client document
        TagContent string // attribute key name for the file data of a client document
-       TagContext string // attribute key name for context object in App Context
+       TagState   string // attribute key name for context object in App Context
 }
index de8ee50..58480cc 100644 (file)
@@ -22,6 +22,7 @@ import (
        nettypes "github.com/onap/multicloud-k8s/src/ncm/pkg/networkintents/types"
        "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db"
        mtypes "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module/types"
+       "github.com/onap/multicloud-k8s/src/orchestrator/pkg/state"
 
        pkgerrors "github.com/pkg/errors"
 )
@@ -89,11 +90,25 @@ func (v *NetworkClient) CreateNetwork(p Network, clusterProvider, cluster string
                NetworkName:         p.Metadata.Name,
        }
 
-       //Check if cluster exists
-       _, err := clusterPkg.NewClusterClient().GetCluster(clusterProvider, cluster)
+       //Check if cluster exists and in a state for adding network intents
+       s, err := clusterPkg.NewClusterClient().GetClusterState(clusterProvider, cluster)
        if err != nil {
                return Network{}, pkgerrors.New("Unable to find the cluster")
        }
+       switch s.State {
+       case state.StateEnum.Approved:
+               return Network{}, pkgerrors.Errorf("Cluster is in an invalid state: " + cluster + " " + state.StateEnum.Approved)
+       case state.StateEnum.Terminated:
+               break
+       case state.StateEnum.Created:
+               break
+       case state.StateEnum.Applied:
+               return Network{}, pkgerrors.Errorf("Existing cluster network intents must be terminated before creating: " + cluster)
+       case state.StateEnum.Instantiated:
+               return Network{}, pkgerrors.Errorf("Cluster is in an invalid state: " + cluster + " " + state.StateEnum.Instantiated)
+       default:
+               return Network{}, pkgerrors.Errorf("Cluster is in an invalid state: " + cluster + " " + s.State)
+       }
 
        //Check if this Network already exists
        _, err = v.GetNetwork(p.Metadata.Name, clusterProvider, cluster)
@@ -167,6 +182,25 @@ func (v *NetworkClient) GetNetworks(clusterProvider, cluster string) ([]Network,
 
 // Delete the  Network from database
 func (v *NetworkClient) DeleteNetwork(name, clusterProvider, cluster string) error {
+       // verify cluster is in a state where network intent can be deleted
+       s, err := clusterPkg.NewClusterClient().GetClusterState(clusterProvider, cluster)
+       if err != nil {
+               return pkgerrors.New("Unable to find the cluster")
+       }
+       switch s.State {
+       case state.StateEnum.Approved:
+               return pkgerrors.Errorf("Cluster is in an invalid state: " + cluster + " " + state.StateEnum.Approved)
+       case state.StateEnum.Terminated:
+               break
+       case state.StateEnum.Created:
+               break
+       case state.StateEnum.Applied:
+               return pkgerrors.Errorf("Cluster network intents must be terminated before deleting: " + cluster)
+       case state.StateEnum.Instantiated:
+               return pkgerrors.Errorf("Cluster is in an invalid state: " + cluster + " " + state.StateEnum.Instantiated)
+       default:
+               return pkgerrors.Errorf("Cluster is in an invalid state: " + cluster + " " + s.State)
+       }
 
        //Construct key and tag to select the entry
        key := NetworkKey{
@@ -175,7 +209,7 @@ func (v *NetworkClient) DeleteNetwork(name, clusterProvider, cluster string) err
                NetworkName:         name,
        }
 
-       err := db.DBconn.Remove(v.db.StoreName, key)
+       err = db.DBconn.Remove(v.db.StoreName, key)
        if err != nil {
                return pkgerrors.Wrap(err, "Delete Network Entry;")
        }
index 072e07f..dbe6e46 100644 (file)
@@ -22,6 +22,7 @@ import (
        nettypes "github.com/onap/multicloud-k8s/src/ncm/pkg/networkintents/types"
        "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db"
        mtypes "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module/types"
+       "github.com/onap/multicloud-k8s/src/orchestrator/pkg/state"
 
        pkgerrors "github.com/pkg/errors"
 )
@@ -84,6 +85,26 @@ func NewProviderNetClient() *ProviderNetClient {
 // CreateProviderNet - create a new ProviderNet
 func (v *ProviderNetClient) CreateProviderNet(p ProviderNet, clusterProvider, cluster string, exists bool) (ProviderNet, error) {
 
+       // verify cluster exists and in state to add provider networks
+       s, err := clusterPkg.NewClusterClient().GetClusterState(clusterProvider, cluster)
+       if err != nil {
+               return ProviderNet{}, pkgerrors.New("Unable to find the cluster")
+       }
+       switch s.State {
+       case state.StateEnum.Approved:
+               return ProviderNet{}, pkgerrors.Wrap(err, "Cluster is in an invalid state: "+cluster+" "+state.StateEnum.Approved)
+       case state.StateEnum.Terminated:
+               break
+       case state.StateEnum.Created:
+               break
+       case state.StateEnum.Applied:
+               return ProviderNet{}, pkgerrors.Wrap(err, "Existing cluster provider network intents must be terminated before creating: "+cluster)
+       case state.StateEnum.Instantiated:
+               return ProviderNet{}, pkgerrors.Wrap(err, "Cluster is in an invalid state: "+cluster+" "+state.StateEnum.Instantiated)
+       default:
+               return ProviderNet{}, pkgerrors.Wrap(err, "Cluster is in an invalid state: "+cluster+" "+s.State)
+       }
+
        //Construct key and tag to select the entry
        key := ProviderNetKey{
                ClusterProviderName: clusterProvider,
@@ -91,12 +112,6 @@ func (v *ProviderNetClient) CreateProviderNet(p ProviderNet, clusterProvider, cl
                ProviderNetName:     p.Metadata.Name,
        }
 
-       //Check if cluster exists
-       _, err := clusterPkg.NewClusterClient().GetCluster(clusterProvider, cluster)
-       if err != nil {
-               return ProviderNet{}, pkgerrors.New("Unable to find the cluster")
-       }
-
        //Check if this ProviderNet already exists
        _, err = v.GetProviderNet(p.Metadata.Name, clusterProvider, cluster)
        if err == nil && !exists {
@@ -169,6 +184,25 @@ func (v *ProviderNetClient) GetProviderNets(clusterProvider, cluster string) ([]
 
 // Delete the  ProviderNet from database
 func (v *ProviderNetClient) DeleteProviderNet(name, clusterProvider, cluster string) error {
+       // verify cluster is in a state where provider network intent can be deleted
+       s, err := clusterPkg.NewClusterClient().GetClusterState(clusterProvider, cluster)
+       if err != nil {
+               return pkgerrors.New("Unable to find the cluster")
+       }
+       switch s.State {
+       case state.StateEnum.Approved:
+               return pkgerrors.Wrap(err, "Cluster is in an invalid state: "+cluster+" "+state.StateEnum.Approved)
+       case state.StateEnum.Terminated:
+               break
+       case state.StateEnum.Created:
+               break
+       case state.StateEnum.Applied:
+               return pkgerrors.Wrap(err, "Cluster provider network intents must be terminated before deleting: "+cluster)
+       case state.StateEnum.Instantiated:
+               return pkgerrors.Wrap(err, "Cluster is in an invalid state: "+cluster+" "+state.StateEnum.Instantiated)
+       default:
+               return pkgerrors.Wrap(err, "Cluster is in an invalid state: "+cluster+" "+s.State)
+       }
 
        //Construct key and tag to select the entry
        key := ProviderNetKey{
@@ -177,7 +211,7 @@ func (v *ProviderNetClient) DeleteProviderNet(name, clusterProvider, cluster str
                ProviderNetName:     name,
        }
 
-       err := db.DBconn.Remove(v.db.StoreName, key)
+       err = db.DBconn.Remove(v.db.StoreName, key)
        if err != nil {
                return pkgerrors.Wrap(err, "Delete ProviderNet Entry;")
        }
index 4886a67..8ced68b 100644 (file)
@@ -27,6 +27,7 @@ import (
        "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/state"
 
        pkgerrors "github.com/pkg/errors"
 )
@@ -51,7 +52,7 @@ func NewSchedulerClient() *SchedulerClient {
                        StoreName:  "cluster",
                        TagMeta:    "clustermetadata",
                        TagContent: "clustercontent",
-                       TagContext: "clustercontext",
+                       TagState:   "stateInfo",
                },
        }
 }
@@ -59,9 +60,23 @@ func NewSchedulerClient() *SchedulerClient {
 // Apply Network Intents associated with a cluster
 func (v *SchedulerClient) ApplyNetworkIntents(clusterProvider, cluster string) error {
 
-       _, _, err := clusterPkg.NewClusterClient().GetClusterContext(clusterProvider, cluster)
-       if err == nil {
-               return pkgerrors.Errorf("Cluster network intents have already been applied: %v, %v", clusterProvider, cluster)
+       s, err := clusterPkg.NewClusterClient().GetClusterState(clusterProvider, cluster)
+       if err != nil {
+               return pkgerrors.Errorf("Error finding cluster: %v %v", clusterProvider, cluster)
+       }
+       switch s.State {
+       case state.StateEnum.Approved:
+               return pkgerrors.Wrap(err, "Cluster is in an invalid state: "+cluster+" "+state.StateEnum.Approved)
+       case state.StateEnum.Terminated:
+               break
+       case state.StateEnum.Created:
+               break
+       case state.StateEnum.Applied:
+               return nil
+       case state.StateEnum.Instantiated:
+               return pkgerrors.Wrap(err, "Cluster is in an invalid state: "+cluster+" "+state.StateEnum.Instantiated)
+       default:
+               return pkgerrors.Wrap(err, "Cluster is in an invalid state: "+cluster+" "+s.State)
        }
 
        // Make an app context for the network intent resources
@@ -135,12 +150,17 @@ func (v *SchedulerClient) ApplyNetworkIntents(clusterProvider, cluster string) e
                return pkgerrors.Wrap(err, "Error adding Cluster to AppContext")
        }
 
-       // save the context in the cluster db record
+       // update the StateInfo in the cluster db record
        key := clusterPkg.ClusterKey{
                ClusterProviderName: clusterProvider,
                ClusterName:         cluster,
        }
-       err = db.DBconn.Insert(v.db.StoreName, key, nil, v.db.TagContext, ctxVal)
+       stateInfo := state.StateInfo{
+               State:     state.StateEnum.Applied,
+               ContextId: ctxVal.(string),
+       }
+
+       err = db.DBconn.Insert(v.db.StoreName, key, nil, v.db.TagState, stateInfo)
        if err != nil {
                cleanuperr := ac.DeleteCompositeApp()
                if cleanuperr != nil {
@@ -149,7 +169,7 @@ func (v *SchedulerClient) ApplyNetworkIntents(clusterProvider, cluster string) e
                                "cluster":          cluster,
                        })
                }
-               return pkgerrors.Wrap(err, "Error adding AppContext to DB")
+               return pkgerrors.Wrap(err, "Error updating the stateInfo of cluster: "+cluster)
        }
 
        // call resource synchronizer to instantiate the CRs in the cluster
@@ -163,37 +183,55 @@ func (v *SchedulerClient) ApplyNetworkIntents(clusterProvider, cluster string) e
 
 // Terminate Network Intents associated with a cluster
 func (v *SchedulerClient) TerminateNetworkIntents(clusterProvider, cluster string) error {
-       context, ctxVal, err := clusterPkg.NewClusterClient().GetClusterContext(clusterProvider, cluster)
+       s, err := clusterPkg.NewClusterClient().GetClusterState(clusterProvider, cluster)
        if err != nil {
-               return pkgerrors.Wrapf(err, "Error finding AppContext for cluster: %v, %v", clusterProvider, cluster)
+               return pkgerrors.Wrapf(err, "Error finding StateInfo for cluster: %v, %v", clusterProvider, cluster)
+       }
+       switch s.State {
+       case state.StateEnum.Approved:
+               return pkgerrors.Wrap(err, "Cluster is in an invalid state: "+cluster+" "+state.StateEnum.Approved)
+       case state.StateEnum.Terminated:
+               return nil
+       case state.StateEnum.Created:
+               return pkgerrors.Wrap(err, "Cluster network intents have not been applied: "+cluster)
+       case state.StateEnum.Applied:
+               break
+       case state.StateEnum.Instantiated:
+               return pkgerrors.Wrap(err, "Cluster is in an invalid state: "+cluster+" "+state.StateEnum.Instantiated)
+       default:
+               return pkgerrors.Wrap(err, "Cluster is in an invalid state: "+cluster+" "+s.State)
        }
 
        // call resource synchronizer to terminate the CRs in the cluster
-       err = installappclient.InvokeUninstallApp(ctxVal)
+       err = installappclient.InvokeUninstallApp(s.ContextId)
        if err != nil {
                return err
        }
 
        // remove the app context
-       cleanuperr := context.DeleteCompositeApp()
-       if cleanuperr != nil {
-               log.Warn("Error deleted AppContext", log.Fields{
-                       "cluster-provider": clusterProvider,
-                       "cluster":          cluster,
-               })
+       context, err := state.GetAppContextFromStateInfo(s)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Error getting appcontext from cluster StateInfo : "+clusterProvider+" "+cluster)
+       }
+       err = context.DeleteCompositeApp()
+       if err != nil {
+               return pkgerrors.Wrap(err, "Error deleting appcontext of cluster : "+clusterProvider+" "+cluster)
        }
 
-       // remove the app context field from the cluster db record
+       // update StateInfo
        key := clusterPkg.ClusterKey{
                ClusterProviderName: clusterProvider,
                ClusterName:         cluster,
        }
-       err = db.DBconn.RemoveTag(v.db.StoreName, key, v.db.TagContext)
+       stateInfo := state.StateInfo{
+               State:     state.StateEnum.Terminated,
+               ContextId: "",
+       }
+
+       err = db.DBconn.Insert(v.db.StoreName, key, nil, v.db.TagState, stateInfo)
        if err != nil {
-               log.Warn("Error removing AppContext from Cluster document", log.Fields{
-                       "cluster-provider": clusterProvider,
-                       "cluster":          cluster,
-               })
+               return pkgerrors.Wrap(err, "Error updating the stateInfo of cluster: "+cluster)
        }
+
        return nil
 }
index 03afee2..72b444b 100644 (file)
@@ -189,6 +189,8 @@ func NewRouter(projectClient moduleLib.ProjectManager,
                client: instantiationClient,
        }
 
+       router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/approve", instantiationHandler.approveHandler).Methods("POST")
+       router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/terminate", instantiationHandler.terminateHandler).Methods("POST")
        router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/instantiate", instantiationHandler.instantiateHandler).Methods("POST")
        router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/terminate", instantiationHandler.terminateHandler).Methods("POST")
        router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/status", instantiationHandler.statusHandler).Methods("GET")
index ce50e5b..eeac8a0 100644 (file)
@@ -31,6 +31,23 @@ type instantiationHandler struct {
        client moduleLib.InstantiationManager
 }
 
+func (h instantiationHandler) approveHandler(w http.ResponseWriter, r *http.Request) {
+
+       vars := mux.Vars(r)
+       p := vars["project-name"]
+       ca := vars["composite-app-name"]
+       v := vars["composite-app-version"]
+       di := vars["deployment-intent-group-name"]
+
+       iErr := h.client.Approve(p, ca, v, di)
+       if iErr != nil {
+               http.Error(w, iErr.Error(), http.StatusInternalServerError)
+               return
+       }
+       w.WriteHeader(http.StatusAccepted)
+
+}
+
 func (h instantiationHandler) instantiateHandler(w http.ResponseWriter, r *http.Request) {
 
        vars := mux.Vars(r)
index 22e1aba..f05343c 100644 (file)
@@ -16,7 +16,6 @@ require (
        github.com/lib/pq v1.6.0 // indirect
        github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
        github.com/mitchellh/copystructure v1.0.0 // indirect
-       github.com/onap/multicloud-k8s/src/clm v0.0.0-00010101000000-000000000000
        github.com/onap/multicloud-k8s/src/monitor v0.0.0-20200630152613-7c20f73e7c5d
        github.com/onap/multicloud-k8s/src/ncm v0.0.0-20200515060444-c77850a75eee
        github.com/onap/multicloud-k8s/src/rsync v0.0.0-20200630152613-7c20f73e7c5d
index 35b0356..d017c1e 100644 (file)
@@ -20,8 +20,8 @@ import (
        "encoding/json"
        "reflect"
 
-       appcontext "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/state"
 
        pkgerrors "github.com/pkg/errors"
 )
@@ -62,7 +62,7 @@ type OverrideValues struct {
 type DeploymentIntentGroupManager interface {
        CreateDeploymentIntentGroup(d DeploymentIntentGroup, p string, ca string, v string) (DeploymentIntentGroup, error)
        GetDeploymentIntentGroup(di string, p string, ca string, v string) (DeploymentIntentGroup, error)
-       GetDeploymentIntentGroupContext(di string, p string, ca string, v string) (appcontext.AppContext, string, error)
+       GetDeploymentIntentGroupState(di string, p string, ca string, v string) (state.StateInfo, error)
        DeleteDeploymentIntentGroup(di string, p string, ca string, v string) error
        GetAllDeploymentIntentGroups(p string, ca string, v string) ([]DeploymentIntentGroup, error)
 }
@@ -89,7 +89,7 @@ func (dk DeploymentIntentGroupKey) String() string {
 type DeploymentIntentGroupClient struct {
        storeName   string
        tagMetaData string
-       tagContext  string
+       tagState    string
 }
 
 // NewDeploymentIntentGroupClient return an instance of DeploymentIntentGroupClient which implements DeploymentIntentGroupManager
@@ -97,7 +97,7 @@ func NewDeploymentIntentGroupClient() *DeploymentIntentGroupClient {
        return &DeploymentIntentGroupClient{
                storeName:   "orchestrator",
                tagMetaData: "deploymentintentgroupmetadata",
-               tagContext:  "contextid",
+               tagState:    "stateInfo",
        }
 }
 
@@ -134,6 +134,17 @@ func (c *DeploymentIntentGroupClient) CreateDeploymentIntentGroup(d DeploymentIn
                return DeploymentIntentGroup{}, pkgerrors.Wrap(err, "Create DB entry error")
        }
 
+       // Add the stateInfo record
+       stateInfo := state.StateInfo{
+               State:     state.StateEnum.Created,
+               ContextId: "",
+       }
+
+       err = db.DBconn.Insert(c.storeName, gkey, nil, c.tagState, stateInfo)
+       if err != nil {
+               return DeploymentIntentGroup{}, pkgerrors.Wrap(err, "Error updating the stateInfo of the DeploymentIntentGroup: "+d.MetaData.Name)
+       }
+
        return d, nil
 }
 
@@ -205,8 +216,8 @@ func (c *DeploymentIntentGroupClient) GetAllDeploymentIntentGroups(p string, ca
 
 }
 
-// GetDeploymentIntentGroupContext returns the AppContent with a given DeploymentIntentname, project, compositeAppName and version of compositeApp
-func (c *DeploymentIntentGroupClient) GetDeploymentIntentGroupContext(di string, p string, ca string, v string) (appcontext.AppContext, string, error) {
+// GetDeploymentIntentGroupState returns the AppContent with a given DeploymentIntentname, project, compositeAppName and version of compositeApp
+func (c *DeploymentIntentGroupClient) GetDeploymentIntentGroupState(di string, p string, ca string, v string) (state.StateInfo, error) {
 
        key := DeploymentIntentGroupKey{
                Name:         di,
@@ -215,22 +226,21 @@ func (c *DeploymentIntentGroupClient) GetDeploymentIntentGroupContext(di string,
                Version:      v,
        }
 
-       result, err := db.DBconn.Find(c.storeName, key, c.tagContext)
+       result, err := db.DBconn.Find(c.storeName, key, c.tagState)
        if err != nil {
-               return appcontext.AppContext{}, "", pkgerrors.Wrap(err, "Get DeploymentIntentGroup Context error")
+               return state.StateInfo{}, pkgerrors.Wrap(err, "Get DeploymentIntentGroup StateInfo error")
        }
 
        if result != nil {
-               ctxVal := string(result[0])
-               var cc appcontext.AppContext
-               _, err = cc.LoadAppContext(ctxVal)
+               s := state.StateInfo{}
+               err = db.DBconn.Unmarshal(result[0], &s)
                if err != nil {
-                       return appcontext.AppContext{}, "", pkgerrors.Wrap(err, "Error loading DeploymentIntentGroup Appcontext")
+                       return state.StateInfo{}, pkgerrors.Wrap(err, "Unmarshalling DeploymentIntentGroup StateInfo")
                }
-               return cc, ctxVal, nil
+               return s, nil
        }
 
-       return appcontext.AppContext{}, "", pkgerrors.New("Error getting DeploymentIntentGroup AppContext")
+       return state.StateInfo{}, pkgerrors.New("Error getting DeploymentIntentGroup StateInfo")
 }
 
 // DeleteDeploymentIntentGroup deletes a DeploymentIntentGroup
@@ -241,9 +251,9 @@ func (c *DeploymentIntentGroupClient) DeleteDeploymentIntentGroup(di string, p s
                CompositeApp: ca,
                Version:      v,
        }
-       _, _, err := c.GetDeploymentIntentGroupContext(di, p, ca, v)
-       if err == nil {
-               return pkgerrors.New("DeploymentIntentGroup must be terminated before it can be deleted " + di)
+       s, err := c.GetDeploymentIntentGroupState(di, p, ca, v)
+       if err == nil && s.State == state.StateEnum.Instantiated {
+               return pkgerrors.Errorf("DeploymentIntentGroup must be terminated before it can be deleted " + di)
        }
 
        err = db.DBconn.Remove(c.storeName, k)
index f4e7586..9c0c9e3 100644 (file)
@@ -25,6 +25,7 @@ import (
        gpic "github.com/onap/multicloud-k8s/src/orchestrator/pkg/gpic"
        "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/state"
        "github.com/onap/multicloud-k8s/src/orchestrator/utils/helm"
        pkgerrors "github.com/pkg/errors"
 )
@@ -71,32 +72,67 @@ type InstantiationKey struct {
 // InstantiationManager is an interface which exposes the
 // InstantiationManager functionalities
 type InstantiationManager interface {
-       //ApproveInstantiation(p string, ca string, v string, di string) (error)
+       Approve(p string, ca string, v string, di string) error
        Instantiate(p string, ca string, v string, di string) error
        Status(p string, ca string, v string, di string) (StatusData, error)
        Terminate(p string, ca string, v string, di string) error
 }
 
-// InstantiationClientDbInfo consists of storeName and tagContext
+// InstantiationClientDbInfo consists of storeName and tagState
 type InstantiationClientDbInfo struct {
-       storeName  string // name of the mongodb collection to use for Instantiationclient documents
-       tagContext string // attribute key name for context object in App Context
+       storeName string // name of the mongodb collection to use for Instantiationclient documents
+       tagState  string // attribute key name for context object in App Context
 }
 
 // NewInstantiationClient returns an instance of InstantiationClient
 func NewInstantiationClient() *InstantiationClient {
        return &InstantiationClient{
                db: InstantiationClientDbInfo{
-                       storeName:  "orchestrator",
-                       tagContext: "contextid",
+                       storeName: "orchestrator",
+                       tagState:  "stateInfo",
                },
        }
 }
 
-// TODO
-//ApproveInstantiation approves an instantiation
-// func (c InstantiationClient) ApproveInstantiation(p string, ca string, v string, di string) (error){
-// }
+//Approve approves an instantiation
+func (c InstantiationClient) Approve(p string, ca string, v string, di string) error {
+       s, err := NewDeploymentIntentGroupClient().GetDeploymentIntentGroupState(di, p, ca, v)
+       if err != nil {
+               return pkgerrors.Wrap(err, "DeploymentIntentGroup has no state info: "+di)
+       }
+       switch s.State {
+       case state.StateEnum.Approved:
+               return nil
+       case state.StateEnum.Terminated:
+               break
+       case state.StateEnum.Created:
+               break
+       case state.StateEnum.Applied:
+               return pkgerrors.Errorf("DeploymentIntentGroup is in an invalid state" + s.State)
+       case state.StateEnum.Instantiated:
+               return pkgerrors.Errorf("DeploymentIntentGroup has already been instantiated" + di)
+       default:
+               return pkgerrors.Errorf("DeploymentIntentGroup is in an unknown state" + s.State)
+       }
+
+       key := DeploymentIntentGroupKey{
+               Name:         di,
+               Project:      p,
+               CompositeApp: ca,
+               Version:      v,
+       }
+       stateInfo := state.StateInfo{
+               State:     state.StateEnum.Approved,
+               ContextId: "",
+       }
+
+       err = db.DBconn.Insert(c.db.storeName, key, nil, c.db.tagState, stateInfo)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Error updating the stateInfo of the DeploymentIntentGroup: "+di)
+       }
+
+       return nil
+}
 
 func getOverrideValuesByAppName(ov []OverrideValues, a string) map[string]string {
        for _, eachOverrideVal := range ov {
@@ -189,9 +225,23 @@ func (c InstantiationClient) Instantiate(p string, ca string, v string, di strin
                return pkgerrors.Wrap(err, "Not finding the deploymentIntentGroup")
        }
 
-       _, _, err = NewDeploymentIntentGroupClient().GetDeploymentIntentGroupContext(di, p, ca, v)
-       if err == nil {
-               return pkgerrors.Errorf("DeploymentIntentGroup has already been instantiated: " + di)
+       s, err := NewDeploymentIntentGroupClient().GetDeploymentIntentGroupState(di, p, ca, v)
+       if err != nil {
+               return pkgerrors.Errorf("Error retrieving DeploymentIntentGroup stateInfo: " + di)
+       }
+       switch s.State {
+       case state.StateEnum.Approved:
+               break
+       case state.StateEnum.Terminated:
+               break // TODO - ideally, should check that all resources have completed being terminated
+       case state.StateEnum.Created:
+               return pkgerrors.Errorf("DeploymentIntentGroup must be Approved before instantiating" + di)
+       case state.StateEnum.Applied:
+               return pkgerrors.Errorf("DeploymentIntentGroup is in an invalid state" + di)
+       case state.StateEnum.Instantiated:
+               return pkgerrors.Errorf("DeploymentIntentGroup has already been instantiated" + di)
+       default:
+               return pkgerrors.Errorf("DeploymentIntentGroup is in an unknown state" + s.State)
        }
 
        rName := dIGrp.Spec.Version //rName is releaseName
@@ -292,8 +342,11 @@ func (c InstantiationClient) Instantiate(p string, ca string, v string, di strin
                CompositeApp: ca,
                Version:      v,
        }
-
-       err = db.DBconn.Insert(c.db.storeName, key, nil, c.db.tagContext, ctxval)
+       stateInfo := state.StateInfo{
+               State:     state.StateEnum.Instantiated,
+               ContextId: ctxval.(string),
+       }
+       err = db.DBconn.Insert(c.db.storeName, key, nil, c.db.tagState, stateInfo)
        if err != nil {
                cleanuperr := context.DeleteCompositeApp()
                if cleanuperr != nil {
@@ -348,11 +401,16 @@ the deployment, which is made available in the appcontext.
 */
 func (c InstantiationClient) Status(p string, ca string, v string, di string) (StatusData, error) {
 
-       ac, _, err := NewDeploymentIntentGroupClient().GetDeploymentIntentGroupContext(di, p, ca, v)
+       s, err := NewDeploymentIntentGroupClient().GetDeploymentIntentGroupState(di, p, ca, v)
        if err != nil {
                return StatusData{}, pkgerrors.Wrap(err, "deploymentIntentGroup not found: "+di)
        }
 
+       ac, err := state.GetAppContextFromStateInfo(s)
+       if err != nil {
+               return StatusData{}, pkgerrors.Wrap(err, "AppContext for deploymentIntentGroup not found: "+di)
+       }
+
        // Get all apps in this composite app
        allApps, err := NewAppClient().GetApps(p, ca, v)
        if err != nil {
@@ -409,12 +467,19 @@ DeploymentIntentName and calls rsync to terminate.
 */
 func (c InstantiationClient) Terminate(p string, ca string, v string, di string) error {
 
-       ac, ctxval, err := NewDeploymentIntentGroupClient().GetDeploymentIntentGroupContext(di, p, ca, v)
+       s, err := NewDeploymentIntentGroupClient().GetDeploymentIntentGroupState(di, p, ca, v)
+       if err != nil {
+               return pkgerrors.Wrap(err, "DeploymentIntentGroup has no state info: "+di)
+       } else if s.State != state.StateEnum.Instantiated {
+               return pkgerrors.Errorf("DeploymentIntentGroup is not instantiated" + di)
+       }
+
+       ac, err := state.GetAppContextFromStateInfo(s)
        if err != nil {
-               return pkgerrors.Wrap(err, "DeploymentIntentGroup has no app context: "+di)
+               return pkgerrors.Wrap(err, "AppContext for deploymentIntentGroup not found: "+di)
        }
 
-       err = callRsyncUninstall(ctxval)
+       err = callRsyncUninstall(s.ContextId)
        if err != nil {
                return err
        }
@@ -430,10 +495,14 @@ func (c InstantiationClient) Terminate(p string, ca string, v string, di string)
                CompositeApp: ca,
                Version:      v,
        }
+       stateInfo := state.StateInfo{
+               State:     state.StateEnum.Terminated,
+               ContextId: "",
+       }
 
-       err = db.DBconn.RemoveTag(c.db.storeName, key, c.db.tagContext)
+       err = db.DBconn.Insert(c.db.storeName, key, nil, c.db.tagState, stateInfo)
        if err != nil {
-               return pkgerrors.Wrap(err, "Error removing the app context tag from DeploymentIntentGroup: "+di)
+               return pkgerrors.Wrap(err, "Error updating the stateInfo of the DeploymentIntentGroup: "+di)
        }
 
        return nil
diff --git a/src/orchestrator/pkg/state/state_helper.go b/src/orchestrator/pkg/state/state_helper.go
new file mode 100644 (file)
index 0000000..a65cea8
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 Intel Corporation, Inc
+ *
+ * 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 state
+
+import "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext"
+
+// GetAppContextFromStateInfo loads the appcontext present in the StateInfo input
+func GetAppContextFromStateInfo(s StateInfo) (appcontext.AppContext, error) {
+       var cc appcontext.AppContext
+       _, err := cc.LoadAppContext(s.ContextId)
+       if err != nil {
+               return appcontext.AppContext{}, err
+       }
+       return cc, nil
+}
diff --git a/src/orchestrator/pkg/state/types.go b/src/orchestrator/pkg/state/types.go
new file mode 100644 (file)
index 0000000..25fb60d
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 Intel Corporation, Inc
+ *
+ * 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 state
+
+// StateInfo struct is used to maintain the values for state, contextid, (and other)
+// information about resources which can be instantiated via rsync.
+type StateInfo struct {
+       State     StateValue
+       ContextId string
+}
+
+type StateValue = string
+
+type states struct {
+       Created      StateValue
+       Approved     StateValue
+       Applied      StateValue
+       Instantiated StateValue
+       Terminated   StateValue
+}
+
+var StateEnum = &states{
+       Created:      "Created",
+       Approved:     "Approved",
+       Applied:      "Applied",
+       Instantiated: "Instantiated",
+       Terminated:   "Terminated",
+}