aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonrad Bańka <k.banka@samsung.com>2021-02-24 18:28:56 +0100
committerKonrad Bańka <k.banka@samsung.com>2021-02-24 21:43:07 +0100
commit74dfd71d3628c52e63f66c079244638c675b2b9c (patch)
tree1162640670a7bf6b3f8f3ab29b58da8bd064cff1
parent69f17bdaf539b3ad89f0c3770ea624b512b80fbd (diff)
Provide Query API for CNF Instances
Query API doesn't directly use Status API code, in order to allow for querying derived resources that might not be typically returned by Status API like replicasets for deployment. Issue-ID: MULTICLOUD-1305 Signed-off-by: Konrad Bańka <k.banka@samsung.com> Change-Id: If15adce23845880f3e6771cc8eab78a78ab13517
-rw-r--r--src/k8splugin/api/api.go6
-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.go65
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) {