aboutsummaryrefslogtreecommitdiffstats
path: root/src/ovnaction/pkg
diff options
context:
space:
mode:
authorEric Multanen <eric.w.multanen@intel.com>2020-05-28 17:07:20 -0700
committerEric Multanen <eric.w.multanen@intel.com>2020-06-02 14:00:07 -0700
commitad7782cbf83c11f152a6457f3808a4da99a1ae56 (patch)
treee88276d8f0d55bd58a903d1c31ab4e43e4011193 /src/ovnaction/pkg
parentc257a136355a794f5bf778f670c041e8958c3608 (diff)
Create OVN network action controller from ncm
Split out part of ncm microservice to act as the Onv4k8s network action controller for the orchestrator. No code changes really - just moving around to fit the architectural plan. Issue-ID: MULTICLOUD-1029 Signed-off-by: Eric Multanen <eric.w.multanen@intel.com> Change-Id: I17292ac72d041050269f05fc4a0c2a6ca741aeb5
Diffstat (limited to 'src/ovnaction/pkg')
-rw-r--r--src/ovnaction/pkg/grpc/contextupdateserver/contextupdateserver.go45
-rw-r--r--src/ovnaction/pkg/grpc/register.go58
-rw-r--r--src/ovnaction/pkg/module/chaining.go209
-rw-r--r--src/ovnaction/pkg/module/module.go37
-rw-r--r--src/ovnaction/pkg/module/module_definitions.go68
-rw-r--r--src/ovnaction/pkg/module/netcontrolintent.go295
-rw-r--r--src/ovnaction/pkg/module/resources.go273
-rw-r--r--src/ovnaction/pkg/module/workloadifintent.go188
-rw-r--r--src/ovnaction/pkg/module/workloadintent.go181
9 files changed, 1354 insertions, 0 deletions
diff --git a/src/ovnaction/pkg/grpc/contextupdateserver/contextupdateserver.go b/src/ovnaction/pkg/grpc/contextupdateserver/contextupdateserver.go
new file mode 100644
index 00000000..fc548ccc
--- /dev/null
+++ b/src/ovnaction/pkg/grpc/contextupdateserver/contextupdateserver.go
@@ -0,0 +1,45 @@
+/*
+Copyright 2020 Intel Corporation.
+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 contextupdateserver
+
+import (
+ "context"
+ "encoding/json"
+ "log"
+
+ contextpb "github.com/onap/multicloud-k8s/src/orchestrator/pkg/grpc/contextupdate"
+ //"google.golang.org/grpc/codes"
+ //"google.golang.org/grpc/status"
+)
+
+type contextupdateServer struct {
+ contextpb.UnimplementedContextupdateServer
+}
+
+func (cs *contextupdateServer) UpdateAppContext(ctx context.Context, req *contextpb.ContextUpdateRequest) (*contextpb.ContextUpdateResponse, error) {
+ contextUpdateReq, _ := json.Marshal(req)
+ log.Println("GRPC Server received contextupdateRequest: ", string(contextUpdateReq))
+
+ // Insert call to Server Functionality here
+ //
+ //
+
+ return &contextpb.ContextUpdateResponse{AppContextUpdated: true}, nil
+}
+
+// NewContextUpdateServer exported
+func NewContextupdateServer() *contextupdateServer {
+ s := &contextupdateServer{}
+ return s
+}
diff --git a/src/ovnaction/pkg/grpc/register.go b/src/ovnaction/pkg/grpc/register.go
new file mode 100644
index 00000000..4a31cf9d
--- /dev/null
+++ b/src/ovnaction/pkg/grpc/register.go
@@ -0,0 +1,58 @@
+/*
+Copyright 2020 Intel Corporation.
+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 grpc
+
+import (
+ "os"
+ "strconv"
+ "strings"
+
+ log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils"
+)
+
+const default_host = "localhost"
+const default_port = 9032
+const default_ovnaction_name = "ovnaction"
+const ENV_OVNACTION_NAME = "OVNACTION_NAME"
+
+func GetServerHostPort() (string, int) {
+
+ // expect name of this ncm program to be in env variable "OVNACTION_NAME" - e.g. OVNACTION_NAME="ncm"
+ serviceName := os.Getenv(ENV_OVNACTION_NAME)
+ if serviceName == "" {
+ serviceName = default_ovnaction_name
+ log.Info("Using default name for OVNACTION service name", log.Fields{
+ "Name": serviceName,
+ })
+ }
+
+ // expect service name to be in env variable - e.g. OVNACTION_SERVICE_HOST
+ host := os.Getenv(strings.ToUpper(serviceName) + "_SERVICE_HOST")
+ if host == "" {
+ host = default_host
+ log.Info("Using default host for ovnaction gRPC controller", log.Fields{
+ "Host": host,
+ })
+ }
+
+ // expect service port to be in env variable - e.g. OVNACTION_SERVICE_PORT
+ port, err := strconv.Atoi(os.Getenv(strings.ToUpper(serviceName) + "_SERVICE_PORT"))
+ if err != nil || port < 0 {
+ port = default_port
+ log.Info("Using default port for ovnaction gRPC controller", log.Fields{
+ "Port": port,
+ })
+ }
+ return host, port
+}
diff --git a/src/ovnaction/pkg/module/chaining.go b/src/ovnaction/pkg/module/chaining.go
new file mode 100644
index 00000000..45f061fa
--- /dev/null
+++ b/src/ovnaction/pkg/module/chaining.go
@@ -0,0 +1,209 @@
+/*
+ * 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"
+)
+
+// Chain defines the high level structure of a network chain document
+type Chain struct {
+ Metadata Metadata `json:"metadata" yaml:"metadata"`
+ Spec NetworkChainingSpec `json:"spec" yaml:"spec"`
+}
+
+// NetworkChainingSpec contains the specification of a network chain
+type NetworkChainingSpec struct {
+ ChainType string `json:"type"`
+ RoutingSpec RouteSpec `json:"routingSpec"`
+}
+
+// RouteSpec contains the routing specificaiton of a network chain
+type RouteSpec struct {
+ LeftNetwork []RoutingNetwork `json:"leftNetwork"`
+ RightNetwork []RoutingNetwork `json:"rightNetwork"`
+ NetworkChain string `json:"networkChain"`
+ Namespace string `json:"namespace"`
+}
+
+// RoutingNetwork contains the route networkroute network details for en element of a network chain
+type RoutingNetwork struct {
+ NetworkName string `json:"networkName"`
+ GatewayIP string `json:"gatewayIp"`
+ Subnet string `json:"subnet"`
+}
+
+// ChainKey is the key structure that is used in the database
+type ChainKey struct {
+ Project string `json:"project"`
+ CompositeApp string `json:"compositeapp"`
+ CompositeAppVersion string `json:"compositeappversion"`
+ NetControlIntent string `json:"netcontrolintent"`
+ NetworkChain string `json:"networkchain"`
+}
+
+// CrChain is the structure for the Network Chain Custom Resource
+type CrChain struct {
+ APIVersion string `yaml:"apiVersion"`
+ Kind string `yaml:"kind"`
+ Chain Chain
+}
+
+// RoutingChainType is currently only defined chaining type
+const RoutingChainType = "routing"
+
+// ChainingAPIVersion is the kubernetes version of a network chain custom resource
+const ChainingAPIVersion = "k8s.plugin.opnfv.org/v1"
+
+// ChainingKind is the Kind string for a network chain
+const ChainingKind = "NetworkChaining"
+
+// ChainManager is an interface exposing the Chain functionality
+type ChainManager interface {
+ CreateChain(ch Chain, pr, ca, caver, netctrlint string, exists bool) (Chain, error)
+ GetChain(name, pr, ca, caver, netctrlint string) (Chain, error)
+ GetChains(pr, ca, caver, netctrlint string) ([]Chain, error)
+ DeleteChain(name, pr, ca, caver, netctrlint string) error
+}
+
+// ChainClient implements the Manager
+// It will also be used to maintain some localized state
+type ChainClient struct {
+ db ClientDbInfo
+}
+
+// NewChainClient returns an instance of the ChainClient
+// which implements the Manager
+func NewChainClient() *ChainClient {
+ return &ChainClient{
+ db: ClientDbInfo{
+ storeName: "orchestrator",
+ tagMeta: "chainmetadata",
+ },
+ }
+}
+
+// CreateChain - create a new Chain
+func (v *ChainClient) CreateChain(ch Chain, pr, ca, caver, netctrlint string, exists bool) (Chain, error) {
+ //Construct key and tag to select the entry
+ key := ChainKey{
+ Project: pr,
+ CompositeApp: ca,
+ CompositeAppVersion: caver,
+ NetControlIntent: netctrlint,
+ NetworkChain: ch.Metadata.Name,
+ }
+
+ //Check if the Network Control Intent exists
+ _, err := NewNetControlIntentClient().GetNetControlIntent(netctrlint, pr, ca, caver)
+ if err != nil {
+ return Chain{}, pkgerrors.Errorf("Network Control Intent %v does not exist", netctrlint)
+ }
+
+ //Check if this Chain already exists
+ _, err = v.GetChain(ch.Metadata.Name, pr, ca, caver, netctrlint)
+ if err == nil && !exists {
+ return Chain{}, pkgerrors.New("Chain already exists")
+ }
+
+ err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagMeta, ch)
+ if err != nil {
+ return Chain{}, pkgerrors.Wrap(err, "Creating DB Entry")
+ }
+
+ return ch, nil
+}
+
+// GetChain returns the Chain for corresponding name
+func (v *ChainClient) GetChain(name, pr, ca, caver, netctrlint string) (Chain, error) {
+ //Construct key and tag to select the entry
+ key := ChainKey{
+ Project: pr,
+ CompositeApp: ca,
+ CompositeAppVersion: caver,
+ NetControlIntent: netctrlint,
+ NetworkChain: name,
+ }
+
+ value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta)
+ if err != nil {
+ return Chain{}, pkgerrors.Wrap(err, "Get Chain")
+ }
+
+ //value is a byte array
+ if value != nil {
+ ch := Chain{}
+ err = db.DBconn.Unmarshal(value[0], &ch)
+ if err != nil {
+ return Chain{}, pkgerrors.Wrap(err, "Unmarshalling Value")
+ }
+ return ch, nil
+ }
+
+ return Chain{}, pkgerrors.New("Error getting Chain")
+}
+
+// GetChains returns all of the Chains for for the given network control intent
+func (v *ChainClient) GetChains(pr, ca, caver, netctrlint string) ([]Chain, error) {
+ //Construct key and tag to select the entry
+ key := ChainKey{
+ Project: pr,
+ CompositeApp: ca,
+ CompositeAppVersion: caver,
+ NetControlIntent: netctrlint,
+ NetworkChain: "",
+ }
+
+ var resp []Chain
+ values, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta)
+ if err != nil {
+ return []Chain{}, pkgerrors.Wrap(err, "Get Chains")
+ }
+
+ for _, value := range values {
+ cp := Chain{}
+ err = db.DBconn.Unmarshal(value, &cp)
+ if err != nil {
+ return []Chain{}, pkgerrors.Wrap(err, "Unmarshalling Value")
+ }
+ resp = append(resp, cp)
+ }
+
+ return resp, nil
+}
+
+// DeleteChain deletes the Chain from the database
+func (v *ChainClient) DeleteChain(name, pr, ca, caver, netctrlint string) error {
+
+ //Construct key and tag to select the entry
+ key := ChainKey{
+ Project: pr,
+ CompositeApp: ca,
+ CompositeAppVersion: caver,
+ NetControlIntent: netctrlint,
+ NetworkChain: name,
+ }
+
+ err := db.DBconn.Remove(v.db.storeName, key)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Delete Chain Entry;")
+ }
+
+ return nil
+}
diff --git a/src/ovnaction/pkg/module/module.go b/src/ovnaction/pkg/module/module.go
new file mode 100644
index 00000000..2b4b9358
--- /dev/null
+++ b/src/ovnaction/pkg/module/module.go
@@ -0,0 +1,37 @@
+/*
+ * 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
+
+// Client for using the services in the ncm
+type Client struct {
+ NetControlIntent *NetControlIntentClient
+ WorkloadIntent *WorkloadIntentClient
+ WorkloadIfIntent *WorkloadIfIntentClient
+ Chain *ChainClient
+ // Add Clients for API's here
+}
+
+// NewClient creates a new client for using the services
+func NewClient() *Client {
+ c := &Client{}
+ c.NetControlIntent = NewNetControlIntentClient()
+ c.WorkloadIntent = NewWorkloadIntentClient()
+ c.WorkloadIfIntent = NewWorkloadIfIntentClient()
+ c.Chain = NewChainClient()
+ // Add Client API handlers here
+ return c
+}
diff --git a/src/ovnaction/pkg/module/module_definitions.go b/src/ovnaction/pkg/module/module_definitions.go
new file mode 100644
index 00000000..a868fdaf
--- /dev/null
+++ b/src/ovnaction/pkg/module/module_definitions.go
@@ -0,0 +1,68 @@
+/*
+ * 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/validation"
+ pkgerrors "github.com/pkg/errors"
+)
+
+const CNI_TYPE_OVN4NFV string = "ovn4nfv"
+
+var CNI_TYPES = [...]string{CNI_TYPE_OVN4NFV}
+
+// 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" 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
+}
+
+// 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
+}
diff --git a/src/ovnaction/pkg/module/netcontrolintent.go b/src/ovnaction/pkg/module/netcontrolintent.go
new file mode 100644
index 00000000..c005a935
--- /dev/null
+++ b/src/ovnaction/pkg/module/netcontrolintent.go
@@ -0,0 +1,295 @@
+/*
+ * 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 (
+ "encoding/json"
+ "strings"
+
+ jyaml "github.com/ghodss/yaml"
+
+ nettypes "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
+ "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext"
+ "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db"
+ log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/client-go/kubernetes/scheme"
+
+ pkgerrors "github.com/pkg/errors"
+)
+
+// 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
+ ApplyNetControlIntent(name, project, compositeapp, compositeappversion, appContextId 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
+}
+
+// (Test Routine) - Apply network-control-intent
+func (v *NetControlIntentClient) ApplyNetControlIntent(name, project, compositeapp, compositeappversion, appContextId string) error {
+ // TODO: Handle all Network Chain Intents for the Network Control Intent
+
+ // Handle all Workload Intents for the Network Control Intent
+ wis, err := NewWorkloadIntentClient().GetWorkloadIntents(project, compositeapp, compositeappversion, name)
+ if err != nil {
+ return pkgerrors.Wrapf(err, "Error getting Workload Intents for Network Control Intent %v for %v/%v%v not found", name, project, compositeapp, compositeappversion)
+ }
+
+ // Setup the AppContext
+ var context appcontext.AppContext
+ _, err = context.LoadAppContext(appContextId)
+ if err != nil {
+ return pkgerrors.Wrapf(err, "Error getting AppContext with Id: %v for %v/%v%v",
+ appContextId, project, compositeapp, compositeappversion)
+ }
+
+ // Handle all intents (currently just Interface intents) for each Workload Intent
+ for _, wi := range wis {
+ // The app/resource identified in the workload intent needs to be updated with two annotations.
+ // 1 - The "k8s.v1.cni.cncf.io/networks" annotation will have {"name": "ovn-networkobj", "namespace": "default"} added
+ // to it (preserving any existing values for this annotation.
+ // 2 - The "k8s.plugin.opnfv.org/nfn-network" annotation will add any network interfaces that are provided by the
+ // workload/interfaces intents.
+
+ // Prepare the list of interfaces from the workload intent
+ wifs, err := NewWorkloadIfIntentClient().GetWorkloadIfIntents(project,
+ compositeapp,
+ compositeappversion,
+ name,
+ wi.Metadata.Name)
+ if err != nil {
+ return pkgerrors.Wrapf(err,
+ "Error getting Workload Interface Intents for Workload Intent %v under Network Control Intent %v for %v/%v%v not found",
+ wi.Metadata.Name, name, project, compositeapp, compositeappversion)
+ }
+ if len(wifs) == 0 {
+ log.Warn("No interface intents provided for workload intent", log.Fields{
+ "project": project,
+ "composite app": compositeapp,
+ "composite app version": compositeappversion,
+ "network control intent": name,
+ "workload intent": wi.Metadata.Name,
+ })
+ continue
+ }
+
+ // Get all clusters for the current App from the AppContext
+ clusters, err := context.GetClusterNames(wi.Spec.AppName)
+ for _, c := range clusters {
+ rh, err := context.GetResourceHandle(wi.Spec.AppName, c,
+ strings.Join([]string{wi.Spec.WorkloadResource, wi.Spec.Type}, "+"))
+ if err != nil {
+ log.Warn("App Context resource handle not found", log.Fields{
+ "project": project,
+ "composite app": compositeapp,
+ "composite app version": compositeappversion,
+ "network control intent": name,
+ "workload name": wi.Metadata.Name,
+ "app": wi.Spec.AppName,
+ "resource": wi.Spec.WorkloadResource,
+ "resource type": wi.Spec.Type,
+ })
+ continue
+ }
+ r, err := context.GetValue(rh)
+ if err != nil {
+ log.Error("Error retrieving resource from App Context", log.Fields{
+ "error": err,
+ "resource handle": rh,
+ })
+ }
+
+ // Unmarshal resource to K8S object
+ robj, err := runtime.Decode(scheme.Codecs.UniversalDeserializer(), []byte(r.(string)))
+
+ // Add network annotation to object
+ netAnnot := nettypes.NetworkSelectionElement{
+ Name: "ovn-networkobj",
+ Namespace: "default",
+ }
+ AddNetworkAnnotation(robj, netAnnot)
+
+ // Add nfn interface annotations to object
+ var newNfnIfs []WorkloadIfIntentSpec
+ for _, i := range wifs {
+ newNfnIfs = append(newNfnIfs, i.Spec)
+ }
+ AddNfnAnnotation(robj, newNfnIfs)
+
+ // Marshal object back to yaml format (via json - seems to eliminate most clutter)
+ j, err := json.Marshal(robj)
+ if err != nil {
+ log.Error("Error marshalling resource to JSON", log.Fields{
+ "error": err,
+ })
+ continue
+ }
+ y, err := jyaml.JSONToYAML(j)
+ if err != nil {
+ log.Error("Error marshalling resource to YAML", log.Fields{
+ "error": err,
+ })
+ continue
+ }
+
+ // Update resource in AppContext
+ err = context.UpdateResourceValue(rh, string(y))
+ if err != nil {
+ log.Error("Network updating app context resource handle", log.Fields{
+ "error": err,
+ "resource handle": rh,
+ })
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/src/ovnaction/pkg/module/resources.go b/src/ovnaction/pkg/module/resources.go
new file mode 100644
index 00000000..24c9833e
--- /dev/null
+++ b/src/ovnaction/pkg/module/resources.go
@@ -0,0 +1,273 @@
+/*
+ * 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 (
+ "encoding/json"
+ "fmt"
+
+ nettypes "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
+ netutils "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/utils"
+ log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils"
+ v1 "k8s.io/api/apps/v1"
+ batch "k8s.io/api/batch/v1"
+ batchv1beta1 "k8s.io/api/batch/v1beta1"
+ v1core "k8s.io/api/core/v1"
+ _ "k8s.io/kubernetes/pkg/apis/apps/install"
+ _ "k8s.io/kubernetes/pkg/apis/batch/install"
+ _ "k8s.io/kubernetes/pkg/apis/core/install"
+ _ "k8s.io/kubernetes/pkg/apis/extensions/install"
+
+ pkgerrors "github.com/pkg/errors"
+)
+
+type NfnAnnotation struct {
+ CniType string
+ Interface []WorkloadIfIntentSpec
+}
+
+const NfnAnnotationKey = "k8s.plugin.opnfv.org/nfn-network"
+
+// ParsePodTemplateNetworkAnnotation parses Pod annotation in PodTemplate
+func ParsePodTemplateNetworkAnnotation(pt *v1core.PodTemplateSpec) ([]*nettypes.NetworkSelectionElement, error) {
+ netAnnot := pt.Annotations[nettypes.NetworkAttachmentAnnot]
+ defaultNamespace := pt.Namespace
+
+ if len(netAnnot) == 0 {
+ return nil, pkgerrors.Errorf("No kubernetes network annotation found")
+ }
+
+ networks, err := netutils.ParseNetworkAnnotation(netAnnot, defaultNamespace)
+ if err != nil {
+ return nil, err
+ }
+ return networks, nil
+}
+
+// GetPodTemplateNetworkAnnotation gets Pod Nfn annotation in PodTemplate
+func GetPodTemplateNfnAnnotation(pt *v1core.PodTemplateSpec) NfnAnnotation {
+ var nfn NfnAnnotation
+
+ nfnAnnot := pt.Annotations[NfnAnnotationKey]
+ if len(nfnAnnot) == 0 {
+ return nfn
+ }
+
+ err := json.Unmarshal([]byte(nfnAnnot), &nfn)
+ if err != nil {
+ log.Warn("Error unmarshalling nfn annotation", log.Fields{
+ "annotation": nfnAnnot,
+ })
+ }
+ return nfn
+}
+
+// GetPodNetworkAnnotation gets Pod Nfn annotation in PodTemplate
+func GetPodNfnAnnotation(p *v1core.Pod) NfnAnnotation {
+ var nfn NfnAnnotation
+
+ nfnAnnot := p.Annotations[NfnAnnotationKey]
+ if len(nfnAnnot) == 0 {
+ return nfn
+ }
+
+ err := json.Unmarshal([]byte(nfnAnnot), &nfn)
+ if err != nil {
+ log.Warn("Error unmarshalling nfn annotation", log.Fields{
+ "annotation": nfnAnnot,
+ })
+ }
+ return nfn
+}
+
+func addNetworkAnnotation(a nettypes.NetworkSelectionElement, as []*nettypes.NetworkSelectionElement) []*nettypes.NetworkSelectionElement {
+ var netElements []*nettypes.NetworkSelectionElement
+
+ found := false
+ for _, e := range as {
+ if e.Name == a.Name {
+ found = true
+ }
+ netElements = append(netElements, e)
+ }
+ if !found {
+ netElements = append(netElements, &a)
+ }
+
+ return netElements
+}
+
+// Add the interfaces in the 'new' parameter to the nfn annotation
+func newNfnIfs(nfn NfnAnnotation, new []WorkloadIfIntentSpec) NfnAnnotation {
+ // Prepare a new interface list - combining the original plus new ones
+ var newNfn NfnAnnotation
+
+ if nfn.CniType != CNI_TYPE_OVN4NFV {
+ if len(nfn.CniType) > 0 {
+ log.Warn("Error existing nfn cnitype is invalid", log.Fields{
+ "existing cnitype": nfn.CniType,
+ "using cnitype": CNI_TYPE_OVN4NFV,
+ })
+ }
+ }
+ newNfn.CniType = CNI_TYPE_OVN4NFV
+
+ // update any interfaces already in the list with the updated interface
+ for _, i := range nfn.Interface {
+ for _, j := range new {
+ if i.NetworkName == j.NetworkName && i.IfName == j.IfName {
+ i.DefaultGateway = j.DefaultGateway
+ i.IpAddr = j.IpAddr
+ i.MacAddr = j.MacAddr
+ break
+ }
+ }
+ newNfn.Interface = append(newNfn.Interface, i)
+ }
+
+ // add new interfaces not present in original list
+ for _, j := range new {
+ found := false
+ for _, i := range nfn.Interface {
+ if i.NetworkName == j.NetworkName && i.IfName == j.IfName {
+ found = true
+ break
+ }
+ }
+ if !found {
+ newNfn.Interface = append(newNfn.Interface, j)
+ }
+ }
+ return newNfn
+}
+
+func updatePodTemplateNetworkAnnotation(pt *v1core.PodTemplateSpec, a nettypes.NetworkSelectionElement) {
+ netAnnotation, _ := ParsePodTemplateNetworkAnnotation(pt)
+ elements := addNetworkAnnotation(a, netAnnotation)
+ j, err := json.Marshal(elements)
+ if err != nil {
+ log.Error("Existing network annotation has invalid format", log.Fields{
+ "error": err,
+ })
+ return
+ }
+ if pt.Annotations == nil {
+ pt.Annotations = make(map[string]string)
+ }
+ pt.Annotations[nettypes.NetworkAttachmentAnnot] = string(j)
+}
+
+// Add a network annotation to the resource
+func AddNetworkAnnotation(r interface{}, a nettypes.NetworkSelectionElement) {
+
+ switch o := r.(type) {
+ case *batch.Job:
+ updatePodTemplateNetworkAnnotation(&o.Spec.Template, a)
+ case *batchv1beta1.CronJob:
+ updatePodTemplateNetworkAnnotation(&o.Spec.JobTemplate.Spec.Template, a)
+ case *v1.DaemonSet:
+ updatePodTemplateNetworkAnnotation(&o.Spec.Template, a)
+ case *v1.Deployment:
+ updatePodTemplateNetworkAnnotation(&o.Spec.Template, a)
+ case *v1.ReplicaSet:
+ updatePodTemplateNetworkAnnotation(&o.Spec.Template, a)
+ case *v1.StatefulSet:
+ updatePodTemplateNetworkAnnotation(&o.Spec.Template, a)
+ case *v1core.Pod:
+ netAnnotation, _ := netutils.ParsePodNetworkAnnotation(o)
+ elements := addNetworkAnnotation(a, netAnnotation)
+ j, err := json.Marshal(elements)
+ if err != nil {
+ log.Error("Existing network annotation has invalid format", log.Fields{
+ "error": err,
+ })
+ break
+ }
+ if o.Annotations == nil {
+ o.Annotations = make(map[string]string)
+ }
+ o.Annotations[nettypes.NetworkAttachmentAnnot] = string(j)
+ return
+ case *v1core.ReplicationController:
+ updatePodTemplateNetworkAnnotation(o.Spec.Template, a)
+ default:
+ typeStr := fmt.Sprintf("%T", o)
+ log.Warn("Network annotations not supported for resource type", log.Fields{
+ "resource type": typeStr,
+ })
+ }
+}
+
+func updatePodTemplateNfnAnnotation(pt *v1core.PodTemplateSpec, new []WorkloadIfIntentSpec) {
+ nfnAnnotation := GetPodTemplateNfnAnnotation(pt)
+ newNfnAnnotation := newNfnIfs(nfnAnnotation, new)
+ j, err := json.Marshal(newNfnAnnotation)
+ if err != nil {
+ log.Error("Network nfn annotation has invalid format", log.Fields{
+ "error": err,
+ })
+ return
+ }
+ if pt.Annotations == nil {
+ pt.Annotations = make(map[string]string)
+ }
+ pt.Annotations[NfnAnnotationKey] = string(j)
+}
+
+// Add an nfn annotation to the resource
+func AddNfnAnnotation(r interface{}, new []WorkloadIfIntentSpec) {
+
+ switch o := r.(type) {
+ case *batch.Job:
+ updatePodTemplateNfnAnnotation(&o.Spec.Template, new)
+ case *batchv1beta1.CronJob:
+ updatePodTemplateNfnAnnotation(&o.Spec.JobTemplate.Spec.Template, new)
+ case *v1.DaemonSet:
+ updatePodTemplateNfnAnnotation(&o.Spec.Template, new)
+ return
+ case *v1.Deployment:
+ updatePodTemplateNfnAnnotation(&o.Spec.Template, new)
+ return
+ case *v1.ReplicaSet:
+ updatePodTemplateNfnAnnotation(&o.Spec.Template, new)
+ case *v1.StatefulSet:
+ updatePodTemplateNfnAnnotation(&o.Spec.Template, new)
+ case *v1core.Pod:
+ nfnAnnotation := GetPodNfnAnnotation(o)
+ newNfnAnnotation := newNfnIfs(nfnAnnotation, new)
+ j, err := json.Marshal(newNfnAnnotation)
+ if err != nil {
+ log.Error("Network nfn annotation has invalid format", log.Fields{
+ "error": err,
+ })
+ break
+ }
+ if o.Annotations == nil {
+ o.Annotations = make(map[string]string)
+ }
+ o.Annotations[NfnAnnotationKey] = string(j)
+ return
+ case *v1core.ReplicationController:
+ updatePodTemplateNfnAnnotation(o.Spec.Template, new)
+ return
+ default:
+ typeStr := fmt.Sprintf("%T", o)
+ log.Warn("Network nfn annotations not supported for resource type", log.Fields{
+ "resource type": typeStr,
+ })
+ }
+}
diff --git a/src/ovnaction/pkg/module/workloadifintent.go b/src/ovnaction/pkg/module/workloadifintent.go
new file mode 100644
index 00000000..55062564
--- /dev/null
+++ b/src/ovnaction/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/ovnaction/pkg/module/workloadintent.go b/src/ovnaction/pkg/module/workloadintent.go
new file mode 100644
index 00000000..e6916954
--- /dev/null
+++ b/src/ovnaction/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
+}