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.
24 "github.com/gorilla/mux"
25 pkgerrors "github.com/pkg/errors"
26 "k8s.io/client-go/kubernetes"
33 // GetVNFClient retrieves the client used to communicate with a Kubernetes Cluster
34 var GetVNFClient = func(kubeConfigPath string) (kubernetes.Clientset, error) {
35 client, err := krd.GetKubeClient(kubeConfigPath)
42 func validateBody(body interface{}) error {
43 switch b := body.(type) {
44 case CreateVnfRequest:
45 if b.CloudRegionID == "" {
46 werr := pkgerrors.Wrap(errors.New("Invalid/Missing CloudRegionID in POST request"), "CreateVnfRequest bad request")
50 werr := pkgerrors.Wrap(errors.New("Invalid/Missing CsarID in POST request"), "CreateVnfRequest bad request")
53 if strings.Contains(b.CloudRegionID, "|") || strings.Contains(b.Namespace, "|") {
54 werr := pkgerrors.Wrap(errors.New("Character \"|\" not allowed in CSAR ID"), "CreateVnfRequest bad request")
57 case UpdateVnfRequest:
58 if b.CloudRegionID == "" || b.CsarID == "" {
59 werr := pkgerrors.Wrap(errors.New("Invalid/Missing Data in PUT request"), "UpdateVnfRequest bad request")
66 // CreateHandler is the POST method creates a new VNF instance resource.
67 func CreateHandler(w http.ResponseWriter, r *http.Request) {
68 var resource CreateVnfRequest
71 http.Error(w, "Body empty", http.StatusBadRequest)
75 err := json.NewDecoder(r.Body).Decode(&resource)
77 http.Error(w, err.Error(), http.StatusUnprocessableEntity)
81 err = validateBody(resource)
83 http.Error(w, err.Error(), http.StatusUnprocessableEntity)
87 // (TODO): Read kubeconfig for specific Cloud Region from local file system
88 // if present or download it from AAI
89 // err := DownloadKubeConfigFromAAI(resource.CloudRegionID, os.Getenv("KUBE_CONFIG_DIR")
90 kubeclient, err := GetVNFClient(os.Getenv("KUBE_CONFIG_DIR") + "/" + resource.CloudRegionID)
92 http.Error(w, err.Error(), http.StatusInternalServerError)
99 "deployment": ["cloud1-default-uuid-sisedeploy1", "cloud1-default-uuid-sisedeploy2", ... ]
100 "service": ["cloud1-default-uuid-sisesvc1", "cloud1-default-uuid-sisesvc2", ... ]
104 externalVNFID, resourceNameMap, err := csar.CreateVNF(resource.CsarID, resource.CloudRegionID, resource.Namespace, &kubeclient)
106 werr := pkgerrors.Wrap(err, "Read Kubernetes Data information error")
107 http.Error(w, werr.Error(), http.StatusInternalServerError)
111 // cloud1-default-uuid
112 internalVNFID := resource.CloudRegionID + "-" + resource.Namespace + "-" + externalVNFID
114 // Persist in AAI database.
115 log.Printf("Cloud Region ID: %s, Namespace: %s, VNF ID: %s ", resource.CloudRegionID, resource.Namespace, externalVNFID)
117 // TODO: Uncomment when annotations are done
118 // krd.AddNetworkAnnotationsToPod(kubeData, resource.Networks)
120 // "{"deployment":<>,"service":<>}"
121 serializedResourceNameMap, err := db.Serialize(resourceNameMap)
123 werr := pkgerrors.Wrap(err, "Create VNF deployment JSON Marshalling error")
124 http.Error(w, werr.Error(), http.StatusInternalServerError)
128 // key: cloud1-default-uuid
129 // value: "{"deployment":<>,"service":<>}"
130 err = db.DBconn.CreateEntry(internalVNFID, serializedResourceNameMap)
132 werr := pkgerrors.Wrap(err, "Create VNF deployment DB error")
133 http.Error(w, werr.Error(), http.StatusInternalServerError)
137 resp := CreateVnfResponse{
138 VNFID: externalVNFID,
139 CloudRegionID: resource.CloudRegionID,
140 Namespace: resource.Namespace,
141 VNFComponents: resourceNameMap,
144 w.Header().Set("Content-Type", "application/json")
145 w.WriteHeader(http.StatusCreated)
146 json.NewEncoder(w).Encode(resp)
149 // ListHandler the existing VNF instances created in a given Kubernetes cluster
150 func ListHandler(w http.ResponseWriter, r *http.Request) {
153 cloudRegionID := vars["cloudRegionID"]
154 namespace := vars["namespace"]
155 prefix := cloudRegionID + "-" + namespace
157 internalVNFIDs, err := db.DBconn.ReadAll(prefix)
159 werr := pkgerrors.Wrap(err, "Get VNF list error")
160 http.Error(w, werr.Error(), http.StatusInternalServerError)
164 if len(internalVNFIDs) == 0 {
165 w.WriteHeader(http.StatusNotFound)
169 // TODO: There is an edge case where if namespace is passed but is missing some characters
170 // trailing, it will print the result with those excluding characters. This is because of
171 // the way I am trimming the Prefix. This fix is needed.
173 var editedList []string
175 for _, id := range internalVNFIDs {
177 editedList = append(editedList, strings.TrimPrefix(id, prefix)[1:])
181 if len(editedList) == 0 {
182 editedList = append(editedList, "")
185 resp := ListVnfsResponse{
189 w.Header().Set("Content-Type", "application/json")
190 w.WriteHeader(http.StatusOK)
191 json.NewEncoder(w).Encode(resp)
194 // DeleteHandler method terminates an individual VNF instance.
195 func DeleteHandler(w http.ResponseWriter, r *http.Request) {
198 cloudRegionID := vars["cloudRegionID"] // cloud1
199 namespace := vars["namespace"] // default
200 externalVNFID := vars["externalVNFID"] // uuid
202 // cloud1-default-uuid
203 internalVNFID := cloudRegionID + "-" + namespace + "-" + externalVNFID
205 // (TODO): Read kubeconfig for specific Cloud Region from local file system
206 // if present or download it from AAI
207 // err := DownloadKubeConfigFromAAI(resource.CloudRegionID, os.Getenv("KUBE_CONFIG_DIR")
208 kubeclient, err := GetVNFClient(os.Getenv("KUBE_CONFIG_DIR") + "/" + cloudRegionID)
210 http.Error(w, err.Error(), http.StatusInternalServerError)
214 // key: cloud1-default-uuid
215 // value: "{"deployment":<>,"service":<>}"
216 serializedResourceNameMap, found, err := db.DBconn.ReadEntry(internalVNFID)
218 http.Error(w, err.Error(), http.StatusInternalServerError)
223 w.WriteHeader(http.StatusNotFound)
229 "deployment": ["cloud1-default-uuid-sisedeploy1", "cloud1-default-uuid-sisedeploy2", ... ]
230 "service": ["cloud1-default-uuid-sisesvc1", "cloud1-default-uuid-sisesvc2", ... ]
233 deserializedResourceNameMap := make(map[string][]string)
234 err = db.DeSerialize(serializedResourceNameMap, &deserializedResourceNameMap)
236 werr := pkgerrors.Wrap(err, "Delete VNF error")
237 http.Error(w, werr.Error(), http.StatusInternalServerError)
241 err = csar.DestroyVNF(deserializedResourceNameMap, namespace, &kubeclient)
243 werr := pkgerrors.Wrap(err, "Delete VNF error")
244 http.Error(w, werr.Error(), http.StatusInternalServerError)
248 err = db.DBconn.DeleteEntry(internalVNFID)
250 werr := pkgerrors.Wrap(err, "Delete VNF error")
251 http.Error(w, werr.Error(), http.StatusInternalServerError)
255 w.Header().Set("Content-Type", "application/json")
256 w.WriteHeader(http.StatusAccepted)
259 // // UpdateHandler method to update a VNF instance.
260 // func UpdateHandler(w http.ResponseWriter, r *http.Request) {
261 // vars := mux.Vars(r)
262 // id := vars["vnfInstanceId"]
264 // var resource UpdateVnfRequest
266 // if r.Body == nil {
267 // http.Error(w, "Body empty", http.StatusBadRequest)
271 // err := json.NewDecoder(r.Body).Decode(&resource)
273 // http.Error(w, err.Error(), http.StatusUnprocessableEntity)
277 // err = validateBody(resource)
279 // http.Error(w, err.Error(), http.StatusUnprocessableEntity)
283 // kubeData, err := utils.ReadCSARFromFileSystem(resource.CsarID)
285 // if kubeData.Deployment == nil {
286 // werr := pkgerrors.Wrap(err, "Update VNF deployment error")
287 // http.Error(w, werr.Error(), http.StatusInternalServerError)
290 // kubeData.Deployment.SetUID(types.UID(id))
293 // werr := pkgerrors.Wrap(err, "Update VNF deployment information error")
294 // http.Error(w, werr.Error(), http.StatusInternalServerError)
298 // // (TODO): Read kubeconfig for specific Cloud Region from local file system
299 // // if present or download it from AAI
300 // s, err := NewVNFInstanceService("../kubeconfig/config")
302 // http.Error(w, err.Error(), http.StatusInternalServerError)
306 // err = s.Client.UpdateDeployment(kubeData.Deployment, resource.Namespace)
308 // werr := pkgerrors.Wrap(err, "Update VNF error")
310 // http.Error(w, werr.Error(), http.StatusInternalServerError)
314 // resp := UpdateVnfResponse{
318 // w.Header().Set("Content-Type", "application/json")
319 // w.WriteHeader(http.StatusCreated)
321 // err = json.NewEncoder(w).Encode(resp)
323 // werr := pkgerrors.Wrap(err, "Parsing output of new VNF error")
324 // http.Error(w, werr.Error(), http.StatusInternalServerError)
328 // GetHandler retrieves information about a VNF instance by reading an individual VNF instance resource.
329 func GetHandler(w http.ResponseWriter, r *http.Request) {
332 cloudRegionID := vars["cloudRegionID"] // cloud1
333 namespace := vars["namespace"] // default
334 externalVNFID := vars["externalVNFID"] // uuid
336 // cloud1-default-uuid
337 internalVNFID := cloudRegionID + "-" + namespace + "-" + externalVNFID
339 // key: cloud1-default-uuid
340 // value: "{"deployment":<>,"service":<>}"
341 serializedResourceNameMap, found, err := db.DBconn.ReadEntry(internalVNFID)
343 http.Error(w, err.Error(), http.StatusInternalServerError)
348 w.WriteHeader(http.StatusNotFound)
354 "deployment": ["cloud1-default-uuid-sisedeploy1", "cloud1-default-uuid-sisedeploy2", ... ]
355 "service": ["cloud1-default-uuid-sisesvc1", "cloud1-default-uuid-sisesvc2", ... ]
358 deserializedResourceNameMap := make(map[string][]string)
359 err = db.DeSerialize(serializedResourceNameMap, &deserializedResourceNameMap)
361 werr := pkgerrors.Wrap(err, "Get VNF error")
362 http.Error(w, werr.Error(), http.StatusInternalServerError)
366 resp := GetVnfResponse{
367 VNFID: externalVNFID,
368 CloudRegionID: cloudRegionID,
369 Namespace: namespace,
370 VNFComponents: deserializedResourceNameMap,
373 w.Header().Set("Content-Type", "application/json")
374 w.WriteHeader(http.StatusOK)
375 json.NewEncoder(w).Encode(resp)