From 91fe5c50c2d882a5c831dd473d8db765b2dd8699 Mon Sep 17 00:00:00 2001 From: Lukasz Rajewski Date: Mon, 2 Aug 2021 22:15:35 +0200 Subject: Config List handler added to Config API Config List handler added to Config API Issue-ID: MULTICLOUD-1332 Signed-off-by: Lukasz Rajewski Change-Id: I63355dd6b05e70398cfc89744efa332926286c40 --- src/k8splugin/api/api.go | 1 + src/k8splugin/api/confighandler.go | 21 +++++++++++++++ src/k8splugin/internal/app/config.go | 21 ++++++++++++++- src/k8splugin/internal/app/config_backend.go | 27 ++++++++++++++++++++ src/k8splugin/internal/app/config_test.go | 38 ++++++++++++++++++++++++---- src/k8splugin/internal/db/etcd.go | 19 +++++++++++++- src/k8splugin/internal/db/etcd_testing.go | 12 +++++++++ 7 files changed, 132 insertions(+), 7 deletions(-) diff --git a/src/k8splugin/api/api.go b/src/k8splugin/api/api.go index 4a196ae2..1c7c5eaf 100644 --- a/src/k8splugin/api/api.go +++ b/src/k8splugin/api/api.go @@ -116,6 +116,7 @@ func NewRouter(defClient rb.DefinitionManager, } configHandler := rbConfigHandler{client: configClient} instRouter.HandleFunc("/instance/{instID}/config", configHandler.createHandler).Methods("POST") + instRouter.HandleFunc("/instance/{instID}/config", configHandler.listHandler).Methods("GET") instRouter.HandleFunc("/instance/{instID}/config/{cfgname}", configHandler.getHandler).Methods("GET") instRouter.HandleFunc("/instance/{instID}/config/{cfgname}", configHandler.updateHandler).Methods("PUT") instRouter.HandleFunc("/instance/{instID}/config/{cfgname}", configHandler.deleteHandler).Methods("DELETE") diff --git a/src/k8splugin/api/confighandler.go b/src/k8splugin/api/confighandler.go index f4bb0862..4ce30799 100644 --- a/src/k8splugin/api/confighandler.go +++ b/src/k8splugin/api/confighandler.go @@ -94,6 +94,27 @@ func (h rbConfigHandler) getHandler(w http.ResponseWriter, r *http.Request) { } } +// listHandler handles GET operations for all configs of instance +// Returns a app.Definition +func (h rbConfigHandler) listHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + instanceID := vars["instID"] + + ret, err := h.client.List(instanceID) + 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 + } +} + // deleteHandler handles DELETE operations on a config func (h rbConfigHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) diff --git a/src/k8splugin/internal/app/config.go b/src/k8splugin/internal/app/config.go index d0f8876d..94acadcc 100644 --- a/src/k8splugin/internal/app/config.go +++ b/src/k8splugin/internal/app/config.go @@ -42,7 +42,7 @@ type ConfigResult struct { ProfileName string `json:"profile-name"` ConfigName string `json:"config-name"` TemplateName string `json:"template-name"` - ConfigVersion uint `json:"config-verion"` + ConfigVersion uint `json:"config-version"` } //ConfigRollback input @@ -62,6 +62,7 @@ type ConfigTagit struct { type ConfigManager interface { Create(instanceID string, p Config) (ConfigResult, error) Get(instanceID, configName string) (Config, error) + List(instanceID string) ([]Config, error) Help() map[string]string Update(instanceID, configName string, p Config) (ConfigResult, error) Delete(instanceID, configName string) (ConfigResult, error) @@ -225,6 +226,24 @@ func (v *ConfigClient) Get(instanceID, configName string) (Config, error) { return cfg, nil } +// List config entry in the database +func (v *ConfigClient) List(instanceID string) ([]Config, error) { + + // Acquire per profile Mutex + lock, _ := getProfileData(instanceID) + lock.Lock() + defer lock.Unlock() + // Read Config DB + cs := ConfigStore{ + instanceID: instanceID, + } + cfg, err := cs.getConfigList() + if err != nil { + return []Config{}, pkgerrors.Wrap(err, "Get Config DB Entry") + } + return cfg, nil +} + // Delete the Config from database func (v *ConfigClient) Delete(instanceID, configName string) (ConfigResult, error) { diff --git a/src/k8splugin/internal/app/config_backend.go b/src/k8splugin/internal/app/config_backend.go index 8187960f..30a480df 100644 --- a/src/k8splugin/internal/app/config_backend.go +++ b/src/k8splugin/internal/app/config_backend.go @@ -170,6 +170,33 @@ func (c ConfigStore) getConfig() (Config, error) { return Config{}, pkgerrors.Wrap(err, "Get Config DB Entry") } +// Read the config entry in the database +func (c ConfigStore) getConfigList() ([]Config, error) { + rbName, rbVersion, profileName, _, err := resolveModelFromInstance(c.instanceID) + if err != nil { + return []Config{}, pkgerrors.Wrap(err, "Retrieving model info") + } + cfgKey := constructKey(rbName, rbVersion, profileName, c.instanceID, tagConfig) + values, err := db.Etcd.GetAll(cfgKey) + if err != nil { + return []Config{}, pkgerrors.Wrap(err, "Get Config DB List") + } + //value is a byte array + if values != nil { + result := make([]Config, 0) + for _, value := range values { + cfg := Config{} + err = db.DeSerialize(string(value), &cfg) + if err != nil { + return []Config{}, pkgerrors.Wrap(err, "Unmarshaling Config Value") + } + result = append(result, cfg) + } + return result, nil + } + return []Config{}, pkgerrors.Wrap(err, "Get Config DB List") +} + // Delete the config entry in the database func (c ConfigStore) deleteConfig() (Config, error) { diff --git a/src/k8splugin/internal/app/config_test.go b/src/k8splugin/internal/app/config_test.go index f20ef055..9ee96881 100644 --- a/src/k8splugin/internal/app/config_test.go +++ b/src/k8splugin/internal/app/config_test.go @@ -105,7 +105,7 @@ func TestCreateConfig(t *testing.T) { } } else { if reflect.DeepEqual(testCase.expected, got) == false { - t.Errorf("Create Resource Bundle returned unexpected body: got %v;"+ + t.Errorf("Create returned unexpected body: got %v;"+ " expected %v", got, testCase.expected) } } @@ -218,10 +218,38 @@ func TestRollbackConfig(t *testing.T) { } } else { if reflect.DeepEqual(testCase.expected1, got) == false { - t.Errorf("Create Resource Bundle returned unexpected body: got %v;"+ + t.Errorf("Create returned unexpected body: got %v;"+ " expected %v", got, testCase.expected1) } } + get, err := impl.Get(testCase.instanceID, testCase.inp.ConfigName) + if err != nil { + if testCase.expectedError == "" { + t.Fatalf("Get returned an unexpected error %s", err) + } + if strings.Contains(err.Error(), testCase.expectedError) == false { + t.Fatalf("Get returned an unexpected error %s", err) + } + } else { + if reflect.DeepEqual(testCase.inp, get) == false { + t.Errorf("Get returned unexpected body: got %v;"+ + " expected %v", get, testCase.inp) + } + } + getList, err := impl.List(testCase.instanceID) + if err != nil { + if testCase.expectedError == "" { + t.Fatalf("List returned an unexpected error %s", err) + } + if strings.Contains(err.Error(), testCase.expectedError) == false { + t.Fatalf("List returned an unexpected error %s", err) + } + } else { + if reflect.DeepEqual([]Config{testCase.inp}, getList) == false { + t.Errorf("List returned unexpected body: got %v;"+ + " expected %v", getList, []Config{testCase.inp}) + } + } got, err = impl.Update(testCase.instanceID, testCase.inp.ConfigName, testCase.inpUpdate1) if err != nil { if testCase.expectedError == "" { @@ -232,7 +260,7 @@ func TestRollbackConfig(t *testing.T) { } } else { if reflect.DeepEqual(testCase.expected2, got) == false { - t.Errorf("Create Resource Bundle returned unexpected body: got %v;"+ + t.Errorf("Create returned unexpected body: got %v;"+ " expected %v", got, testCase.expected2) } } @@ -246,7 +274,7 @@ func TestRollbackConfig(t *testing.T) { } } else { if reflect.DeepEqual(testCase.expected3, got) == false { - t.Errorf("Create Resource Bundle returned unexpected body: got %v;"+ + t.Errorf("Create returned unexpected body: got %v;"+ " expected %v", got, testCase.expected3) } } @@ -260,7 +288,7 @@ func TestRollbackConfig(t *testing.T) { } } else { if reflect.DeepEqual(testCase.expected4, got) == false { - t.Errorf("Create Resource Bundle returned unexpected body: got %v;"+ + t.Errorf("Create returned unexpected body: got %v;"+ " expected %v", got, testCase.expected4) } } diff --git a/src/k8splugin/internal/db/etcd.go b/src/k8splugin/internal/db/etcd.go index 97771a07..a435b435 100644 --- a/src/k8splugin/internal/db/etcd.go +++ b/src/k8splugin/internal/db/etcd.go @@ -36,6 +36,7 @@ type EtcdConfig struct { // EtcdStore Interface needed for mocking type EtcdStore interface { Get(key string) ([]byte, error) + GetAll(key string) ([][]byte, error) Put(key, value string) error Delete(key string) error } @@ -114,7 +115,7 @@ func (e EtcdClient) Get(key string) ([]byte, error) { } getResp, err := e.cli.Get(context.Background(), key) if err != nil { - return nil, pkgerrors.Errorf("Error getitng etcd entry: %s", err.Error()) + return nil, pkgerrors.Errorf("Error getting etcd entry: %s", err.Error()) } if getResp.Count == 0 { return nil, pkgerrors.Errorf("Key doesn't exist") @@ -122,6 +123,22 @@ func (e EtcdClient) Get(key string) ([]byte, error) { return getResp.Kvs[0].Value, nil } +// GetAll sub values from Etcd DB +func (e EtcdClient) GetAll(key string) ([][]byte, error) { + if e.cli == nil { + return nil, pkgerrors.Errorf("Etcd Client not initialized") + } + getResp, err := e.cli.Get(context.Background(), key, clientv3.WithPrefix()) + if err != nil { + return nil, pkgerrors.Errorf("Error getting etcd entry: %s", err.Error()) + } + result := make([][]byte, 0) + for _, v := range getResp.Kvs { + result = append(result, v.Value) + } + return result, nil +} + // Delete values from Etcd DB func (e EtcdClient) Delete(key string) error { diff --git a/src/k8splugin/internal/db/etcd_testing.go b/src/k8splugin/internal/db/etcd_testing.go index 12b17e33..9dfcad82 100644 --- a/src/k8splugin/internal/db/etcd_testing.go +++ b/src/k8splugin/internal/db/etcd_testing.go @@ -14,6 +14,8 @@ limitations under the License. package db import ( + "strings" + pkgerrors "github.com/pkg/errors" ) @@ -39,6 +41,16 @@ func (c *MockEtcdClient) Get(key string) ([]byte, error) { return nil, pkgerrors.Errorf("Key doesn't exist") } +func (c *MockEtcdClient) GetAll(key string) ([][]byte, error) { + result := make([][]byte, 0) + for kvKey, kvValue := range c.Items { + if strings.HasPrefix(kvKey, key) { + result = append(result, []byte(kvValue)) + } + } + return result, nil +} + func (c *MockEtcdClient) Delete(key string) error { delete(c.Items, key) return c.Err -- cgit 1.2.3-korg