Add support for parsing profile yaml files
[multicloud/k8s.git] / src / k8splugin / internal / app / vnfhelper.go
1 /*
2 Copyright 2018 Intel Corporation.
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6     http://www.apache.org/licenses/LICENSE-2.0
7 Unless required by applicable law or agreed to in writing, software
8 distributed under the License is distributed on an "AS IS" BASIS,
9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 See the License for the specific language governing permissions and
11 limitations under the License.
12 */
13
14 package app
15
16 import (
17         "encoding/hex"
18         "io/ioutil"
19         "log"
20         "math/rand"
21         "os"
22
23         "k8s.io/client-go/kubernetes"
24
25         pkgerrors "github.com/pkg/errors"
26         yaml "gopkg.in/yaml.v2"
27
28         utils "k8splugin/internal"
29 )
30
31 func generateExternalVNFID() string {
32         b := make([]byte, 2)
33         rand.Read(b)
34         return hex.EncodeToString(b)
35 }
36
37 func ensuresNamespace(namespace string, kubeclient kubernetes.Interface) error {
38         namespacePlugin, ok := utils.LoadedPlugins["namespace"]
39         if !ok {
40                 return pkgerrors.New("No plugin for namespace resource found")
41         }
42
43         symGetNamespaceFunc, err := namespacePlugin.Lookup("Get")
44         if err != nil {
45                 return pkgerrors.Wrap(err, "Error fetching get namespace function")
46         }
47
48         ns, err := symGetNamespaceFunc.(func(string, string, kubernetes.Interface) (string, error))(
49                 namespace, namespace, kubeclient)
50         if err != nil {
51                 return pkgerrors.Wrap(err, "An error ocurred during the get namespace execution")
52         }
53
54         if ns == "" {
55                 log.Println("Creating " + namespace + " namespace")
56                 symGetNamespaceFunc, err := namespacePlugin.Lookup("Create")
57                 if err != nil {
58                         return pkgerrors.Wrap(err, "Error fetching create namespace plugin")
59                 }
60                 namespaceResource := &utils.ResourceData{
61                         Namespace: namespace,
62                 }
63
64                 _, err = symGetNamespaceFunc.(func(*utils.ResourceData, kubernetes.Interface) (string, error))(
65                         namespaceResource, kubeclient)
66                 if err != nil {
67                         return pkgerrors.Wrap(err, "Error creating "+namespace+" namespace")
68                 }
69         }
70         return nil
71 }
72
73 // CreateVNF reads the CSAR files from the files system and creates them one by one
74 var CreateVNF = func(csarID string, cloudRegionID string, namespace string, kubeclient *kubernetes.Clientset) (string, map[string][]string, error) {
75         if err := ensuresNamespace(namespace, kubeclient); err != nil {
76                 return "", nil, pkgerrors.Wrap(err, "Error while ensuring namespace: "+namespace)
77         }
78         externalVNFID := generateExternalVNFID()
79         internalVNFID := cloudRegionID + "-" + namespace + "-" + externalVNFID
80
81         csarDirPath := os.Getenv("CSAR_DIR") + "/" + csarID
82         metadataYAMLPath := csarDirPath + "/metadata.yaml"
83
84         log.Println("Reading " + metadataYAMLPath + " file")
85         metadataFile, err := ReadMetadataFile(metadataYAMLPath)
86         if err != nil {
87                 return "", nil, pkgerrors.Wrap(err, "Error while reading Metadata File: "+metadataYAMLPath)
88         }
89
90         var path string
91         resourceYAMLNameMap := make(map[string][]string)
92         // Iterates over the resources defined in the metadata file to create kubernetes resources
93         log.Println(string(len(metadataFile.ResourceTypePathMap)) + " resource(s) type(s) to be processed")
94         for resource, fileNames := range metadataFile.ResourceTypePathMap {
95                 log.Println("Processing items of " + string(resource) + " resource")
96                 var resourcesCreated []string
97                 for _, filename := range fileNames {
98                         path = csarDirPath + "/" + filename
99
100                         if _, err := os.Stat(path); os.IsNotExist(err) {
101                                 return "", nil, pkgerrors.New("File " + path + "does not exists")
102                         }
103                         log.Println("Processing file: " + path)
104
105                         genericKubeData := &utils.ResourceData{
106                                 YamlFilePath: path,
107                                 Namespace:    namespace,
108                                 VnfId:        internalVNFID,
109                         }
110
111                         typePlugin, ok := utils.LoadedPlugins[resource]
112                         if !ok {
113                                 return "", nil, pkgerrors.New("No plugin for resource " + resource + " found")
114                         }
115
116                         symCreateResourceFunc, err := typePlugin.Lookup("Create")
117                         if err != nil {
118                                 return "", nil, pkgerrors.Wrap(err, "Error fetching "+resource+" plugin")
119                         }
120
121                         internalResourceName, err := symCreateResourceFunc.(func(*utils.ResourceData, kubernetes.Interface) (string, error))(
122                                 genericKubeData, kubeclient)
123                         if err != nil {
124                                 return "", nil, pkgerrors.Wrap(err, "Error in plugin "+resource+" plugin")
125                         }
126                         log.Print(internalResourceName + " succesful resource created")
127                         resourcesCreated = append(resourcesCreated, internalResourceName)
128                 }
129                 resourceYAMLNameMap[resource] = resourcesCreated
130         }
131
132         return externalVNFID, resourceYAMLNameMap, nil
133 }
134
135 // DestroyVNF deletes VNFs based on data passed
136 var DestroyVNF = func(data map[string][]string, namespace string, kubeclient *kubernetes.Clientset) error {
137         /* data:
138         {
139                 "deployment": ["cloud1-default-uuid-sisedeploy1", "cloud1-default-uuid-sisedeploy2", ... ]
140                 "service": ["cloud1-default-uuid-sisesvc1", "cloud1-default-uuid-sisesvc2", ... ]
141         },
142         */
143
144         for resourceName, resourceList := range data {
145                 typePlugin, ok := utils.LoadedPlugins[resourceName]
146                 if !ok {
147                         return pkgerrors.New("No plugin for resource " + resourceName + " found")
148                 }
149
150                 symDeleteResourceFunc, err := typePlugin.Lookup("Delete")
151                 if err != nil {
152                         return pkgerrors.Wrap(err, "Error fetching "+resourceName+" plugin")
153                 }
154
155                 for _, resourceName := range resourceList {
156
157                         log.Println("Deleting resource: " + resourceName)
158
159                         err = symDeleteResourceFunc.(func(string, string, kubernetes.Interface) error)(
160                                 resourceName, namespace, kubeclient)
161                         if err != nil {
162                                 return pkgerrors.Wrap(err, "Error destroying "+resourceName)
163                         }
164                 }
165         }
166
167         return nil
168 }
169
170 // MetadataFile stores the metadata of execution
171 type MetadataFile struct {
172         ResourceTypePathMap map[string][]string `yaml:"resources"`
173 }
174
175 // ReadMetadataFile reads the metadata yaml to return the order or reads
176 var ReadMetadataFile = func(path string) (MetadataFile, error) {
177         var metadataFile MetadataFile
178
179         if _, err := os.Stat(path); os.IsNotExist(err) {
180                 return metadataFile, pkgerrors.Wrap(err, "Metadata YAML file does not exist")
181         }
182
183         log.Println("Reading metadata YAML: " + path)
184         yamlFile, err := ioutil.ReadFile(path)
185         if err != nil {
186                 return metadataFile, pkgerrors.Wrap(err, "Metadata YAML file read error")
187         }
188
189         err = yaml.Unmarshal(yamlFile, &metadataFile)
190         if err != nil {
191                 return metadataFile, pkgerrors.Wrap(err, "Metadata YAML file unmarshal error")
192         }
193         log.Printf("metadata:\n%v", metadataFile)
194
195         return metadataFile, nil
196 }