From 0b59486c82a9786c85438f6352636b19b83e1021 Mon Sep 17 00:00:00 2001 From: Eric Multanen Date: Thu, 16 Apr 2020 10:44:06 -0700 Subject: Controller API support Add controller API support as baseline for adding gRPC framework. Issue-ID: MULTICLOUD-1019 Signed-off-by: Eric Multanen Change-Id: Ifd522a0eefbb8e54be45cc62003d3809283c9bfe --- src/orchestrator/api/api.go | 3 +- src/orchestrator/api/controllerhandler.go | 106 +++++++++++++++++++++++-- src/orchestrator/api/controllerhandler_test.go | 57 +++++++++---- 3 files changed, 144 insertions(+), 22 deletions(-) (limited to 'src/orchestrator/api') diff --git a/src/orchestrator/api/api.go b/src/orchestrator/api/api.go index 6277d994..8b4b91a1 100644 --- a/src/orchestrator/api/api.go +++ b/src/orchestrator/api/api.go @@ -111,7 +111,8 @@ func NewRouter(projectClient moduleLib.ProjectManager, router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/composite-profiles/{composite-profile-name}/profiles/{app-profile}", appProfileHandler.deleteAppProfileHandler).Methods("DELETE") router.HandleFunc("/controllers", controlHandler.createHandler).Methods("POST") - router.HandleFunc("/controllers", controlHandler.createHandler).Methods("PUT") + router.HandleFunc("/controllers", controlHandler.getHandler).Methods("GET") + router.HandleFunc("/controllers/{controller-name}", controlHandler.putHandler).Methods("PUT") router.HandleFunc("/controllers/{controller-name}", controlHandler.getHandler).Methods("GET") router.HandleFunc("/controllers/{controller-name}", controlHandler.deleteHandler).Methods("DELETE") //setting routes for genericPlacementIntent diff --git a/src/orchestrator/api/controllerhandler.go b/src/orchestrator/api/controllerhandler.go index 4f98c023..1dad2bf8 100644 --- a/src/orchestrator/api/controllerhandler.go +++ b/src/orchestrator/api/controllerhandler.go @@ -22,7 +22,9 @@ import ( "net/http" "github.com/gorilla/mux" + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation" moduleLib "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module" + pkgerrors "github.com/pkg/errors" ) // Used to store backend implementations objects @@ -33,6 +35,43 @@ type controllerHandler struct { client moduleLib.ControllerManager } +// Check for valid format of input parameters +func validateControllerInputs(c moduleLib.Controller) error { + // validate metadata + err := moduleLib.IsValidMetadata(c.Metadata) + if err != nil { + return pkgerrors.Wrap(err, "Invalid controller metadata") + } + + errs := validation.IsValidName(c.Spec.Host) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid host name for controller %v, errors: %v", c.Spec.Host, errs) + } + + errs = validation.IsValidNumber(c.Spec.Port, 0, 65535) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid controller port [%v], errors: %v", c.Spec.Port, errs) + } + + found := false + for _, val := range moduleLib.CONTROLLER_TYPES { + if c.Spec.Type == val { + found = true + break + } + } + if !found { + return pkgerrors.Errorf("Invalid controller type: %v", c.Spec.Type) + } + + errs = validation.IsValidNumber(c.Spec.Priority, moduleLib.MinControllerPriority, moduleLib.MaxControllerPriority) + if len(errs) > 0 { + return pkgerrors.Errorf("Invalid controller priority = [%v], errors: %v", c.Spec.Priority, errs) + } + + return nil +} + // Create handles creation of the controller entry in the database func (h controllerHandler) createHandler(w http.ResponseWriter, r *http.Request) { var m moduleLib.Controller @@ -48,12 +87,12 @@ func (h controllerHandler) createHandler(w http.ResponseWriter, r *http.Request) } // Name is required. - if m.Name == "" { + if m.Metadata.Name == "" { http.Error(w, "Missing name in POST request", http.StatusBadRequest) return } - ret, err := h.client.CreateController(m) + ret, err := h.client.CreateController(m, false) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -68,18 +107,73 @@ func (h controllerHandler) createHandler(w http.ResponseWriter, r *http.Request) } } -// Get handles GET operations on a particular controller Name -// Returns a controller -func (h controllerHandler) getHandler(w http.ResponseWriter, r *http.Request) { +// Put handles creation or update of the controller entry in the database +func (h controllerHandler) putHandler(w http.ResponseWriter, r *http.Request) { + var m moduleLib.Controller vars := mux.Vars(r) name := vars["controller-name"] - ret, err := h.client.GetController(name) + err := json.NewDecoder(r.Body).Decode(&m) + switch { + case err == io.EOF: + http.Error(w, "Empty body", http.StatusBadRequest) + return + case err != nil: + http.Error(w, err.Error(), http.StatusUnprocessableEntity) + return + } + + // Name is required. + if m.Metadata.Name == "" { + http.Error(w, "Missing name in POST request", http.StatusBadRequest) + return + } + + // name in URL should match name in body + if m.Metadata.Name != name { + http.Error(w, "Mismatched name in PUT request", http.StatusBadRequest) + return + } + + ret, err := h.client.CreateController(m, true) 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 + } +} + +// Get handles GET operations on a particular controller Name +// Returns a controller +func (h controllerHandler) getHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name := vars["controller-name"] + var ret interface{} + var err error + + // handle the get all controllers case + if len(name) == 0 { + ret, err = h.client.GetControllers() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } else { + + ret, err = h.client.GetController(name) + 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) diff --git a/src/orchestrator/api/controllerhandler_test.go b/src/orchestrator/api/controllerhandler_test.go index 3c543cb8..a2f93ea7 100644 --- a/src/orchestrator/api/controllerhandler_test.go +++ b/src/orchestrator/api/controllerhandler_test.go @@ -40,7 +40,7 @@ type mockControllerManager struct { Err error } -func (m *mockControllerManager) CreateController(inp moduleLib.Controller) (moduleLib.Controller, error) { +func (m *mockControllerManager) CreateController(inp moduleLib.Controller, mayExist bool) (moduleLib.Controller, error) { if m.Err != nil { return moduleLib.Controller{}, m.Err } @@ -56,6 +56,14 @@ func (m *mockControllerManager) GetController(name string) (moduleLib.Controller return m.Items[0], nil } +func (m *mockControllerManager) GetControllers() ([]moduleLib.Controller, error) { + if m.Err != nil { + return []moduleLib.Controller{}, m.Err + } + + return m.Items, nil +} + func (m *mockControllerManager) DeleteController(name string) error { return m.Err } @@ -77,22 +85,33 @@ func TestControllerCreateHandler(t *testing.T) { label: "Create Controller", expectedCode: http.StatusCreated, reader: bytes.NewBuffer([]byte(`{ - "name":"testController", + "metadata": { + "name":"testController" + }, + "spec": { "ip-address":"10.188.234.1", - "port":8080 + "port":8080 } }`)), expected: moduleLib.Controller{ - Name: "testController", - Host: "10.188.234.1", - Port: 8080, + Metadata: moduleLib.Metadata{ + Name: "testController", + }, + Spec: moduleLib.ControllerSpec{ + Host: "10.188.234.1", + Port: 8080, + }, }, controllerClient: &mockControllerManager{ //Items that will be returned by the mocked Client Items: []moduleLib.Controller{ { - Name: "testController", - Host: "10.188.234.1", - Port: 8080, + Metadata: moduleLib.Metadata{ + Name: "testController", + }, + Spec: moduleLib.ControllerSpec{ + Host: "10.188.234.1", + Port: 8080, + }, }, }, }, @@ -144,17 +163,25 @@ func TestControllerGetHandler(t *testing.T) { label: "Get Controller", expectedCode: http.StatusOK, expected: moduleLib.Controller{ - Name: "testController", - Host: "10.188.234.1", - Port: 8080, + Metadata: moduleLib.Metadata{ + Name: "testController", + }, + Spec: moduleLib.ControllerSpec{ + Host: "10.188.234.1", + Port: 8080, + }, }, name: "testController", controllerClient: &mockControllerManager{ Items: []moduleLib.Controller{ { - Name: "testController", - Host: "10.188.234.1", - Port: 8080, + Metadata: moduleLib.Metadata{ + Name: "testController", + }, + Spec: moduleLib.ControllerSpec{ + Host: "10.188.234.1", + Port: 8080, + }, }, }, }, -- cgit 1.2.3-korg