2 * Copyright 2020 Intel Corporation, Inc
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
23 jyaml "github.com/ghodss/yaml"
25 nettypes "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
26 "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext"
27 "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db"
28 log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils"
29 "k8s.io/apimachinery/pkg/runtime"
30 "k8s.io/client-go/kubernetes/scheme"
32 pkgerrors "github.com/pkg/errors"
35 // NetControlIntent contains the parameters needed for dynamic networks
36 type NetControlIntent struct {
37 Metadata Metadata `json:"metadata"`
40 // NetControlIntentKey is the key structure that is used in the database
41 type NetControlIntentKey struct {
42 NetControlIntent string `json:"netcontrolintent"`
43 Project string `json:"project"`
44 CompositeApp string `json:"compositeapp"`
45 CompositeAppVersion string `json:"compositeappversion"`
48 // Manager is an interface exposing the NetControlIntent functionality
49 type NetControlIntentManager interface {
50 CreateNetControlIntent(nci NetControlIntent, project, compositeapp, compositeappversion string, exists bool) (NetControlIntent, error)
51 GetNetControlIntent(name, project, compositeapp, compositeappversion string) (NetControlIntent, error)
52 GetNetControlIntents(project, compositeapp, compositeappversion string) ([]NetControlIntent, error)
53 DeleteNetControlIntent(name, project, compositeapp, compositeappversion string) error
54 ApplyNetControlIntent(name, project, compositeapp, compositeappversion, appContextId string) error
57 // NetControlIntentClient implements the Manager
58 // It will also be used to maintain some localized state
59 type NetControlIntentClient struct {
63 // NewNetControlIntentClient returns an instance of the NetControlIntentClient
64 // which implements the Manager
65 func NewNetControlIntentClient() *NetControlIntentClient {
66 return &NetControlIntentClient{
68 storeName: "orchestrator",
69 tagMeta: "netcontrolintentmetadata",
74 // CreateNetControlIntent - create a new NetControlIntent
75 func (v *NetControlIntentClient) CreateNetControlIntent(nci NetControlIntent, project, compositeapp, compositeappversion string, exists bool) (NetControlIntent, error) {
77 //Construct key and tag to select the entry
78 key := NetControlIntentKey{
79 NetControlIntent: nci.Metadata.Name,
81 CompositeApp: compositeapp,
82 CompositeAppVersion: compositeappversion,
85 //Check if this NetControlIntent already exists
86 _, err := v.GetNetControlIntent(nci.Metadata.Name, project, compositeapp, compositeappversion)
87 if err == nil && !exists {
88 return NetControlIntent{}, pkgerrors.New("NetControlIntent already exists")
91 err = db.DBconn.Insert(v.db.storeName, key, nil, v.db.tagMeta, nci)
93 return NetControlIntent{}, pkgerrors.Wrap(err, "Creating DB Entry")
99 // GetNetControlIntent returns the NetControlIntent for corresponding name
100 func (v *NetControlIntentClient) GetNetControlIntent(name, project, compositeapp, compositeappversion string) (NetControlIntent, error) {
102 //Construct key and tag to select the entry
103 key := NetControlIntentKey{
104 NetControlIntent: name,
106 CompositeApp: compositeapp,
107 CompositeAppVersion: compositeappversion,
110 value, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta)
112 return NetControlIntent{}, pkgerrors.Wrap(err, "Get NetControlIntent")
115 //value is a byte array
117 nci := NetControlIntent{}
118 err = db.DBconn.Unmarshal(value[0], &nci)
120 return NetControlIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value")
125 return NetControlIntent{}, pkgerrors.New("Error getting NetControlIntent")
128 // GetNetControlIntentList returns all of the NetControlIntent for corresponding name
129 func (v *NetControlIntentClient) GetNetControlIntents(project, compositeapp, compositeappversion string) ([]NetControlIntent, error) {
131 //Construct key and tag to select the entry
132 key := NetControlIntentKey{
133 NetControlIntent: "",
135 CompositeApp: compositeapp,
136 CompositeAppVersion: compositeappversion,
139 var resp []NetControlIntent
140 values, err := db.DBconn.Find(v.db.storeName, key, v.db.tagMeta)
142 return []NetControlIntent{}, pkgerrors.Wrap(err, "Get NetControlIntents")
145 for _, value := range values {
146 nci := NetControlIntent{}
147 err = db.DBconn.Unmarshal(value, &nci)
149 return []NetControlIntent{}, pkgerrors.Wrap(err, "Unmarshalling Value")
151 resp = append(resp, nci)
157 // Delete the NetControlIntent from database
158 func (v *NetControlIntentClient) DeleteNetControlIntent(name, project, compositeapp, compositeappversion string) error {
160 //Construct key and tag to select the entry
161 key := NetControlIntentKey{
162 NetControlIntent: name,
164 CompositeApp: compositeapp,
165 CompositeAppVersion: compositeappversion,
168 err := db.DBconn.Remove(v.db.storeName, key)
170 return pkgerrors.Wrap(err, "Delete NetControlIntent Entry;")
176 // (Test Routine) - Apply network-control-intent
177 func (v *NetControlIntentClient) ApplyNetControlIntent(name, project, compositeapp, compositeappversion, appContextId string) error {
178 // TODO: Handle all Network Chain Intents for the Network Control Intent
180 // Handle all Workload Intents for the Network Control Intent
181 wis, err := NewWorkloadIntentClient().GetWorkloadIntents(project, compositeapp, compositeappversion, name)
183 return pkgerrors.Wrapf(err, "Error getting Workload Intents for Network Control Intent %v for %v/%v%v not found", name, project, compositeapp, compositeappversion)
186 // Setup the AppContext
187 var context appcontext.AppContext
188 _, err = context.LoadAppContext(appContextId)
190 return pkgerrors.Wrapf(err, "Error getting AppContext with Id: %v for %v/%v%v",
191 appContextId, project, compositeapp, compositeappversion)
194 // Handle all intents (currently just Interface intents) for each Workload Intent
195 for _, wi := range wis {
196 // The app/resource identified in the workload intent needs to be updated with two annotations.
197 // 1 - The "k8s.v1.cni.cncf.io/networks" annotation will have {"name": "ovn-networkobj", "namespace": "default"} added
198 // to it (preserving any existing values for this annotation.
199 // 2 - The "k8s.plugin.opnfv.org/nfn-network" annotation will add any network interfaces that are provided by the
200 // workload/interfaces intents.
202 // Prepare the list of interfaces from the workload intent
203 wifs, err := NewWorkloadIfIntentClient().GetWorkloadIfIntents(project,
209 return pkgerrors.Wrapf(err,
210 "Error getting Workload Interface Intents for Workload Intent %v under Network Control Intent %v for %v/%v%v not found",
211 wi.Metadata.Name, name, project, compositeapp, compositeappversion)
214 log.Warn("No interface intents provided for workload intent", log.Fields{
216 "composite app": compositeapp,
217 "composite app version": compositeappversion,
218 "network control intent": name,
219 "workload intent": wi.Metadata.Name,
224 // Get all clusters for the current App from the AppContext
225 clusters, err := context.GetClusterNames(wi.Spec.AppName)
226 for _, c := range clusters {
227 rh, err := context.GetResourceHandle(wi.Spec.AppName, c,
228 strings.Join([]string{wi.Spec.WorkloadResource, wi.Spec.Type}, "+"))
230 log.Warn("App Context resource handle not found", log.Fields{
232 "composite app": compositeapp,
233 "composite app version": compositeappversion,
234 "network control intent": name,
235 "workload name": wi.Metadata.Name,
236 "app": wi.Spec.AppName,
237 "resource": wi.Spec.WorkloadResource,
238 "resource type": wi.Spec.Type,
242 r, err := context.GetValue(rh)
244 log.Error("Error retrieving resource from App Context", log.Fields{
246 "resource handle": rh,
250 // Unmarshal resource to K8S object
251 robj, err := runtime.Decode(scheme.Codecs.UniversalDeserializer(), []byte(r.(string)))
253 // Add network annotation to object
254 netAnnot := nettypes.NetworkSelectionElement{
255 Name: "ovn-networkobj",
256 Namespace: "default",
258 AddNetworkAnnotation(robj, netAnnot)
260 // Add nfn interface annotations to object
261 var newNfnIfs []WorkloadIfIntentSpec
262 for _, i := range wifs {
263 newNfnIfs = append(newNfnIfs, i.Spec)
265 AddNfnAnnotation(robj, newNfnIfs)
267 // Marshal object back to yaml format (via json - seems to eliminate most clutter)
268 j, err := json.Marshal(robj)
270 log.Error("Error marshalling resource to JSON", log.Fields{
275 y, err := jyaml.JSONToYAML(j)
277 log.Error("Error marshalling resource to YAML", log.Fields{
283 // Update resource in AppContext
284 err = context.UpdateResourceValue(rh, y)
286 log.Error("Network updating app context resource handle", log.Fields{
288 "resource handle": rh,