diff options
-rw-r--r-- | src/k8splugin/api/api.go | 6 | ||||
-rw-r--r-- | src/k8splugin/api/instancehandler.go | 46 | ||||
-rw-r--r-- | src/k8splugin/internal/app/client.go | 35 | ||||
-rw-r--r-- | src/k8splugin/internal/app/instance.go | 65 |
4 files changed, 150 insertions, 2 deletions
diff --git a/src/k8splugin/api/api.go b/src/k8splugin/api/api.go index c836fc65..e55d833b 100644 --- a/src/k8splugin/api/api.go +++ b/src/k8splugin/api/api.go @@ -1,5 +1,6 @@ /* Copyright 2018 Intel Corporation. +Copyright © 2021 Samsung Electronics 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 @@ -47,6 +48,11 @@ func NewRouter(defClient rb.DefinitionManager, instRouter.HandleFunc("/instance/{instID}", instHandler.getHandler).Methods("GET") instRouter.HandleFunc("/instance/{instID}/status", instHandler.statusHandler).Methods("GET") + instRouter.HandleFunc("/instance/{instID}/query", instHandler.queryHandler). + Queries("ApiVersion", "{ApiVersion}", + "Kind", "{Kind}", + "Name", "{Name}", + "Labels", "{Labels}").Methods("GET") instRouter.HandleFunc("/instance/{instID}", instHandler.deleteHandler).Methods("DELETE") // (TODO): Fix update method // instRouter.HandleFunc("/{vnfInstanceId}", UpdateHandler).Methods("PUT") diff --git a/src/k8splugin/api/instancehandler.go b/src/k8splugin/api/instancehandler.go index b0437426..b56a8e12 100644 --- a/src/k8splugin/api/instancehandler.go +++ b/src/k8splugin/api/instancehandler.go @@ -1,5 +1,6 @@ /* Copyright 2018 Intel Corporation. +Copyright © 2021 Samsung Electronics 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 @@ -171,6 +172,51 @@ func (i instanceHandler) statusHandler(w http.ResponseWriter, r *http.Request) { } } +// queryHandler retrieves information about specified resources for instance +func (i instanceHandler) queryHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + id := vars["instID"] + apiVersion := r.FormValue("ApiVersion") + kind := r.FormValue("Kind") + name := r.FormValue("Name") + labels := r.FormValue("Labels") + if apiVersion == "" { + http.Error(w, "Missing apiVersion mandatory parameter", http.StatusBadRequest) + return + } + if kind == "" { + http.Error(w, "Missing kind mandatory parameter", http.StatusBadRequest) + return + } + if name == "" && labels == "" { + http.Error(w, "Name or Labels parameter must be provided", http.StatusBadRequest) + return + } + resp, err := i.client.Query(id, apiVersion, kind, name, labels) + if err != nil { + log.Error("Error getting Query results", log.Fields{ + "error": err, + "id": id, + "apiVersion": apiVersion, + "kind": kind, + "name": name, + "labels": labels, + }) + http.Error(w, err.Error(), http.StatusInternalServerError) + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + err = json.NewEncoder(w).Encode(resp) + if err != nil { + log.Error("Error Marshaling Response", log.Fields{ + "error": err, + "response": resp, + }) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + // listHandler retrieves information about an instance via the ID func (i instanceHandler) listHandler(w http.ResponseWriter, r *http.Request) { diff --git a/src/k8splugin/internal/app/client.go b/src/k8splugin/internal/app/client.go index 6762d1bc..f0edf8c9 100644 --- a/src/k8splugin/internal/app/client.go +++ b/src/k8splugin/internal/app/client.go @@ -1,6 +1,6 @@ /* Copyright 2018 Intel Corporation. -Copyright © 2020 Samsung Electronics +Copyright © 2021 Samsung Electronics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -90,6 +90,39 @@ func (k *KubernetesClient) getPodsByLabel(namespace string) ([]ResourceStatus, e return resp, nil } +func (k *KubernetesClient) queryResources(apiVersion, kind, labelSelector, namespace string) ([]ResourceStatus, error) { + dynClient := k.GetDynamicClient() + mapper := k.GetMapper() + gvk := schema.FromAPIVersionAndKind(apiVersion, kind) + mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version) + if err != nil { + return nil, pkgerrors.Wrap(err, "Preparing mapper based on GVK") + } + + gvr := mapping.Resource + opts := metav1.ListOptions{ + LabelSelector: labelSelector, + } + var unstrList *unstructured.UnstructuredList + switch mapping.Scope.Name() { + case meta.RESTScopeNameNamespace: + unstrList, err = dynClient.Resource(gvr).Namespace(namespace).List(opts) + case meta.RESTScopeNameRoot: + unstrList, err = dynClient.Resource(gvr).List(opts) + default: + return nil, pkgerrors.New("Got an unknown RESTScopeName for mapping: " + gvk.String()) + } + if err != nil { + return nil, pkgerrors.Wrap(err, "Querying for resources") + } + + resp := make([]ResourceStatus, len(unstrList.Items)) + for _, unstr := range unstrList.Items { + resp = append(resp, ResourceStatus{unstr.GetName(), gvk, unstr}) + } + return resp, nil +} + // getResourcesStatus yields status of given generic resource func (k *KubernetesClient) getResourceStatus(res helm.KubernetesResource, namespace string) (ResourceStatus, error) { dynClient := k.GetDynamicClient() diff --git a/src/k8splugin/internal/app/instance.go b/src/k8splugin/internal/app/instance.go index a6e213c1..e789664e 100644 --- a/src/k8splugin/internal/app/instance.go +++ b/src/k8splugin/internal/app/instance.go @@ -1,6 +1,6 @@ /* * Copyright 2018 Intel Corporation, Inc - * Copyright © 2020 Samsung Electronics + * Copyright © 2021 Samsung Electronics * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -74,6 +74,7 @@ type InstanceManager interface { Create(i InstanceRequest) (InstanceResponse, error) Get(id string) (InstanceResponse, error) Status(id string) (InstanceStatus, error) + Query(id, apiVersion, kind, name, labels string) (InstanceStatus, error) List(rbname, rbversion, profilename string) ([]InstanceMiniResponse, error) Find(rbName string, ver string, profile string, labelKeys map[string]string) ([]InstanceMiniResponse, error) Delete(id string) error @@ -198,6 +199,68 @@ func (v *InstanceClient) Get(id string) (InstanceResponse, error) { return InstanceResponse{}, pkgerrors.New("Error getting Instance") } +// Query returns state of instance's filtered resources +func (v *InstanceClient) Query(id, apiVersion, kind, name, labels string) (InstanceStatus, error) { + + //Read the status from the DB + key := InstanceKey{ + ID: id, + } + value, err := db.DBconn.Read(v.storeName, key, v.tagInst) + if err != nil { + return InstanceStatus{}, pkgerrors.Wrap(err, "Get Instance") + } + if value == nil { //value is a byte array + return InstanceStatus{}, pkgerrors.New("Status is not available") + } + resResp := InstanceResponse{} + err = db.DBconn.Unmarshal(value, &resResp) + if err != nil { + return InstanceStatus{}, pkgerrors.Wrap(err, "Unmarshaling Instance Value") + } + + k8sClient := KubernetesClient{} + err = k8sClient.init(resResp.Request.CloudRegion, id) + if err != nil { + return InstanceStatus{}, pkgerrors.Wrap(err, "Getting CloudRegion Information") + } + + var resourcesStatus []ResourceStatus + if labels != "" { + resList, err := k8sClient.queryResources(apiVersion, kind, labels, resResp.Namespace) + if err != nil { + return InstanceStatus{}, pkgerrors.Wrap(err, "Querying Resources") + } + // If user specifies both label and name, we want to pick up only single resource from these matching label + if name != "" { + //Assigning 0-length, because we may actually not find matching name + resourcesStatus = make([]ResourceStatus, 0) + for _, res := range resList { + if res.Name == name { + resourcesStatus = append(resourcesStatus, res) + break + } + } + } else { + resourcesStatus = resList + } + } else if name != "" { + resIdentifier := helm.KubernetesResource{} + res, err := k8sClient.getResourceStatus(resIdentifier, resResp.Namespace) + if err != nil { + return InstanceStatus{}, pkgerrors.Wrap(err, "Querying Resource") + } + resourcesStatus = []ResourceStatus{res} + } + + resp := InstanceStatus{ + Request: resResp.Request, + ResourceCount: int32(len(resourcesStatus)), + ResourcesStatus: resourcesStatus, + } + return resp, nil +} + // Status returns the status for the instance func (v *InstanceClient) Status(id string) (InstanceStatus, error) { |