aboutsummaryrefslogtreecommitdiffstats
path: root/src/k8splugin/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/k8splugin/api')
-rw-r--r--src/k8splugin/api/api.go9
-rw-r--r--src/k8splugin/api/handler.go7
-rw-r--r--src/k8splugin/api/handler_test.go3
-rw-r--r--src/k8splugin/api/vnfdhandler.go128
-rw-r--r--src/k8splugin/api/vnfdhandler_test.go336
5 files changed, 479 insertions, 4 deletions
diff --git a/src/k8splugin/api/api.go b/src/k8splugin/api/api.go
index 53db3fb5..e90c994e 100644
--- a/src/k8splugin/api/api.go
+++ b/src/k8splugin/api/api.go
@@ -14,6 +14,7 @@ limitations under the License.
package api
import (
+ "k8splugin/vnfd"
"os"
"path/filepath"
"plugin"
@@ -110,6 +111,14 @@ func NewRouter(kubeconfig string) *mux.Router {
vnfInstanceHandler.HandleFunc("/{cloudRegionID}/{namespace}/{externalVNFID}", DeleteHandler).Methods("DELETE")
vnfInstanceHandler.HandleFunc("/{cloudRegionID}/{namespace}/{externalVNFID}", GetHandler).Methods("GET")
+ vnfdRouter := router.PathPrefix("/v1/vnfd").Subrouter()
+ vh := vnfdHandler{vnfdClient: vnfd.GetVNFDClient()}
+ vnfdRouter.HandleFunc("", vh.vnfdCreateHandler).Methods("POST")
+ vnfdRouter.HandleFunc("/{vnfdID}/upload", vh.vnfdUploadHandler).Methods("POST")
+ vnfdRouter.HandleFunc("", vh.vnfdListHandler).Methods("GET")
+ vnfdRouter.HandleFunc("/{vnfdID}", vh.vnfdGetHandler).Methods("GET")
+ vnfdRouter.HandleFunc("/{vnfdID}", vh.vnfdDeleteHandler).Methods("DELETE")
+
// (TODO): Fix update method
// vnfInstanceHandler.HandleFunc("/{vnfInstanceId}", UpdateHandler).Methods("PUT")
diff --git a/src/k8splugin/api/handler.go b/src/k8splugin/api/handler.go
index 4635e7ba..b4828b76 100644
--- a/src/k8splugin/api/handler.go
+++ b/src/k8splugin/api/handler.go
@@ -118,13 +118,12 @@ func CreateHandler(w http.ResponseWriter, r *http.Request) {
// krd.AddNetworkAnnotationsToPod(kubeData, resource.Networks)
// "{"deployment":<>,"service":<>}"
- out, err := json.Marshal(resourceNameMap)
+ serializedResourceNameMap, err := db.Serialize(resourceNameMap)
if err != nil {
werr := pkgerrors.Wrap(err, "Create VNF deployment JSON Marshalling error")
http.Error(w, werr.Error(), http.StatusInternalServerError)
return
}
- serializedResourceNameMap := string(out)
// key: cloud1-default-uuid
// value: "{"deployment":<>,"service":<>}"
@@ -232,7 +231,7 @@ func DeleteHandler(w http.ResponseWriter, r *http.Request) {
},
*/
deserializedResourceNameMap := make(map[string][]string)
- err = json.Unmarshal([]byte(serializedResourceNameMap), &deserializedResourceNameMap)
+ err = db.DeSerialize(serializedResourceNameMap, &deserializedResourceNameMap)
if err != nil {
werr := pkgerrors.Wrap(err, "Delete VNF error")
http.Error(w, werr.Error(), http.StatusInternalServerError)
@@ -357,7 +356,7 @@ func GetHandler(w http.ResponseWriter, r *http.Request) {
},
*/
deserializedResourceNameMap := make(map[string][]string)
- err = json.Unmarshal([]byte(serializedResourceNameMap), &deserializedResourceNameMap)
+ err = db.DeSerialize(serializedResourceNameMap, &deserializedResourceNameMap)
if err != nil {
werr := pkgerrors.Wrap(err, "Get VNF error")
http.Error(w, werr.Error(), http.StatusInternalServerError)
diff --git a/src/k8splugin/api/handler_test.go b/src/k8splugin/api/handler_test.go
index 8d990daa..ac97d011 100644
--- a/src/k8splugin/api/handler_test.go
+++ b/src/k8splugin/api/handler_test.go
@@ -29,6 +29,9 @@ import (
"k8splugin/db"
)
+//Creating an embedded interface via anonymous variable
+//This allows us to make mockDB satisfy the DatabaseConnection
+//interface even if we are not implementing all the methods in it
type mockDB struct {
db.DatabaseConnection
}
diff --git a/src/k8splugin/api/vnfdhandler.go b/src/k8splugin/api/vnfdhandler.go
new file mode 100644
index 00000000..ff777826
--- /dev/null
+++ b/src/k8splugin/api/vnfdhandler.go
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2018 Intel Corporation, Inc
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package api
+
+import (
+ "encoding/json"
+ "net/http"
+
+ "k8splugin/vnfd"
+
+ "github.com/gorilla/mux"
+)
+
+// Used to store backend implementations objects
+// Also simplifies mocking for unit testing purposes
+type vnfdHandler struct {
+ // Interface that implements vnfDefinition operations
+ // We will set this variable with a mock interface for testing
+ vnfdClient vnfd.VNFDefinitionInterface
+}
+
+// vnfdCreateHandler handles creation of the vnfd entry in the database
+func (h vnfdHandler) vnfdCreateHandler(w http.ResponseWriter, r *http.Request) {
+ var v vnfd.VNFDefinition
+
+ if r.Body == nil {
+ http.Error(w, "Empty body", http.StatusBadRequest)
+ return
+ }
+
+ err := json.NewDecoder(r.Body).Decode(&v)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusUnprocessableEntity)
+ return
+ }
+
+ // Name is required.
+ if v.Name == "" {
+ http.Error(w, "Missing name in POST request", http.StatusBadRequest)
+ return
+ }
+
+ ret, err := h.vnfdClient.Create(v)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusCreated)
+ err = json.NewEncoder(w).Encode(ret)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
+
+// vnfdUploadHandler handles upload of the vnf tar file into the database
+// Note: This will be implemented in a different patch
+func (h vnfdHandler) vnfdUploadHandler(w http.ResponseWriter, r *http.Request) {
+}
+
+// vnfdListHandler handles GET (list) operations on the /v1/vnfd endpoint
+// Returns a list of vnfd.VNFDefinitions
+func (h vnfdHandler) vnfdListHandler(w http.ResponseWriter, r *http.Request) {
+ ret, err := h.vnfdClient.List()
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ err = json.NewEncoder(w).Encode(ret)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
+
+// vnfdGetHandler handles GET operations on a particular VNFID
+// Returns a vnfd.VNFDefinition
+func (h vnfdHandler) vnfdGetHandler(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ vnfdID := vars["vnfdID"]
+
+ ret, err := h.vnfdClient.Get(vnfdID)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ err = json.NewEncoder(w).Encode(ret)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
+
+// vnfdDeleteHandler handles DELETE operations on a particular VNFID
+func (h vnfdHandler) vnfdDeleteHandler(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ vnfdID := vars["vnfdID"]
+
+ err := h.vnfdClient.Delete(vnfdID)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ w.WriteHeader(http.StatusNoContent)
+}
diff --git a/src/k8splugin/api/vnfdhandler_test.go b/src/k8splugin/api/vnfdhandler_test.go
new file mode 100644
index 00000000..e393be6f
--- /dev/null
+++ b/src/k8splugin/api/vnfdhandler_test.go
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2018 Intel Corporation, Inc
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package api
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+ "k8splugin/vnfd"
+ "net/http"
+ "net/http/httptest"
+ "reflect"
+ "testing"
+
+ pkgerrors "github.com/pkg/errors"
+)
+
+//Creating an embedded interface via anonymous variable
+//This allows us to make mockDB satisfy the DatabaseConnection
+//interface even if we are not implementing all the methods in it
+type mockVNFDefinition struct {
+ vnfd.VNFDefinitionInterface
+ // Items and err will be used to customize each test
+ // via a localized instantiation of mockVNFDefinition
+ Items []vnfd.VNFDefinition
+ Err error
+}
+
+func (m *mockVNFDefinition) Create(inp vnfd.VNFDefinition) (vnfd.VNFDefinition, error) {
+ if m.Err != nil {
+ return vnfd.VNFDefinition{}, m.Err
+ }
+
+ return m.Items[0], nil
+}
+
+func (m *mockVNFDefinition) List() ([]vnfd.VNFDefinition, error) {
+ if m.Err != nil {
+ return []vnfd.VNFDefinition{}, m.Err
+ }
+
+ return m.Items, nil
+}
+
+func (m *mockVNFDefinition) Get(vnfID string) (vnfd.VNFDefinition, error) {
+ if m.Err != nil {
+ return vnfd.VNFDefinition{}, m.Err
+ }
+
+ return m.Items[0], nil
+}
+
+func (m *mockVNFDefinition) Delete(vnfID string) error {
+ return m.Err
+}
+
+func TestVnfdCreateHandler(t *testing.T) {
+ testCases := []struct {
+ label string
+ reader io.Reader
+ expected vnfd.VNFDefinition
+ expectedCode int
+ vnfdClient *mockVNFDefinition
+ }{
+ {
+ label: "Missing Body Failure",
+ expectedCode: http.StatusBadRequest,
+ vnfdClient: &mockVNFDefinition{},
+ },
+ {
+ label: "Create without UUID",
+ expectedCode: http.StatusCreated,
+ reader: bytes.NewBuffer([]byte(`{
+ "name":"testdomain",
+ "description":"test description",
+ "service-type":"firewall"
+ }`)),
+ expected: vnfd.VNFDefinition{
+ UUID: "123e4567-e89b-12d3-a456-426655440000",
+ Name: "testvnf",
+ Description: "test description",
+ ServiceType: "firewall",
+ },
+ vnfdClient: &mockVNFDefinition{
+ //Items that will be returned by the mocked Client
+ Items: []vnfd.VNFDefinition{
+ {
+ UUID: "123e4567-e89b-12d3-a456-426655440000",
+ Name: "testvnf",
+ Description: "test description",
+ ServiceType: "firewall",
+ },
+ },
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ vh := vnfdHandler{vnfdClient: testCase.vnfdClient}
+ req, err := http.NewRequest("POST", "/v1/vnfd", testCase.reader)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rr := httptest.NewRecorder()
+ hr := http.HandlerFunc(vh.vnfdCreateHandler)
+ hr.ServeHTTP(rr, req)
+
+ //Check returned code
+ if rr.Code != testCase.expectedCode {
+ t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, rr.Code)
+ }
+
+ //Check returned body only if statusCreated
+ if rr.Code == http.StatusCreated {
+ got := vnfd.VNFDefinition{}
+ json.NewDecoder(rr.Body).Decode(&got)
+
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("vnfdCreateHandler returned unexpected body: got %v;"+
+ " expected %v", got, testCase.expected)
+ }
+ }
+ })
+ }
+}
+
+func TestVnfdListHandler(t *testing.T) {
+
+ testCases := []struct {
+ label string
+ expected []vnfd.VNFDefinition
+ expectedCode int
+ vnfdClient *mockVNFDefinition
+ }{
+ {
+ label: "List VNF Definitions",
+ expectedCode: http.StatusOK,
+ expected: []vnfd.VNFDefinition{
+ {
+ UUID: "123e4567-e89b-12d3-a456-426655440000",
+ Name: "testvnf",
+ Description: "test description",
+ ServiceType: "firewall",
+ },
+ {
+ UUID: "123e4567-e89b-12d3-a456-426655441111",
+ Name: "testvnf2",
+ Description: "test description",
+ ServiceType: "dns",
+ },
+ },
+ vnfdClient: &mockVNFDefinition{
+ // list of definitions that will be returned by the mockclient
+ Items: []vnfd.VNFDefinition{
+ {
+ UUID: "123e4567-e89b-12d3-a456-426655440000",
+ Name: "testvnf",
+ Description: "test description",
+ ServiceType: "firewall",
+ },
+ {
+ UUID: "123e4567-e89b-12d3-a456-426655441111",
+ Name: "testvnf2",
+ Description: "test description",
+ ServiceType: "dns",
+ },
+ },
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ vh := vnfdHandler{vnfdClient: testCase.vnfdClient}
+ req, err := http.NewRequest("GET", "/v1/vnfd", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rr := httptest.NewRecorder()
+ hr := http.HandlerFunc(vh.vnfdListHandler)
+
+ hr.ServeHTTP(rr, req)
+ //Check returned code
+ if rr.Code != testCase.expectedCode {
+ t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, rr.Code)
+ }
+
+ //Check returned body only if statusOK
+ if rr.Code == http.StatusOK {
+ got := []vnfd.VNFDefinition{}
+ json.NewDecoder(rr.Body).Decode(&got)
+
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("vnfdListHandler returned unexpected body: got %v;"+
+ " expected %v", got, testCase.expected)
+ }
+ }
+ })
+ }
+}
+
+func TestVnfdGetHandler(t *testing.T) {
+
+ testCases := []struct {
+ label string
+ expected vnfd.VNFDefinition
+ inpUUID string
+ expectedCode int
+ vnfdClient *mockVNFDefinition
+ }{
+ {
+ label: "Get VNF Definition",
+ expectedCode: http.StatusOK,
+ expected: vnfd.VNFDefinition{
+ UUID: "123e4567-e89b-12d3-a456-426655441111",
+ Name: "testvnf2",
+ Description: "test description",
+ ServiceType: "dns",
+ },
+ inpUUID: "123e4567-e89b-12d3-a456-426655441111",
+ vnfdClient: &mockVNFDefinition{
+ // list of definitions that will be returned by the mockclient
+ Items: []vnfd.VNFDefinition{
+ {
+ UUID: "123e4567-e89b-12d3-a456-426655441111",
+ Name: "testvnf2",
+ Description: "test description",
+ ServiceType: "dns",
+ },
+ },
+ },
+ },
+ {
+ label: "Get Non-Exiting VNF Definition",
+ expectedCode: http.StatusInternalServerError,
+ inpUUID: "123e4567-e89b-12d3-a456-426655440000",
+ vnfdClient: &mockVNFDefinition{
+ // list of definitions that will be returned by the mockclient
+ Items: []vnfd.VNFDefinition{},
+ Err: pkgerrors.New("Internal Error"),
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ vh := vnfdHandler{vnfdClient: testCase.vnfdClient}
+ req, err := http.NewRequest("GET", "/v1/vnfd/"+testCase.inpUUID, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rr := httptest.NewRecorder()
+ hr := http.HandlerFunc(vh.vnfdGetHandler)
+
+ hr.ServeHTTP(rr, req)
+ //Check returned code
+ if rr.Code != testCase.expectedCode {
+ t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, rr.Code)
+ }
+
+ //Check returned body only if statusOK
+ if rr.Code == http.StatusOK {
+ got := vnfd.VNFDefinition{}
+ json.NewDecoder(rr.Body).Decode(&got)
+
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("vnfdListHandler returned unexpected body: got %v;"+
+ " expected %v", got, testCase.expected)
+ }
+ }
+ })
+ }
+}
+
+func TestVnfdDeleteHandler(t *testing.T) {
+
+ testCases := []struct {
+ label string
+ inpUUID string
+ expectedCode int
+ vnfdClient *mockVNFDefinition
+ }{
+ {
+ label: "Delete VNF Definition",
+ expectedCode: http.StatusNoContent,
+ inpUUID: "123e4567-e89b-12d3-a456-426655441111",
+ vnfdClient: &mockVNFDefinition{},
+ },
+ {
+ label: "Delete Non-Exiting VNF Definition",
+ expectedCode: http.StatusInternalServerError,
+ inpUUID: "123e4567-e89b-12d3-a456-426655440000",
+ vnfdClient: &mockVNFDefinition{
+ Err: pkgerrors.New("Internal Error"),
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ vh := vnfdHandler{vnfdClient: testCase.vnfdClient}
+ req, err := http.NewRequest("GET", "/v1/vnfd/"+testCase.inpUUID, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rr := httptest.NewRecorder()
+ hr := http.HandlerFunc(vh.vnfdDeleteHandler)
+
+ hr.ServeHTTP(rr, req)
+ //Check returned code
+ if rr.Code != testCase.expectedCode {
+ t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, rr.Code)
+ }
+ })
+ }
+}