diff options
Diffstat (limited to 'src/tools/emcoui/middle_end/app/intents.go')
-rw-r--r-- | src/tools/emcoui/middle_end/app/intents.go | 664 |
1 files changed, 664 insertions, 0 deletions
diff --git a/src/tools/emcoui/middle_end/app/intents.go b/src/tools/emcoui/middle_end/app/intents.go new file mode 100644 index 00000000..992f7b66 --- /dev/null +++ b/src/tools/emcoui/middle_end/app/intents.go @@ -0,0 +1,664 @@ +/* +======================================================================= +Copyright (c) 2017-2020 Aarna Networks, Inc. +All rights reserved. +====================================================================== +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 app + +import ( + "encoding/json" + "fmt" + "log" + "strconv" +) + +type GenericPlacementIntent struct { + Metadata apiMetaData `json:"metadata"` +} + +type PlacementIntent struct { + Metadata apiMetaData `json:"metadata"` + Spec AppPlacementIntentSpec `json:"spec"` +} +type PlacementIntentExport struct { + Metadata apiMetaData `json:"metadata"` + Spec AppPlacementIntentSpecExport `json:"spec"` +} + +// appPlacementIntentSpec is the spec for per app intent +type AppPlacementIntentSpec struct { + AppName string `json:"app-name"` + Intent arrayIntent `json:"intent"` +} +type arrayIntent struct { + AllofCluster []Allof `json:"allof"` +} +type Allof struct { + ProviderName string `json:"provider-name"` + ClusterName string `json:"cluster-name"` +} +type AppPlacementIntentSpecExport struct { + AppName string `json:"appName"` + Intent arrayIntentExport `json:"intent"` +} +type arrayIntentExport struct { + AllofCluster []AllofExport `json:"allof"` +} +type AllofExport struct { + ProviderName string `json:"providerName"` + ClusterName string `json:"clusterName"` +} + +// plamcentIntentHandler implements the orchworkflow interface +type placementIntentHandler struct { + orchURL string + orchInstance *OrchestrationHandler +} + +type NetworkCtlIntent struct { + Metadata apiMetaData `json:"metadata"` +} + +type NetworkWlIntent struct { + Metadata apiMetaData `json:"metadata"` + Spec WorkloadIntentSpec `json:"spec"` +} + +type WorkloadIntentSpec struct { + AppName string `json:"application-name"` + Resource string `json:"workload-resource"` + Type string `json:"type"` +} +type WorkloadIntentSpecExport struct { + AppName string `json:"applicationName"` + Resource string `json:"workloadResource"` + Type string `json:"type"` +} + +type NwInterface struct { + Metadata apiMetaData `json:"metadata"` + Spec InterfaceSpec `json:"spec"` +} + +type InterfaceSpec struct { + Interface string `json:"interface"` + Name string `json:"name"` + DefaultGateway string `json:"defaultGateway"` + IPAddress string `json:"ipAddress"` + MacAddress string `json:"macAddress"` +} + +// networkIntentHandler implements the orchworkflow interface +type networkIntentHandler struct { + ovnURL string + orchInstance *OrchestrationHandler +} + +func (h *placementIntentHandler) getObject() (interface{}, interface{}) { + orch := h.orchInstance + retcode := 200 + dataRead := h.orchInstance.dataRead + for _, compositeAppValue := range dataRead.compositeAppMap { + compositeAppMetadata := compositeAppValue.Metadata.Metadata + compositeAppSpec := compositeAppValue.Metadata.Spec + Dig := compositeAppValue.DigMap + Apps := compositeAppValue.AppsDataArray + for digName, digValue := range Dig { + h.orchURL = "http://" + orch.MiddleendConf.OrchService + "/v2/projects/" + + orch.projectName + "/composite-apps/" + compositeAppMetadata.Name + + "/" + compositeAppSpec.Version + + "/deployment-intent-groups/" + digName + "/generic-placement-intents" + for gpintName, gpintValue := range digValue.GpintMap { + for appName, _ := range Apps { + var appPint PlacementIntent + url := h.orchURL + "/" + gpintName + "/app-intents/" + appName + "_pint" + retcode, retval, err := orch.apiGet(url, compositeAppMetadata.Name+"_getappPint") + fmt.Printf("Get Gpint App intent in Composite app %s dig %s Gpint %s status %s\n", + orch.compositeAppName, digName, gpintName, retcode) + if err != nil { + fmt.Printf("Failed to read app pint\n") + return nil, 500 + } + if retcode != 200 { + fmt.Printf("Failed to read app pint\n") + return nil, 200 + } + err = json.Unmarshal(retval, &appPint) + if err != nil { + fmt.Printf("Failed to unmarshal json %s\n", err) + return nil, 500 + } + gpintValue.AppIntentArray = append(gpintValue.AppIntentArray, appPint) + } + } + } + } + return nil, retcode +} + +func (h *placementIntentHandler) getAnchor() (interface{}, interface{}) { + orch := h.orchInstance + retcode := 200 + dataRead := h.orchInstance.dataRead + for _, compositeAppValue := range dataRead.compositeAppMap { + compositeAppMetadata := compositeAppValue.Metadata.Metadata + compositeAppSpec := compositeAppValue.Metadata.Spec + Dig := compositeAppValue.DigMap + for digName, digValue := range Dig { + var gpintList []GenericPlacementIntent + h.orchURL = "http://" + orch.MiddleendConf.OrchService + "/v2/projects/" + + orch.projectName + "/composite-apps/" + compositeAppMetadata.Name + + "/" + compositeAppSpec.Version + + "/deployment-intent-groups/" + digName + "/generic-placement-intents" + retcode, retval, err := orch.apiGet(h.orchURL, compositeAppMetadata.Name+"_getgpint") + fmt.Printf("Get Gpint in Composite app %s dig %s status %s\n", orch.compositeAppName, + digName, retcode) + if err != nil { + fmt.Printf("Failed to read gpint\n") + return nil, 500 + } + if retcode != 200 { + fmt.Printf("Failed to read gpint\n") + return nil, retcode + } + json.Unmarshal(retval, &gpintList) + digValue.GpintMap = make(map[string]*GpintData, len(gpintList)) + for _, value := range gpintList { + var GpintDataInstance GpintData + GpintDataInstance.Gpint = value + digValue.GpintMap[value.Metadata.Name] = &GpintDataInstance + } + } + } + return nil, retcode +} + +func (h *placementIntentHandler) deleteObject() interface{} { + orch := h.orchInstance + dataRead := h.orchInstance.dataRead + for _, compositeAppValue := range dataRead.compositeAppMap { + compositeAppMetadata := compositeAppValue.Metadata.Metadata + compositeAppSpec := compositeAppValue.Metadata.Spec + Dig := compositeAppValue.DigMap + Apps := compositeAppValue.AppsDataArray + + // loop through all app intens in the gpint + for digName, digValue := range Dig { + h.orchURL = "http://" + orch.MiddleendConf.OrchService + "/v2/projects/" + + orch.projectName + "/composite-apps/" + compositeAppMetadata.Name + + "/" + compositeAppSpec.Version + + "/deployment-intent-groups/" + digName + "/generic-placement-intents/" + for gpintName, _ := range digValue.GpintMap { + for appName, _ := range Apps { + url := h.orchURL + gpintName + + "/app-intents/" + appName + "_pint" // FIXME when query API works, change this API call to + // query based on app name. + fmt.Printf("Delete gping app intents %s\n", url) + resp, err := orch.apiDel(url, orch.compositeAppName+"_delgpintintents") + if err != nil { + return err + } + if resp != 204 { + return resp + } + fmt.Printf("Delete gpint intents resp %s\n", resp) + } + } + } + } + return nil +} + +func (h placementIntentHandler) deleteAnchor() interface{} { + orch := h.orchInstance + dataRead := h.orchInstance.dataRead + for _, compositeAppValue := range dataRead.compositeAppMap { + compositeAppMetadata := compositeAppValue.Metadata.Metadata + compositeAppSpec := compositeAppValue.Metadata.Spec + Dig := compositeAppValue.DigMap + + // loop through all app intens in the gpint + for digName, digValue := range Dig { + for gpintName, _ := range digValue.GpintMap { + h.orchURL = "http://" + orch.MiddleendConf.OrchService + "/v2/projects/" + + orch.projectName + "/composite-apps/" + compositeAppMetadata.Name + + "/" + compositeAppSpec.Version + + "/deployment-intent-groups/" + digName + "/generic-placement-intents/" + + gpintName + fmt.Printf("Delete gpint %s\n", h.orchURL) + resp, err := orch.apiDel(h.orchURL, compositeAppMetadata.Name+"_delgpints") + if err != nil { + return err + } + if resp != 204 { + return resp + } + fmt.Printf("Delete gpint resp %s\n", resp) + } + } + } + return nil +} + +func (h *placementIntentHandler) createAnchor() interface{} { + orch := h.orchInstance + intentData := h.orchInstance.DigData + + gpi := GenericPlacementIntent{ + Metadata: apiMetaData{ + Name: intentData.CompositeAppName + "_gpint", + Description: "Generic placement intent created from middleend", + UserData1: "data 1", + UserData2: "data2"}, + } + + jsonLoad, _ := json.Marshal(gpi) + // POST the generic placement intent + h.orchURL = "http://" + orch.MiddleendConf.OrchService + "/v2/projects/" + intentData.Spec.ProjectName + + "/composite-apps/" + intentData.CompositeAppName + "/" + intentData.CompositeAppVersion + + "/deployment-intent-groups/" + intentData.Name + url := h.orchURL + "/generic-placement-intents" + resp, err := orch.apiPost(jsonLoad, url, orch.digpIntents["generic-placement-intent"]) + if err != nil { + return err + } + if resp != 201 { + return resp + } + fmt.Printf("Generic placement intent resp %s\n", resp) + + return nil +} + +func (h *placementIntentHandler) createObject() interface{} { + orch := h.orchInstance + intentData := h.orchInstance.DigData + + for _, value := range intentData.Spec.Apps { + appName := value.Metadata.Name + intentName := appName + "_pint" + genericAppIntentName := intentData.CompositeAppName + "_gpint" + providerName := value.Clusters[0].Provider + clusterName := value.Clusters[0].SelectedClusters[0].Name + + pint := PlacementIntent{ + Metadata: apiMetaData{ + Name: intentName, + Description: "NA", + UserData1: "data 1", + UserData2: "data2"}, + Spec: AppPlacementIntentSpec{ + AppName: appName, + Intent: arrayIntent{ + AllofCluster: []Allof{ // FIXME: the logic requires to handle allof/anyof and multi cluster. + Allof{ + ProviderName: providerName, + ClusterName: clusterName}, + }, + }, + }, + } + + url := h.orchURL + "/generic-placement-intents/" + genericAppIntentName + "/app-intents" + jsonLoad, _ := json.Marshal(pint) + status, err := orch.apiPost(jsonLoad, url, intentName) + if err != nil { + log.Fatalln(err) + } + if status != 201 { + return status + } + fmt.Printf("Placement intent %s status %s %s\n", intentName, status, url) + } + + return nil +} + +func addPlacementIntent(I orchWorkflow) interface{} { + // 1. Create the Anchor point + err := I.createAnchor() + if err != nil { + return err + } + // 2. Create the Objects + err = I.createObject() + if err != nil { + return err + } + return nil +} + +func delGpint(I orchWorkflow) interface{} { + // 1. Create the Anchor point + err := I.deleteObject() + if err != nil { + return err + } + // 2. Create the Objects + err = I.deleteAnchor() + if err != nil { + return err + } + return nil +} + +func (h *networkIntentHandler) createAnchor() interface{} { + orch := h.orchInstance + intentData := h.orchInstance.DigData + + nwIntent := NetworkCtlIntent{ + Metadata: apiMetaData{ + Name: intentData.CompositeAppName + "_nwctlint", + Description: "Network Controller created from middleend", + UserData1: "data 1", + UserData2: "data2"}, + } + jsonLoad, _ := json.Marshal(nwIntent) + // POST the network controller intent + h.ovnURL = "http://" + orch.MiddleendConf.OvnService + "/v2/projects/" + intentData.Spec.ProjectName + + "/composite-apps/" + intentData.CompositeAppName + "/" + intentData.CompositeAppVersion + + "/deployment-intent-groups/" + intentData.Name + url := h.ovnURL + "/network-controller-intent" + resp, err := orch.apiPost(jsonLoad, url, orch.nwCtlIntents["network-controller-intent"]) + if err != nil { + return err + } + if resp != 201 { + return resp + } + fmt.Printf("Network contoller intent resp %s\n", resp) + + return nil +} + +func (h *networkIntentHandler) createObject() interface{} { + orch := h.orchInstance + intentData := h.orchInstance.DigData + + for _, value := range intentData.Spec.Apps { + + appName := value.Metadata.Name + intentName := value.Metadata.Name + "_wnwlint" + genericAppIntentName := intentData.CompositeAppName + "_nwctlint" + + wlIntent := NetworkWlIntent{ + Metadata: apiMetaData{ + Name: intentName, + Description: "NA", + UserData1: "data 1", + UserData2: "data2"}, + Spec: WorkloadIntentSpec{ + AppName: appName, + Resource: appName, + Type: "deployment", + }, + } + + url := h.ovnURL + "/network-controller-intent/" + genericAppIntentName + "/workload-intents" + jsonLoad, _ := json.Marshal(wlIntent) + status, err := orch.apiPost(jsonLoad, url, intentName) + if err != nil { + log.Fatalln(err) + } + if status != 201 { + return status + } + fmt.Printf("Workload intent %s status %s %s\n", intentName, status, url) + } + + // Add interfaces for to each application + for _, value := range intentData.Spec.Apps { + interfaces := value.Clusters[0].SelectedClusters[0].Interfaces + for j := range interfaces { + interfaceNum := strconv.Itoa(j) + interfaceName := value.Metadata.Name + "_interface" + interfaceNum + genericAppIntentName := intentData.CompositeAppName + "_nwctlint" + workloadIntent := value.Metadata.Name + "_wnwlint" + + iface := NwInterface{ + Metadata: apiMetaData{ + Name: interfaceName, + Description: "NA", + UserData1: "data 1", + UserData2: "data2"}, + Spec: InterfaceSpec{ + Interface: "eth" + interfaceNum, + Name: interfaces[j].NetworkName, + DefaultGateway: "false", + IPAddress: interfaces[j].IP, + }, + } + + url := h.ovnURL + "/network-controller-intent" + "/" + genericAppIntentName + + "/workload-intents/" + workloadIntent + "/interfaces" + jsonLoad, _ := json.Marshal(iface) + status, err := orch.apiPost(jsonLoad, url, interfaceName) + if err != nil { + log.Fatalln(err) + } + if status != 201 { + return status + } + fmt.Printf("interface %s status %s %s\n", interfaceName, status, url) + } + } + + return nil +} + +func (h *networkIntentHandler) getObject() (interface{}, interface{}) { + orch := h.orchInstance + retcode := 200 + dataRead := h.orchInstance.dataRead + for _, compositeAppValue := range dataRead.compositeAppMap { + compositeAppMetadata := compositeAppValue.Metadata.Metadata + compositeAppSpec := compositeAppValue.Metadata.Spec + Dig := compositeAppValue.DigMap + for digName, digValue := range Dig { + h.ovnURL = "http://" + orch.MiddleendConf.OvnService + "/v2/projects/" + + orch.projectName + "/composite-apps/" + compositeAppMetadata.Name + + "/" + compositeAppSpec.Version + + "/deployment-intent-groups/" + digName + for nwintName, nwintValue := range digValue.NwintMap { + var wrlintList []NetworkWlIntent + wlurl := h.ovnURL + "/network-controller-intent/" + nwintName + "/workload-intents" + retcode, retval, err := orch.apiGet(wlurl, orch.compositeAppName+"_getnwwlint") + fmt.Printf("Get Wrkld intents in Composite app %s dig %s nw intent %s status %d\n", + orch.compositeAppName, digName, nwintName, retcode) + if err != nil { + fmt.Printf("Failed to read nw workload int") + return nil, 500 + } + if retcode != 200 { + fmt.Printf("Failed to read nw workload int") + return nil, retcode + } + json.Unmarshal(retval, &wrlintList) + nwintValue.WrkintMap = make(map[string]*WrkintData, len(wrlintList)) + for _, wrlIntValue := range wrlintList { + var WrkintDataInstance WrkintData + WrkintDataInstance.Wrkint = wrlIntValue + + var ifaceList []NwInterface + ifaceurl := h.ovnURL + "/network-controller-intent/" + nwintName + + "/workload-intents/" + wrlIntValue.Metadata.Name + "/interfaces" + retcode, retval, err := orch.apiGet(ifaceurl, orch.compositeAppName+"_getnwiface") + fmt.Printf("Get interface in Composite app %s dig %s nw intent %s wrkld intent %s status %d\n", + orch.compositeAppName, digName, nwintName, wrlIntValue.Metadata.Name, retcode) + if err != nil { + fmt.Printf("Failed to read nw interface") + return nil, 500 + } + if retcode != 200 { + fmt.Printf("Failed to read nw interface") + return nil, retcode + } + json.Unmarshal(retval, &ifaceList) + WrkintDataInstance.Interfaces = ifaceList + nwintValue.WrkintMap[wrlIntValue.Metadata.Name] = &WrkintDataInstance + } + } + } + } + return nil, retcode +} + +func (h *networkIntentHandler) getAnchor() (interface{}, interface{}) { + orch := h.orchInstance + retcode := 200 + dataRead := h.orchInstance.dataRead + for _, compositeAppValue := range dataRead.compositeAppMap { + compositeAppMetadata := compositeAppValue.Metadata.Metadata + compositeAppSpec := compositeAppValue.Metadata.Spec + Dig := compositeAppValue.DigMap + for digName, digValue := range Dig { + h.ovnURL = "http://" + orch.MiddleendConf.OvnService + "/v2/projects/" + + orch.projectName + "/composite-apps/" + compositeAppMetadata.Name + + "/" + compositeAppSpec.Version + + "/deployment-intent-groups/" + digName + var nwintList []NetworkCtlIntent + + url := h.ovnURL + "/network-controller-intent" + retcode, retval, err := orch.apiGet(url, orch.compositeAppName+"_getnwint") + fmt.Printf("Get Network Ctl intent in Composite app %s dig %s status %d\n", + orch.compositeAppName, digName, retcode) + if err != nil { + fmt.Printf("Failed to read nw int %s\n", err) + return nil, 500 + } + if retcode != 200 { + fmt.Printf("Failed to read nw int") + return nil, retcode + } + json.Unmarshal(retval, &nwintList) + digValue.NwintMap = make(map[string]*NwintData, len(nwintList)) + for _, nwIntValue := range nwintList { + var NwintDataInstance NwintData + NwintDataInstance.Nwint = nwIntValue + digValue.NwintMap[nwIntValue.Metadata.Name] = &NwintDataInstance + } + } + } + return nil, retcode +} + +func (h *networkIntentHandler) deleteObject() interface{} { + orch := h.orchInstance + retcode := 200 + dataRead := h.orchInstance.dataRead + for _, compositeAppValue := range dataRead.compositeAppMap { + compositeAppMetadata := compositeAppValue.Metadata.Metadata + compositeAppSpec := compositeAppValue.Metadata.Spec + Dig := compositeAppValue.DigMap + for digName, digValue := range Dig { + h.ovnURL = "http://" + orch.MiddleendConf.OvnService + "/v2/projects/" + + orch.projectName + "/composite-apps/" + compositeAppMetadata.Name + + "/" + compositeAppSpec.Version + + "/deployment-intent-groups/" + digName + + for nwintName, nwintValue := range digValue.NwintMap { + for wrkintName, wrkintValue := range nwintValue.WrkintMap { + // Delete the interfaces per workload intent. + for _, value := range wrkintValue.Interfaces { + url := h.ovnURL + "network-controller-intent/" + nwintName + "/workload-intents/" + + wrkintName + "/interfaces/" + value.Spec.Name + fmt.Printf("Delete app nw interface %s\n", url) + retcode, err := orch.apiDel(url, orch.compositeAppName+"_delnwinterface") + if err != nil { + return err + } + if retcode != 204 { + return retcode + } + fmt.Printf("Delete nw interface resp %s\n", retcode) + } + // Delete the workload intents. + url := h.ovnURL + "network-controller-intent/" + nwintName + "/workload-intents/" + wrkintName + fmt.Printf("Delete app nw wl intent %s\n", url) + retcode, err := orch.apiDel(url, orch.compositeAppName+"_delnwwrkintent") + if err != nil { + return err + } + if retcode != 204 { + return retcode + } + fmt.Printf("Delete nw wl intent resp %s\n", retcode) + } // For workload intents in network controller intent. + } // For network controller intents in Dig. + } // For Dig. + } // For composite app. + return retcode +} + +func (h networkIntentHandler) deleteAnchor() interface{} { + orch := h.orchInstance + retcode := 200 + dataRead := h.orchInstance.dataRead + for _, compositeAppValue := range dataRead.compositeAppMap { + compositeAppMetadata := compositeAppValue.Metadata.Metadata + compositeAppSpec := compositeAppValue.Metadata.Spec + Dig := compositeAppValue.DigMap + for digName, digValue := range Dig { + h.ovnURL = "http://" + orch.MiddleendConf.OvnService + "/v2/projects/" + + orch.projectName + "/composite-apps/" + compositeAppMetadata.Name + + "/" + compositeAppSpec.Version + + "/deployment-intent-groups/" + digName + for nwintName, _ := range digValue.NwintMap { + // loop through all app intens in the gpint + url := h.ovnURL + "/network-controller-intent/" + nwintName + fmt.Printf("Delete app nw controller intent %s\n", url) + retcode, err := orch.apiDel(url, compositeAppMetadata.Name+"_delnwctlintent") + if err != nil { + return err + } + if retcode != 204 { + return retcode + } + fmt.Printf("Delete nw controller intent %s\n", retcode) + } + } + } + return retcode +} + +func addNetworkIntent(I orchWorkflow) interface{} { + //1. Add network controller Intent + err := I.createAnchor() + if err != nil { + return err + } + + //2. Add network workload intent + err = I.createObject() + if err != nil { + return err + } + + return nil +} + +func delNwintData(I orchWorkflow) interface{} { + // 1. Create the Anchor point + err := I.deleteObject() + if err != nil { + return err + } + // 2. Create the Objects + err = I.deleteAnchor() + if err != nil { + return err + } + return nil +} |