aboutsummaryrefslogtreecommitdiffstats
path: root/src/ovnaction/pkg
diff options
context:
space:
mode:
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
+}