diff options
Diffstat (limited to 'src/ncm/pkg/module')
-rw-r--r-- | src/ncm/pkg/module/cluster.go | 255 | ||||
-rw-r--r-- | src/ncm/pkg/module/module.go | 14 | ||||
-rw-r--r-- | src/ncm/pkg/module/module_definitions.go | 58 | ||||
-rw-r--r-- | src/ncm/pkg/module/netcontrolintent.go | 164 | ||||
-rw-r--r-- | src/ncm/pkg/module/network.go | 14 | ||||
-rw-r--r-- | src/ncm/pkg/module/providernet.go | 18 | ||||
-rw-r--r-- | src/ncm/pkg/module/workloadifintent.go | 188 | ||||
-rw-r--r-- | src/ncm/pkg/module/workloadintent.go | 181 |
8 files changed, 867 insertions, 25 deletions
diff --git a/src/ncm/pkg/module/cluster.go b/src/ncm/pkg/module/cluster.go index e3260b7e..2397a091 100644 --- a/src/ncm/pkg/module/cluster.go +++ b/src/ncm/pkg/module/cluster.go @@ -17,7 +17,10 @@ package module import ( + "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" + "gopkg.in/yaml.v2" pkgerrors "github.com/pkg/errors" ) @@ -66,6 +69,12 @@ type ClusterLabelKey struct { ClusterLabelName string `json:"label"` } +// LabelKey is the key structure that is used in the database +type LabelKey struct { + ClusterProviderName string `json:"provider"` + ClusterLabelName string `json:"label"` +} + // ClusterKvPairsKey is the key structure that is used in the database type ClusterKvPairsKey struct { ClusterProviderName string `json:"provider"` @@ -73,7 +82,11 @@ type ClusterKvPairsKey struct { ClusterKvPairsName string `json:"kvname"` } -// Manager is an interface exposes the Cluster functionality +const SEPARATOR = "+" +const CONTEXT_CLUSTER_APP = "network-intents" +const CONTEXT_CLUSTER_RESOURCE = "network-intents" + +// ClusterManager is an interface exposes the Cluster functionality type ClusterManager interface { CreateClusterProvider(pr ClusterProvider) (ClusterProvider, error) GetClusterProvider(name string) (ClusterProvider, error) @@ -82,8 +95,12 @@ 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, error) GetClusters(provider string) ([]Cluster, error) + GetClustersWithLabel(provider, label string) ([]string, error) DeleteCluster(provider, name string) error + ApplyNetworkIntents(provider, name string) error + TerminateNetworkIntents(provider, name string) error CreateClusterLabel(provider, cluster string, pr ClusterLabel) (ClusterLabel, error) GetClusterLabel(provider, cluster, label string) (ClusterLabel, error) GetClusterLabels(provider, cluster string) ([]ClusterLabel, error) @@ -108,6 +125,7 @@ func NewClusterClient() *ClusterClient { storeName: "cluster", tagMeta: "clustermetadata", tagContent: "clustercontent", + tagContext: "clustercontext", }, } } @@ -287,6 +305,33 @@ 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, 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) + if err != nil { + return appcontext.AppContext{}, pkgerrors.Wrap(err, "Get Cluster Context") + } + + //value is a byte array + if value != nil { + ctxVal := string(value[0]) + var cc appcontext.AppContext + _, err = cc.LoadAppContext(ctxVal) + if err != nil { + return appcontext.AppContext{}, pkgerrors.Wrap(err, "Reinitializing Cluster AppContext") + } + return cc, nil + } + + return appcontext.AppContext{}, pkgerrors.New("Error getting Cluster AppContext") +} + // GetClusters returns all the Clusters for corresponding provider func (v *ClusterClient) GetClusters(provider string) ([]Cluster, error) { //Construct key and tag to select the entry @@ -314,6 +359,29 @@ func (v *ClusterClient) GetClusters(provider string) ([]Cluster, error) { return resp, nil } +// GetClustersWithLabel returns all the Clusters with Labels for provider +// Support Query like /cluster-providers/{Provider}/clusters?label={label} +func (v *ClusterClient) GetClustersWithLabel(provider, label string) ([]string, error) { + //Construct key and tag to select the entry + key := LabelKey{ + ClusterProviderName: provider, + ClusterLabelName: label, + } + + values, err := db.DBconn.Find(v.db.storeName, key, "cluster") + if err != nil { + return []string{}, pkgerrors.Wrap(err, "Get Clusters by label") + } + var resp []string + + for _, value := range values { + cp := string(value) + resp = append(resp, cp) + } + + return resp, nil +} + // DeleteCluster the Cluster from database func (v *ClusterClient) DeleteCluster(provider, name string) error { //Construct key and tag to select the entry @@ -321,8 +389,12 @@ 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) + } - err := db.DBconn.Remove(v.db.storeName, key) + err = db.DBconn.Remove(v.db.storeName, key) if err != nil { return pkgerrors.Wrap(err, "Delete Cluster Entry;") } @@ -330,6 +402,185 @@ func (v *ClusterClient) DeleteCluster(provider, name string) error { return nil } +// Apply Network Intents associated with a cluster +func (v *ClusterClient) ApplyNetworkIntents(provider, name string) error { + + _, err := v.GetClusterContext(provider, name) + if err == nil { + return pkgerrors.Errorf("Cluster network intents have already been applied: %v, %v", provider, name) + } + + type resource struct { + name string + value string + } + + var resources []resource + + // Find all Network Intents for this cluster + networkIntents, err := NewNetworkClient().GetNetworks(provider, name) + if err != nil { + return pkgerrors.Wrap(err, "Error finding Network Intents") + } + for _, intent := range networkIntents { + var crNetwork = CrNetwork{ + ApiVersion: NETWORK_APIVERSION, + Kind: NETWORK_KIND, + } + crNetwork.Network = intent + // Produce the yaml CR document for each intent + y, err := yaml.Marshal(&crNetwork) + if err != nil { + log.Info("Error marshalling network intent to yaml", log.Fields{ + "error": err, + "intent": intent, + }) + continue + } + resources = append(resources, resource{ + name: intent.Metadata.Name + SEPARATOR + NETWORK_KIND, + value: string(y), + }) + } + + // Find all Provider Network Intents for this cluster + providerNetworkIntents, err := NewProviderNetClient().GetProviderNets(provider, name) + if err != nil { + return pkgerrors.Wrap(err, "Error finding Provider Network Intents") + } + for _, intent := range providerNetworkIntents { + var crProviderNet = CrProviderNet{ + ApiVersion: PROVIDER_NETWORK_APIVERSION, + Kind: PROVIDER_NETWORK_KIND, + } + crProviderNet.ProviderNet = intent + // Produce the yaml CR document for each intent + y, err := yaml.Marshal(&crProviderNet) + if err != nil { + log.Info("Error marshalling provider network intent to yaml", log.Fields{ + "error": err, + "intent": intent, + }) + continue + } + resources = append(resources, resource{ + name: intent.Metadata.Name + SEPARATOR + PROVIDER_NETWORK_KIND, + value: string(y), + }) + } + + if len(resources) == 0 { + return nil + } + + // Make an app context for the network intent resources + context := appcontext.AppContext{} + ctxVal, err := context.InitAppContext() + if err != nil { + return pkgerrors.Wrap(err, "Error creating AppContext") + } + handle, err := context.CreateCompositeApp() + if err != nil { + return pkgerrors.Wrap(err, "Error creating AppContext CompositeApp") + } + + // Add an app (fixed value) to the app context + apphandle, err := context.AddApp(handle, CONTEXT_CLUSTER_APP) + if err != nil { + cleanuperr := context.DeleteCompositeApp() + if cleanuperr != nil { + log.Warn("Error cleaning AppContext CompositeApp create failure", log.Fields{ + "cluster-provider": provider, + "cluster": name, + }) + } + return pkgerrors.Wrap(err, "Error adding App to AppContext") + } + + // Add a cluster to the app + clusterhandle, err := context.AddCluster(apphandle, provider+SEPARATOR+name) + if err != nil { + cleanuperr := context.DeleteCompositeApp() + if cleanuperr != nil { + log.Warn("Error cleaning AppContext after add cluster failure", log.Fields{ + "cluster-provider": provider, + "cluster": name, + }) + } + return pkgerrors.Wrap(err, "Error adding Cluster to AppContext") + } + + // add the resources to the app context + for _, resource := range resources { + _, err = context.AddResource(clusterhandle, resource.name, resource.value) + if err != nil { + cleanuperr := context.DeleteCompositeApp() + if cleanuperr != nil { + log.Warn("Error cleaning AppContext after add resource failure", log.Fields{ + "cluster-provider": provider, + "cluster": name, + "resource": resource.name, + }) + } + return pkgerrors.Wrap(err, "Error adding Resource to AppContext") + } + } + + // save the context in the cluster db record + key := ClusterKey{ + ClusterProviderName: provider, + ClusterName: name, + } + err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagContext, ctxVal) + if err != nil { + cleanuperr := context.DeleteCompositeApp() + if cleanuperr != nil { + log.Warn("Error cleaning AppContext after DB insert failure", log.Fields{ + "cluster-provider": provider, + "cluster": name, + }) + } + return pkgerrors.Wrap(err, "Error adding AppContext to DB") + } + + // TODO: call resource synchronizer to instantiate the CRs in the cluster + + return nil +} + +// Terminate Network Intents associated with a cluster +func (v *ClusterClient) TerminateNetworkIntents(provider, name string) error { + context, err := v.GetClusterContext(provider, name) + if err != nil { + return pkgerrors.Wrapf(err, "Error finding AppContext for cluster: %v, %v", provider, name) + } + + // TODO: call resource synchronizer to terminate the CRs in the cluster + + // remove the app context + cleanuperr := context.DeleteCompositeApp() + if cleanuperr != nil { + log.Warn("Error deleted AppContext", log.Fields{ + "cluster-provider": provider, + "cluster": name, + }) + } + + // remove the app context field from the cluster db record + key := ClusterKey{ + ClusterProviderName: provider, + ClusterName: name, + } + err = db.DBconn.RemoveTag(v.db.storeName, key, v.db.tagContext) + if err != nil { + log.Warn("Error removing AppContext from Cluster document", log.Fields{ + "cluster-provider": provider, + "cluster": name, + }) + } + return nil +} + // CreateClusterLabel - create a new Cluster Label mongo document for a cluster-provider/cluster func (v *ClusterClient) CreateClusterLabel(provider string, cluster string, p ClusterLabel) (ClusterLabel, error) { //Construct key and tag to select the entry diff --git a/src/ncm/pkg/module/module.go b/src/ncm/pkg/module/module.go index a9950901..9655c1de 100644 --- a/src/ncm/pkg/module/module.go +++ b/src/ncm/pkg/module/module.go @@ -16,11 +16,14 @@ package module -// Client for using the services in the orchestrator +// Client for using the services in the ncm type Client struct { - Cluster *ClusterClient - Network *NetworkClient - ProviderNet *ProviderNetClient + Cluster *ClusterClient + Network *NetworkClient + ProviderNet *ProviderNetClient + NetControlIntent *NetControlIntentClient + WorkloadIntent *WorkloadIntentClient + WorkloadIfIntent *WorkloadIfIntentClient // Add Clients for API's here } @@ -30,6 +33,9 @@ func NewClient() *Client { c.Cluster = NewClusterClient() c.Network = NewNetworkClient() c.ProviderNet = NewProviderNetClient() + c.NetControlIntent = NewNetControlIntentClient() + c.WorkloadIntent = NewWorkloadIntentClient() + c.WorkloadIfIntent = NewWorkloadIfIntentClient() // Add Client API handlers here return c } diff --git a/src/ncm/pkg/module/module_definitions.go b/src/ncm/pkg/module/module_definitions.go index 1e839014..36c865a5 100644 --- a/src/ncm/pkg/module/module_definitions.go +++ b/src/ncm/pkg/module/module_definitions.go @@ -31,25 +31,32 @@ const CNI_TYPE_OVN4NFV string = "ovn4nfv" var CNI_TYPES = [...]string{CNI_TYPE_OVN4NFV} +const YAML_START = "---\n" +const YAML_END = "...\n" + // It implements the interface for managing the ClusterProviders +const MAX_DESCRIPTION_LEN int = 1024 +const MAX_USERDATA_LEN int = 4096 + type Metadata struct { - Name string `json:"name"` - Description string `json:"description"` - UserData1 string `json:"userData1"` - UserData2 string `json:"userData2"` + Name string `json:"name" yaml:"name"` + Description string `json:"description" yaml:"-"` + UserData1 string `json:"userData1" yaml:"-"` + UserData2 string `json:"userData2" yaml:"-"` } 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 } type Ipv4Subnet struct { - Subnet string `json:"subnet"` // CIDR notation, e.g. 172.16.33.0/24 - Name string `json:"name"` - Gateway string `json:"gateway"` // IPv4 addre, e.g. 172.16.33.1/24 - Exclude string `json:"excludeIps"` // space separated list of single IPs or ranges e.g. "172.16.33.2 172.16.33.5..172.16.33.10" + Subnet string `json:"subnet" yaml:"subnet"` // CIDR notation, e.g. 172.16.33.0/24 + Name string `json:"name" yaml:"name"` + Gateway string `json:"gateway" yaml:"gateway"` // IPv4 addre, e.g. 172.16.33.1/24 + Exclude string `json:"excludeIps" yaml:"excludeIps"` // space separated list of single IPs or ranges e.g. "172.16.33.2 172.16.33.5..172.16.33.10" } const VLAN_NODE_ANY = "any" @@ -58,11 +65,36 @@ const VLAN_NODE_SPECIFIC = "specific" var VLAN_NODE_SELECTORS = [...]string{VLAN_NODE_ANY, VLAN_NODE_SPECIFIC} type Vlan struct { - VlanId int `json:"vlanID"` - ProviderInterfaceName string `json:"providerInterfaceName"` - LogicalInterfaceName string `json:"logicalInterfaceName"` - VlanNodeSelector string `json:"vlanNodeSelector"` - NodeLabelList []string `json:"nodeLabelList"` + VlanId int `json:"vlanID" yaml:"vlanId"` + ProviderInterfaceName string `json:"providerInterfaceName" yaml:"providerInterfaceName"` + LogicalInterfaceName string `json:"logicalInterfaceName" yaml:"logicalInterfaceName"` + VlanNodeSelector string `json:"vlanNodeSelector" yaml:"vlanNodeSelector"` + NodeLabelList []string `json:"nodeLabelList" yaml:"nodeLabelList"` +} + +// Check for valid format Metadata +func IsValidMetadata(metadata Metadata) error { + errs := validation.IsValidName(metadata.Name) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid Metadata name=[%v], errors: %v", metadata.Name, errs) + } + + errs = validation.IsValidString(metadata.Description, 0, MAX_DESCRIPTION_LEN, validation.VALID_ANY_STR) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid Metadata description=[%v], errors: %v", metadata.Description, errs) + } + + errs = validation.IsValidString(metadata.UserData1, 0, MAX_DESCRIPTION_LEN, validation.VALID_ANY_STR) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid Metadata description=[%v], errors: %v", metadata.UserData1, errs) + } + + errs = validation.IsValidString(metadata.UserData2, 0, MAX_DESCRIPTION_LEN, validation.VALID_ANY_STR) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid Metadata description=[%v], errors: %v", metadata.UserData2, errs) + } + + return nil } // Check for valid format of an Ipv4Subnet diff --git a/src/ncm/pkg/module/netcontrolintent.go b/src/ncm/pkg/module/netcontrolintent.go new file mode 100644 index 00000000..5ef9dffe --- /dev/null +++ b/src/ncm/pkg/module/netcontrolintent.go @@ -0,0 +1,164 @@ +/* + * 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 module + +import ( + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" + + + pkgerrors "github.com/pkg/errors" +) + +// NetControlIntent contains the parameters needed for dynamic networks +type NetControlIntent struct { + Metadata Metadata `json:"metadata"` +} + +// NetControlIntentKey is the key structure that is used in the database +type NetControlIntentKey struct { + NetControlIntent string `json:"netcontrolintent"` + Project string `json:"project"` + CompositeApp string `json:"compositeapp"` + CompositeAppVersion string `json:"compositeappversion"` +} + +// 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 +} + +// NetControlIntentClient implements the Manager +// It will also be used to maintain some localized state +type NetControlIntentClient struct { + db ClientDbInfo +} + +// NewNetControlIntentClient returns an instance of the NetControlIntentClient +// which implements the Manager +func NewNetControlIntentClient() *NetControlIntentClient { + return &NetControlIntentClient{ + db: ClientDbInfo{ + storeName: "orchestrator", + tagMeta: "netcontrolintentmetadata", + }, + } +} + +// CreateNetControlIntent - create a new NetControlIntent +func (v *NetControlIntentClient) CreateNetControlIntent(nci NetControlIntent, project, compositeapp, compositeappversion string, exists bool) (NetControlIntent, error) { + + //Construct key and tag to select the entry + key := NetControlIntentKey{ + NetControlIntent: nci.Metadata.Name, + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + } + + //Check if this NetControlIntent already exists + _, err := v.GetNetControlIntent(nci.Metadata.Name, project, compositeapp, compositeappversion) + if err == nil && !exists { + return NetControlIntent{}, pkgerrors.New("NetControlIntent already exists") + } + + err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagMeta, nci) + if err != nil { + return NetControlIntent{}, pkgerrors.Wrap(err, "Creating DB Entry") + } + + return nci, nil +} + +// GetNetControlIntent returns the NetControlIntent for corresponding name +func (v *NetControlIntentClient) GetNetControlIntent(name, project, compositeapp, compositeappversion string) (NetControlIntent, error) { + + //Construct key and tag to select the entry + key := NetControlIntentKey{ + NetControlIntent: name, + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + } + + value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) + if err != nil { + return NetControlIntent{}, pkgerrors.Wrap(err, "Get NetControlIntent") + } + + //value is a byte array + if value != nil { + nci := NetControlIntent{} + err = db.DBconn.Unmarshal(value[0], &nci) + if err != nil { + return NetControlIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") + } + return nci, nil + } + + return NetControlIntent{}, pkgerrors.New("Error getting NetControlIntent") +} + +// GetNetControlIntentList returns all of the NetControlIntent for corresponding name +func (v *NetControlIntentClient) GetNetControlIntents(project, compositeapp, compositeappversion string) ([]NetControlIntent, error) { + + //Construct key and tag to select the entry + key := NetControlIntentKey{ + NetControlIntent: "", + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + } + + var resp []NetControlIntent + values, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) + if err != nil { + return []NetControlIntent{}, pkgerrors.Wrap(err, "Get NetControlIntents") + } + + for _, value := range values { + nci := NetControlIntent{} + err = db.DBconn.Unmarshal(value, &nci) + if err != nil { + return []NetControlIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") + } + resp = append(resp, nci) + } + + return resp, nil +} + +// Delete the NetControlIntent from database +func (v *NetControlIntentClient) DeleteNetControlIntent(name, project, compositeapp, compositeappversion string) error { + + //Construct key and tag to select the entry + key := NetControlIntentKey{ + NetControlIntent: name, + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + } + + err := db.DBconn.Remove(v.db.storeName, key) + if err != nil { + return pkgerrors.Wrap(err, "Delete NetControlIntent Entry;") + } + + return nil +} diff --git a/src/ncm/pkg/module/network.go b/src/ncm/pkg/module/network.go index 2d4121e9..cfb414c5 100644 --- a/src/ncm/pkg/module/network.go +++ b/src/ncm/pkg/module/network.go @@ -24,8 +24,8 @@ import ( // Network contains the parameters needed for dynamic networks type Network struct { - Metadata Metadata `json:"metadata"` - Spec NetworkSpec `json:"spec"` + Metadata Metadata `json:"metadata" yaml:"metadata"` + Spec NetworkSpec `json:"spec" yaml:"spec"` } type NetworkSpec struct { @@ -40,6 +40,16 @@ type NetworkKey struct { NetworkName string `json:"network"` } +// structure for the Network Custom Resource +type CrNetwork struct { + ApiVersion string `yaml:"apiVersion"` + Kind string `yaml:"kind"` + Network Network +} + +const NETWORK_APIVERSION = "k8s.plugin.opnfv.org/v1alpha1" +const NETWORK_KIND = "Network" + // Manager is an interface exposing the Network functionality type NetworkManager interface { CreateNetwork(pr Network, clusterProvider, cluster string, exists bool) (Network, error) diff --git a/src/ncm/pkg/module/providernet.go b/src/ncm/pkg/module/providernet.go index 5e2c0343..0435f2ba 100644 --- a/src/ncm/pkg/module/providernet.go +++ b/src/ncm/pkg/module/providernet.go @@ -29,12 +29,22 @@ type ProviderNet struct { } type ProviderNetSpec struct { - CniType string `json:"cniType"` - Ipv4Subnets []Ipv4Subnet `json:"ipv4Subnets"` - ProviderNetType string `json:"providerNetType"` - Vlan Vlan `json:"vlan"` + CniType string `json:"cniType" yaml:"cniType"` + Ipv4Subnets []Ipv4Subnet `json:"ipv4Subnets" yaml:"ipv4Subnets"` + ProviderNetType string `json:"providerNetType" yaml:"providerNetType"` + Vlan Vlan `json:"vlan" yaml:"vlan"` } +// structure for the Network Custom Resource +type CrProviderNet struct { + ApiVersion string `yaml:"apiVersion"` + Kind string `yaml:"kind"` + ProviderNet ProviderNet +} + +const PROVIDER_NETWORK_APIVERSION = "k8s.plugin.opnfv.org/v1alpha1" +const PROVIDER_NETWORK_KIND = "ProviderNetwork" + // ProviderNetKey is the key structure that is used in the database type ProviderNetKey struct { ClusterProviderName string `json:"provider"` diff --git a/src/ncm/pkg/module/workloadifintent.go b/src/ncm/pkg/module/workloadifintent.go new file mode 100644 index 00000000..55062564 --- /dev/null +++ b/src/ncm/pkg/module/workloadifintent.go @@ -0,0 +1,188 @@ +/* + * 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 module + +import ( + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" + + pkgerrors "github.com/pkg/errors" +) + +// WorkloadIfIntent contains the parameters needed for dynamic networks +type WorkloadIfIntent struct { + Metadata Metadata `json:"metadata"` + Spec WorkloadIfIntentSpec `json:"spec"` +} + +type WorkloadIfIntentSpec struct { + IfName string `json:"interface"` + NetworkName string `json:"name"` + DefaultGateway string `json:"defaultGateway"` // optional, default value is "false" + IpAddr string `json:"ipAddress,omitempty"` // optional, if not provided then will be dynamically allocated + MacAddr string `json:"macAddress,omitempty"` // optional, if not provided then will be dynamically allocated +} + +// WorkloadIfIntentKey is the key structure that is used in the database +type WorkloadIfIntentKey struct { + Project string `json:"provider"` + CompositeApp string `json:"compositeapp"` + CompositeAppVersion string `json:"compositeappversion"` + NetControlIntent string `json:"netcontrolintent"` + WorkloadIntent string `json:"workloadintent"` + WorkloadIfIntent string `json:"workloadifintent"` +} + +// 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 +} + +// WorkloadIfIntentClient implements the Manager +// It will also be used to maintain some localized state +type WorkloadIfIntentClient struct { + db ClientDbInfo +} + +// NewWorkloadIfIntentClient returns an instance of the WorkloadIfIntentClient +// which implements the Manager +func NewWorkloadIfIntentClient() *WorkloadIfIntentClient { + return &WorkloadIfIntentClient{ + db: ClientDbInfo{ + storeName: "orchestrator", + tagMeta: "workloadifintentmetadata", + }, + } +} + +// CreateWorkloadIfIntent - create a new WorkloadIfIntent +func (v *WorkloadIfIntentClient) CreateWorkloadIfIntent(wif WorkloadIfIntent, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string, exists bool) (WorkloadIfIntent, error) { + + //Construct key and tag to select the entry + key := WorkloadIfIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: workloadintent, + WorkloadIfIntent: wif.Metadata.Name, + } + + //Check if the Workload Intent exists + _, err := NewWorkloadIntentClient().GetWorkloadIntent(workloadintent, project, compositeapp, compositeappversion, 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) + if err == nil && !exists { + return WorkloadIfIntent{}, pkgerrors.New("WorkloadIfIntent already exists") + } + + err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagMeta, wif) + if err != nil { + return WorkloadIfIntent{}, pkgerrors.Wrap(err, "Creating DB Entry") + } + + return wif, nil +} + +// GetWorkloadIfIntent returns the WorkloadIfIntent for corresponding name +func (v *WorkloadIfIntentClient) GetWorkloadIfIntent(name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) (WorkloadIfIntent, error) { + + //Construct key and tag to select the entry + key := WorkloadIfIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: workloadintent, + WorkloadIfIntent: name, + } + + value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) + if err != nil { + return WorkloadIfIntent{}, pkgerrors.Wrap(err, "Get WorkloadIfIntent") + } + + //value is a byte array + if value != nil { + wif := WorkloadIfIntent{} + err = db.DBconn.Unmarshal(value[0], &wif) + if err != nil { + return WorkloadIfIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") + } + return wif, nil + } + + return WorkloadIfIntent{}, pkgerrors.New("Error getting WorkloadIfIntent") +} + +// GetWorkloadIfIntentList returns all of the WorkloadIfIntent for corresponding name +func (v *WorkloadIfIntentClient) GetWorkloadIfIntents(project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) ([]WorkloadIfIntent, error) { + + //Construct key and tag to select the entry + key := WorkloadIfIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: workloadintent, + WorkloadIfIntent: "", + } + + var resp []WorkloadIfIntent + values, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) + if err != nil { + return []WorkloadIfIntent{}, pkgerrors.Wrap(err, "Get WorkloadIfIntents") + } + + for _, value := range values { + wif := WorkloadIfIntent{} + err = db.DBconn.Unmarshal(value, &wif) + if err != nil { + return []WorkloadIfIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") + } + resp = append(resp, wif) + } + + return resp, nil +} + +// Delete the WorkloadIfIntent from database +func (v *WorkloadIfIntentClient) DeleteWorkloadIfIntent(name, project, compositeapp, compositeappversion, netcontrolintent, workloadintent string) error { + + //Construct key and tag to select the entry + key := WorkloadIfIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: workloadintent, + WorkloadIfIntent: name, + } + + err := db.DBconn.Remove(v.db.storeName, key) + if err != nil { + return pkgerrors.Wrap(err, "Delete WorkloadIfIntent Entry;") + } + + return nil +} diff --git a/src/ncm/pkg/module/workloadintent.go b/src/ncm/pkg/module/workloadintent.go new file mode 100644 index 00000000..e6916954 --- /dev/null +++ b/src/ncm/pkg/module/workloadintent.go @@ -0,0 +1,181 @@ +/* + * 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 module + +import ( + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" + + pkgerrors "github.com/pkg/errors" +) + +// WorkloadIntent contains the parameters needed for dynamic networks +type WorkloadIntent struct { + Metadata Metadata `json:"metadata"` + Spec WorkloadIntentSpec `json:"spec"` +} + +type WorkloadIntentSpec struct { + AppName string `json:"application-name"` + WorkloadResource string `json:"workload-resource"` + Type string `json:"type"` +} + +// WorkloadIntentKey is the key structure that is used in the database +type WorkloadIntentKey struct { + Project string `json:"provider"` + CompositeApp string `json:"compositeapp"` + CompositeAppVersion string `json:"compositeappversion"` + 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 +} + +// WorkloadIntentClient implements the Manager +// It will also be used to maintain some localized state +type WorkloadIntentClient struct { + db ClientDbInfo +} + +// NewWorkloadIntentClient returns an instance of the WorkloadIntentClient +// which implements the Manager +func NewWorkloadIntentClient() *WorkloadIntentClient { + return &WorkloadIntentClient{ + db: ClientDbInfo{ + storeName: "orchestrator", + tagMeta: "workloadintentmetadata", + }, + } +} + +// CreateWorkloadIntent - create a new WorkloadIntent +func (v *WorkloadIntentClient) CreateWorkloadIntent(wi WorkloadIntent, project, compositeapp, compositeappversion, netcontrolintent string, exists bool) (WorkloadIntent, error) { + + //Construct key and tag to select the entry + key := WorkloadIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: wi.Metadata.Name, + } + + //Check if the Network Control Intent exists + _, err := NewNetControlIntentClient().GetNetControlIntent(netcontrolintent, project, compositeapp, compositeappversion) + 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) + if err == nil && !exists { + return WorkloadIntent{}, pkgerrors.New("WorkloadIntent already exists") + } + + err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagMeta, wi) + if err != nil { + return WorkloadIntent{}, pkgerrors.Wrap(err, "Creating DB Entry") + } + + return wi, nil +} + +// GetWorkloadIntent returns the WorkloadIntent for corresponding name +func (v *WorkloadIntentClient) GetWorkloadIntent(name, project, compositeapp, compositeappversion, netcontrolintent string) (WorkloadIntent, error) { + + //Construct key and tag to select the entry + key := WorkloadIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: name, + } + + value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) + if err != nil { + return WorkloadIntent{}, pkgerrors.Wrap(err, "Get WorkloadIntent") + } + + //value is a byte array + if value != nil { + wi := WorkloadIntent{} + err = db.DBconn.Unmarshal(value[0], &wi) + if err != nil { + return WorkloadIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") + } + return wi, nil + } + + return WorkloadIntent{}, pkgerrors.New("Error getting WorkloadIntent") +} + +// GetWorkloadIntentList returns all of the WorkloadIntent for corresponding name +func (v *WorkloadIntentClient) GetWorkloadIntents(project, compositeapp, compositeappversion, netcontrolintent string) ([]WorkloadIntent, error) { + + //Construct key and tag to select the entry + key := WorkloadIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: "", + } + + var resp []WorkloadIntent + values, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta) + if err != nil { + return []WorkloadIntent{}, pkgerrors.Wrap(err, "Get WorkloadIntents") + } + + for _, value := range values { + wi := WorkloadIntent{} + err = db.DBconn.Unmarshal(value, &wi) + if err != nil { + return []WorkloadIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value") + } + resp = append(resp, wi) + } + + return resp, nil +} + +// Delete the WorkloadIntent from database +func (v *WorkloadIntentClient) DeleteWorkloadIntent(name, project, compositeapp, compositeappversion, netcontrolintent string) error { + + //Construct key and tag to select the entry + key := WorkloadIntentKey{ + Project: project, + CompositeApp: compositeapp, + CompositeAppVersion: compositeappversion, + NetControlIntent: netcontrolintent, + WorkloadIntent: name, + } + + err := db.DBconn.Remove(v.db.storeName, key) + if err != nil { + return pkgerrors.Wrap(err, "Delete WorkloadIntent Entry;") + } + + return nil +} |