diff options
Diffstat (limited to 'src/k8splugin/api')
-rw-r--r-- | src/k8splugin/api/api.go | 1 | ||||
-rw-r--r-- | src/k8splugin/api/brokerhandler.go | 12 | ||||
-rw-r--r-- | src/k8splugin/api/brokerhandler_test.go | 41 | ||||
-rw-r--r-- | src/k8splugin/api/instancehandler.go | 151 | ||||
-rw-r--r-- | src/k8splugin/api/instancehandler_test.go | 158 |
5 files changed, 218 insertions, 145 deletions
diff --git a/src/k8splugin/api/api.go b/src/k8splugin/api/api.go index 726bd116..c836fc65 100644 --- a/src/k8splugin/api/api.go +++ b/src/k8splugin/api/api.go @@ -46,6 +46,7 @@ func NewRouter(defClient rb.DefinitionManager, "profile-name", "{profile-name}").Methods("GET") instRouter.HandleFunc("/instance/{instID}", instHandler.getHandler).Methods("GET") + instRouter.HandleFunc("/instance/{instID}/status", instHandler.statusHandler).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/brokerhandler.go b/src/k8splugin/api/brokerhandler.go index 669b539f..b377baf1 100644 --- a/src/k8splugin/api/brokerhandler.go +++ b/src/k8splugin/api/brokerhandler.go @@ -134,21 +134,21 @@ func (b brokerInstanceHandler) createHandler(w http.ResponseWriter, r *http.Requ return } - rbName := req.getAttributeValue(req.UserDirectives, "definition-name") + rbName := req.getAttributeValue(req.SDNCDirectives, "k8s-rb-definition-name") if rbName == "" { - http.Error(w, "definition-name is missing from user-directives", http.StatusBadRequest) + http.Error(w, "k8s-rb-definition-name is missing from sdnc-directives", http.StatusBadRequest) return } - rbVersion := req.getAttributeValue(req.UserDirectives, "definition-version") + rbVersion := req.getAttributeValue(req.SDNCDirectives, "k8s-rb-definition-version") if rbVersion == "" { - http.Error(w, "definition-version is missing from user-directives", http.StatusBadRequest) + http.Error(w, "k8s-rb-definition-version is missing from sdnc-directives", http.StatusBadRequest) return } - profileName := req.getAttributeValue(req.UserDirectives, "profile-name") + profileName := req.getAttributeValue(req.SDNCDirectives, "k8s-rb-profile-name") if profileName == "" { - http.Error(w, "profile-name is missing from user-directives", http.StatusBadRequest) + http.Error(w, "k8s-rb-profile-name is missing from sdnc-directives", http.StatusBadRequest) return } diff --git a/src/k8splugin/api/brokerhandler_test.go b/src/k8splugin/api/brokerhandler_test.go index 8ef5e184..00ca3b7b 100644 --- a/src/k8splugin/api/brokerhandler_test.go +++ b/src/k8splugin/api/brokerhandler_test.go @@ -54,11 +54,11 @@ func TestBrokerCreateHandler(t *testing.T) { "user_directives": { "attributes": [ { - "attribute_name": "definition-name", + "attribute_name": "k8s-rb-definition-name", "attribute_value": "test-rbdef" }, { - "attribute_name": "definition-version", + "attribute_name": "k8s-rb-definition-version", "attribute_value": "v1" } ] @@ -67,9 +67,9 @@ func TestBrokerCreateHandler(t *testing.T) { expectedCode: http.StatusBadRequest, }, { - label: "Succesfully create an Instance", + label: "Deprecated parameters passed (user_directives)", input: bytes.NewBuffer([]byte(`{ - "vf-module-model-customization-id": "84sdfkio938", + "vf-module-model-customization-id": "97sdfkio168", "sdnc_directives": { "attributes": [ { @@ -81,15 +81,42 @@ func TestBrokerCreateHandler(t *testing.T) { "user_directives": { "attributes": [ { - "attribute_name": "definition-name", + "attribute_name": "rb-definition-name", + "attribute_value": "test-rbdef" + }, + { + "attribute_name": "rb-definition-version", + "attribute_value": "v1" + }, + { + "attribute_name": "rb-profile-name", + "attribute_value": "profile1" + } + ] + } + }`)), + expectedCode: http.StatusBadRequest, + }, + { + label: "Succesfully create an Instance", + input: bytes.NewBuffer([]byte(`{ + "vf-module-model-customization-id": "84sdfkio938", + "sdnc_directives": { + "attributes": [ + { + "attribute_name": "vf_module_name", + "attribute_value": "test-vf-module-name" + }, + { + "attribute_name": "k8s-rb-definition-name", "attribute_value": "test-rbdef" }, { - "attribute_name": "definition-version", + "attribute_name": "k8s-rb-definition-version", "attribute_value": "v1" }, { - "attribute_name": "profile-name", + "attribute_name": "k8s-rb-profile-name", "attribute_value": "profile1" } ] diff --git a/src/k8splugin/api/instancehandler.go b/src/k8splugin/api/instancehandler.go index be8e64fa..b0437426 100644 --- a/src/k8splugin/api/instancehandler.go +++ b/src/k8splugin/api/instancehandler.go @@ -20,6 +20,7 @@ import ( "net/http" "github.com/onap/multicloud-k8s/src/k8splugin/internal/app" + log "github.com/onap/multicloud-k8s/src/k8splugin/internal/logutils" "github.com/gorilla/mux" pkgerrors "github.com/pkg/errors" @@ -36,14 +37,25 @@ func (i instanceHandler) validateBody(body interface{}) error { switch b := body.(type) { case app.InstanceRequest: if b.CloudRegion == "" { + log.Error("CreateVnfRequest Bad Request", log.Fields{ + "cloudRegion": "Missing CloudRegion in POST request", + }) werr := pkgerrors.Wrap(errors.New("Invalid/Missing CloudRegion in POST request"), "CreateVnfRequest bad request") return werr } if b.RBName == "" || b.RBVersion == "" { + log.Error("CreateVnfRequest Bad Request", log.Fields{ + "message": "One of RBName, RBVersion is missing", + "RBName": b.RBName, + "RBVersion": b.RBVersion, + }) werr := pkgerrors.Wrap(errors.New("Invalid/Missing resource bundle parameters in POST request"), "CreateVnfRequest bad request") return werr } if b.ProfileName == "" { + log.Error("CreateVnfRequest bad request", log.Fields{ + "ProfileName": "Missing profile name in POST request", + }) werr := pkgerrors.Wrap(errors.New("Invalid/Missing profile name in POST request"), "CreateVnfRequest bad request") return werr } @@ -57,9 +69,15 @@ func (i instanceHandler) createHandler(w http.ResponseWriter, r *http.Request) { err := json.NewDecoder(r.Body).Decode(&resource) switch { case err == io.EOF: + log.Error("Body Empty", log.Fields{ + "error": io.EOF, + }) http.Error(w, "Body empty", http.StatusBadRequest) return case err != nil: + log.Error("Error unmarshaling Body", log.Fields{ + "error": err, + }) http.Error(w, err.Error(), http.StatusUnprocessableEntity) return } @@ -67,12 +85,19 @@ func (i instanceHandler) createHandler(w http.ResponseWriter, r *http.Request) { // Check body for expected parameters err = i.validateBody(resource) if err != nil { + log.Error("Invalid Parameters in Body", log.Fields{ + "error": err, + }) http.Error(w, err.Error(), http.StatusUnprocessableEntity) return } resp, err := i.client.Create(resource) if err != nil { + log.Error("Error Creating Resource", log.Fields{ + "error": err, + "resource": resource, + }) http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -81,6 +106,10 @@ func (i instanceHandler) createHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusCreated) 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 } @@ -93,6 +122,10 @@ func (i instanceHandler) getHandler(w http.ResponseWriter, r *http.Request) { resp, err := i.client.Get(id) if err != nil { + log.Error("Error getting Instance", log.Fields{ + "error": err, + "id": id, + }) http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -101,6 +134,38 @@ func (i instanceHandler) getHandler(w http.ResponseWriter, r *http.Request) { 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 + } +} + +// statusHandler retrieves status about an instance via the ID +func (i instanceHandler) statusHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + id := vars["instID"] + + resp, err := i.client.Status(id) + if err != nil { + log.Error("Error getting Status", log.Fields{ + "error": err, + "id": id, + }) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + 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 } @@ -113,10 +178,16 @@ func (i instanceHandler) listHandler(w http.ResponseWriter, r *http.Request) { //Which will list all instances rbName := r.FormValue("rb-name") rbVersion := r.FormValue("rb-version") - ProfileName := r.FormValue("profile-name") + profileName := r.FormValue("profile-name") - resp, err := i.client.List(rbName, rbVersion, ProfileName) + resp, err := i.client.List(rbName, rbVersion, profileName) if err != nil { + log.Error("Error listing instances", log.Fields{ + "error": err, + "rb-name": rbName, + "rb-version": rbVersion, + "profile-name": profileName, + }) http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -125,6 +196,10 @@ func (i instanceHandler) listHandler(w http.ResponseWriter, r *http.Request) { 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 } @@ -137,6 +212,9 @@ func (i instanceHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { err := i.client.Delete(id) if err != nil { + log.Error("Error Deleting Instance", log.Fields{ + "error": err, + }) http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -144,72 +222,3 @@ func (i instanceHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) } - -// // UpdateHandler method to update a VNF instance. -// func UpdateHandler(w http.ResponseWriter, r *http.Request) { -// vars := mux.Vars(r) -// id := vars["vnfInstanceId"] - -// var resource UpdateVnfRequest - -// if r.Body == nil { -// http.Error(w, "Body empty", http.StatusBadRequest) -// return -// } - -// err := json.NewDecoder(r.Body).Decode(&resource) -// if err != nil { -// http.Error(w, err.Error(), http.StatusUnprocessableEntity) -// return -// } - -// err = validateBody(resource) -// if err != nil { -// http.Error(w, err.Error(), http.StatusUnprocessableEntity) -// return -// } - -// kubeData, err := utils.ReadCSARFromFileSystem(resource.CsarID) - -// if kubeData.Deployment == nil { -// werr := pkgerrors.Wrap(err, "Update VNF deployment error") -// http.Error(w, werr.Error(), http.StatusInternalServerError) -// return -// } -// kubeData.Deployment.SetUID(types.UID(id)) - -// if err != nil { -// werr := pkgerrors.Wrap(err, "Update VNF deployment information error") -// http.Error(w, werr.Error(), http.StatusInternalServerError) -// return -// } - -// // (TODO): Read kubeconfig for specific Cloud Region from local file system -// // if present or download it from AAI -// s, err := NewVNFInstanceService("../kubeconfig/config") -// if err != nil { -// http.Error(w, err.Error(), http.StatusInternalServerError) -// return -// } - -// err = s.Client.UpdateDeployment(kubeData.Deployment, resource.Namespace) -// if err != nil { -// werr := pkgerrors.Wrap(err, "Update VNF error") - -// http.Error(w, werr.Error(), http.StatusInternalServerError) -// return -// } - -// resp := UpdateVnfResponse{ -// DeploymentID: id, -// } - -// w.Header().Set("Content-Type", "application/json") -// w.WriteHeader(http.StatusCreated) - -// err = json.NewEncoder(w).Encode(resp) -// if err != nil { -// werr := pkgerrors.Wrap(err, "Parsing output of new VNF error") -// http.Error(w, werr.Error(), http.StatusInternalServerError) -// } -// } diff --git a/src/k8splugin/api/instancehandler_test.go b/src/k8splugin/api/instancehandler_test.go index 418054ec..7b6594cf 100644 --- a/src/k8splugin/api/instancehandler_test.go +++ b/src/k8splugin/api/instancehandler_test.go @@ -39,9 +39,10 @@ type mockInstanceClient struct { app.InstanceManager // Items and err will be used to customize each test // via a localized instantiation of mockInstanceClient - items []app.InstanceResponse - miniitems []app.InstanceMiniResponse - err error + items []app.InstanceResponse + miniitems []app.InstanceMiniResponse + statusItem app.InstanceStatus + err error } func (m *mockInstanceClient) Create(inp app.InstanceRequest) (app.InstanceResponse, error) { @@ -60,6 +61,14 @@ func (m *mockInstanceClient) Get(id string) (app.InstanceResponse, error) { return m.items[0], nil } +func (m *mockInstanceClient) Status(id string) (app.InstanceStatus, error) { + if m.err != nil { + return app.InstanceStatus{}, m.err + } + + return m.statusItem, nil +} + func (m *mockInstanceClient) List(rbname, rbversion, profilename string) ([]app.InstanceMiniResponse, error) { if m.err != nil { return []app.InstanceMiniResponse{}, m.err @@ -307,6 +316,91 @@ func TestInstanceGetHandler(t *testing.T) { } } +func TestStatusHandler(t *testing.T) { + testCases := []struct { + label string + input string + expectedCode int + expectedResponse *app.InstanceStatus + instClient *mockInstanceClient + }{ + { + label: "Fail to Get Status", + input: "HaKpys8e", + expectedCode: http.StatusInternalServerError, + instClient: &mockInstanceClient{ + err: pkgerrors.New("Internal error"), + }, + }, + { + label: "Succesful GET Status", + input: "HaKpys8e", + expectedCode: http.StatusOK, + expectedResponse: &app.InstanceStatus{ + Request: app.InstanceRequest{ + RBName: "test-rbdef", + RBVersion: "v1", + ProfileName: "profile1", + CloudRegion: "region1", + }, + Ready: true, + ResourceCount: 2, + PodStatuses: []app.PodStatus{ + { + Name: "test-pod1", + Namespace: "default", + Ready: true, + IPAddresses: []string{"192.168.1.1", "192.168.2.1"}, + }, + { + Name: "test-pod2", + Namespace: "default", + Ready: true, + IPAddresses: []string{"192.168.3.1", "192.168.5.1"}, + }, + }, + }, + instClient: &mockInstanceClient{ + statusItem: app.InstanceStatus{ + Request: app.InstanceRequest{ + RBName: "test-rbdef", + RBVersion: "v1", + ProfileName: "profile1", + CloudRegion: "region1", + }, + Ready: true, + ResourceCount: 2, + PodStatuses: []app.PodStatus{ + { + Name: "test-pod1", + Namespace: "default", + Ready: true, + IPAddresses: []string{"192.168.1.1", "192.168.2.1"}, + }, + { + Name: "test-pod2", + Namespace: "default", + Ready: true, + IPAddresses: []string{"192.168.3.1", "192.168.5.1"}, + }, + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + request := httptest.NewRequest("GET", "/v1/instance/"+testCase.input+"/status", nil) + resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient, nil, nil, nil)) + + if testCase.expectedCode != resp.StatusCode { + t.Fatalf("Request method returned: %v and it was expected: %v", resp.StatusCode, testCase.expectedCode) + } + }) + } +} + func TestInstanceListHandler(t *testing.T) { testCases := []struct { label string @@ -488,61 +582,3 @@ func TestDeleteHandler(t *testing.T) { }) } } - -// TODO: Update this test when the UpdateVNF endpoint is fixed. -/* -func TestVNFInstanceUpdate(t *testing.T) { - t.Run("Succesful update a VNF", func(t *testing.T) { - payload := []byte(`{ - "cloud_region_id": "region1", - "csar_id": "UUID-1", - "oof_parameters": [{ - "key1": "value1", - "key2": "value2", - "key3": {} - }], - "network_parameters": { - "oam_ip_address": { - "connection_point": "string", - "ip_address": "string", - "workload_name": "string" - } - } - }`) - expected := &UpdateVnfResponse{ - DeploymentID: "1", - } - - var result UpdateVnfResponse - - req := httptest.NewRequest("PUT", "/v1/vnf_instances/1", bytes.NewBuffer(payload)) - - GetVNFClient = func(configPath string) (krd.VNFInstanceClientInterface, error) { - return &mockClient{ - update: func() error { - return nil - }, - }, nil - } - utils.ReadCSARFromFileSystem = func(csarID string) (*krd.KubernetesData, error) { - kubeData := &krd.KubernetesData{ - Deployment: &appsV1.Deployment{}, - Service: &coreV1.Service{}, - } - return kubeData, nil - } - - response := executeRequest(req) - checkResponseCode(t, http.StatusCreated, response.Code) - - err := json.NewDecoder(response.Body).Decode(&result) - if err != nil { - t.Fatalf("TestVNFInstanceUpdate returned:\n result=%v\n expected=%v", err, expected.DeploymentID) - } - - if resp.DeploymentID != expected.DeploymentID { - t.Fatalf("TestVNFInstanceUpdate returned:\n result=%v\n expected=%v", resp.DeploymentID, expected.DeploymentID) - } - }) -} -*/ |