aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRitu Sood <ritu.sood@intel.com>2021-02-25 14:17:19 +0000
committerGerrit Code Review <gerrit@onap.org>2021-02-25 14:17:19 +0000
commit965da8328566d58b2b38373f76aa1ab79c0b314e (patch)
tree21d98c7a7d73b9f8db7fb0b78f779601f71b4f17 /src
parent2f09583725c8481ea3d7505ed2394c180af5ef03 (diff)
parent74dfd71d3628c52e63f66c079244638c675b2b9c (diff)
Merge "Provide Query API for CNF Instances"
Diffstat (limited to 'src')
-rw-r--r--src/k8splugin/api/api.go5
-rw-r--r--src/k8splugin/api/instancehandler.go46
-rw-r--r--src/k8splugin/internal/app/client.go35
-rw-r--r--src/k8splugin/internal/app/instance.go63
4 files changed, 148 insertions, 1 deletions
diff --git a/src/k8splugin/api/api.go b/src/k8splugin/api/api.go
index cb094683..a7aa0be7 100644
--- a/src/k8splugin/api/api.go
+++ b/src/k8splugin/api/api.go
@@ -48,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 69ade3a8..b11283e0 100644
--- a/src/k8splugin/internal/app/instance.go
+++ b/src/k8splugin/internal/app/instance.go
@@ -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
@@ -208,6 +209,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) {