Config List handler added to Config API 44/123044/2
authorLukasz Rajewski <lukasz.rajewski@orange.com>
Mon, 2 Aug 2021 20:15:35 +0000 (22:15 +0200)
committerLukasz Rajewski <lukasz.rajewski@orange.com>
Mon, 2 Aug 2021 20:30:16 +0000 (22:30 +0200)
Config List handler added to Config API

Issue-ID: MULTICLOUD-1332
Signed-off-by: Lukasz Rajewski <lukasz.rajewski@orange.com>
Change-Id: I63355dd6b05e70398cfc89744efa332926286c40

src/k8splugin/api/api.go
src/k8splugin/api/confighandler.go
src/k8splugin/internal/app/config.go
src/k8splugin/internal/app/config_backend.go
src/k8splugin/internal/app/config_test.go
src/k8splugin/internal/db/etcd.go
src/k8splugin/internal/db/etcd_testing.go

index 4a196ae..1c7c5ea 100644 (file)
@@ -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")
index f4bb086..4ce3079 100644 (file)
@@ -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)
index d0f8876..94acadc 100644 (file)
@@ -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) {
 
index 8187960..30a480d 100644 (file)
@@ -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) {
 
index f20ef05..9ee9688 100644 (file)
@@ -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)
                                }
                        }
index 97771a0..a435b43 100644 (file)
@@ -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 {
 
index 12b17e3..9dfcad8 100644 (file)
@@ -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