Support for XApp configuration update
[ric-plt/appmgr.git] / cmd / appmgr / desc.go
index c3a27a3..2f55460 100755 (executable)
@@ -58,8 +58,13 @@ type CMMetadata struct {
        Namespace string `json:"namespace"`
 }
 
-func UploadConfig() (cfg []XAppConfig) {
-       for _, name := range GetNamesFromHelmRepo() {
+type CMError struct {
+       Field       string `json:"field"`
+       Description string `json:"description"`
+}
+
+func (cm *ConfigMap) UploadConfig() (cfg []XAppConfig) {
+       for _, name := range cm.GetNamesFromHelmRepo() {
                if name == "appmgr" {
                        continue
                }
@@ -68,12 +73,12 @@ func UploadConfig() (cfg []XAppConfig) {
                        Metadata: ConfigMetadata{Name: name, Namespace: "ricxapp", ConfigName: name + "-appconfig"},
                }
 
-               err := ReadSchema(name, &c)
+               err := cm.ReadSchema(name, &c)
                if err != nil {
                        continue
                }
 
-               err = ReadConfigMap(name, "ricxapp", &c.Configuration)
+               err = cm.ReadConfigMap(c.Metadata.ConfigName, "ricxapp", &c.Configuration)
                if err != nil {
                        log.Println("No active configMap found, using default!")
                }
@@ -83,18 +88,18 @@ func UploadConfig() (cfg []XAppConfig) {
        return
 }
 
-func ReadSchema(name string, c *XAppConfig) (err error) {
-       if err = FetchChart(name); err != nil {
+func (cm *ConfigMap) ReadSchema(name string, c *XAppConfig) (err error) {
+       if err = cm.FetchChart(name); err != nil {
                return
        }
 
        tarDir := viper.GetString("xapp.tarDir")
-       err = ReadFile(path.Join(tarDir, name, viper.GetString("xapp.schema")), &c.Descriptor)
+       err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.schema")), &c.Descriptor)
        if err != nil {
                return
        }
 
-       err = ReadFile(path.Join(tarDir, name, viper.GetString("xapp.config")), &c.Configuration)
+       err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.config")), &c.Configuration)
        if err != nil {
                return
        }
@@ -106,8 +111,8 @@ func ReadSchema(name string, c *XAppConfig) (err error) {
        return
 }
 
-func ReadConfigMap(name string, ns string, c *interface{}) (err error) {
-       args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s-appconfig", ns, name)
+func (cm *ConfigMap) ReadConfigMap(ConfigName string, ns string, c *interface{}) (err error) {
+       args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s", ns, ConfigName)
        configMapJson, err := KubectlExec(args)
        if err != nil {
                return
@@ -121,15 +126,15 @@ func ReadConfigMap(name string, ns string, c *interface{}) (err error) {
        return
 }
 
-func ApplyConfigMap(r XAppConfig) (err error) {
-       cm := ConfigMap{
+func (cm *ConfigMap) ApplyConfigMap(r XAppConfig, action string) (err error) {
+       c := ConfigMap{
                Kind:       "ConfigMap",
                ApiVersion: "v1",
                Metadata:   CMMetadata{Name: r.Metadata.Name, Namespace: r.Metadata.Namespace},
                Data:       r.Configuration,
        }
 
-       cmJson, err := json.Marshal(cm)
+       cmJson, err := json.Marshal(c)
        if err != nil {
                log.Println("Config marshalling failed: ", err)
                return
@@ -142,26 +147,37 @@ func ApplyConfigMap(r XAppConfig) (err error) {
                return
        }
 
-       cmd := " create configmap -n %s %s --from-file=%s -o json --dry-run | kubectl apply -f -"
-       args := fmt.Sprintf(cmd, r.Metadata.Namespace, r.Metadata.ConfigName, cmFile)
+       cmd := " create configmap -n %s %s --from-file=%s -o json --dry-run | kubectl %s -f -"
+       args := fmt.Sprintf(cmd, r.Metadata.Namespace, r.Metadata.ConfigName, cmFile, action)
        _, err = KubectlExec(args)
        if err != nil {
                return
        }
-       log.Println("Configmap changes created!")
+       log.Println("Configmap changes done!")
+
+       return
+}
 
+func (cm *ConfigMap) CreateConfigMap(r XAppConfig) (errList []CMError, err error) {
+       if errList, err = cm.Validate(r); err != nil {
+               return
+       }
+       err = cm.ApplyConfigMap(r, "create")
        return
 }
 
-func CreateConfigMap(r XAppConfig) (err error) {
-       if err = Validate(r); err != nil {
+func (cm *ConfigMap) UpdateConfigMap(r XAppConfig) (errList []CMError, err error) {
+       if errList, err = cm.Validate(r); err != nil {
                return
        }
-       return ApplyConfigMap(r)
+
+       // Re-create the configmap with the new parameters
+       err = cm.ApplyConfigMap(r, "apply")
+       return
 }
 
-func DeleteConfigMap(r XAppConfig) (cm interface{}, err error) {
-       err = ReadConfigMap(r.Metadata.Name, r.Metadata.Namespace, &cm)
+func (cm *ConfigMap) DeleteConfigMap(r XAppConfig) (c interface{}, err error) {
+       err = cm.ReadConfigMap(r.Metadata.ConfigName, r.Metadata.Namespace, &c)
        if err == nil {
                args := fmt.Sprintf(" delete configmap --namespace=%s %s", r.Metadata.Namespace, r.Metadata.ConfigName)
                _, err = KubectlExec(args)
@@ -169,23 +185,26 @@ func DeleteConfigMap(r XAppConfig) (cm interface{}, err error) {
        return
 }
 
-func PurgeConfigMap(m ConfigMetadata) (cm interface{}, err error) {
+func (cm *ConfigMap) PurgeConfigMap(m XappDeploy) (c interface{}, err error) {
        if m.ConfigName == "" {
                m.ConfigName = m.Name + "-appconfig"
        }
-       return DeleteConfigMap(XAppConfig{Metadata: m})
+       md := ConfigMetadata{Name: m.Name, Namespace: m.Namespace, ConfigName: m.ConfigName}
+
+       return cm.DeleteConfigMap(XAppConfig{Metadata: md})
 }
 
-func RestoreConfigMap(m ConfigMetadata, cm interface{}) (err error) {
+func (cm *ConfigMap) RestoreConfigMap(m XappDeploy, c interface{}) (err error) {
        if m.ConfigName == "" {
                m.ConfigName = m.Name + "-appconfig"
        }
+       md := ConfigMetadata{Name: m.Name, Namespace: m.Namespace, ConfigName: m.ConfigName}
        time.Sleep(time.Duration(10 * time.Second))
 
-       return ApplyConfigMap(XAppConfig{Metadata: m, Configuration: cm})
+       return cm.ApplyConfigMap(XAppConfig{Metadata: md, Configuration: c}, "create")
 }
 
-func GetNamesFromHelmRepo() (names []string) {
+func (cm *ConfigMap) GetNamesFromHelmRepo() (names []string) {
        rname := viper.GetString("helm.repo-name")
 
        cmdArgs := strings.Join([]string{"search ", rname}, "")
@@ -206,37 +225,37 @@ func GetNamesFromHelmRepo() (names []string) {
        return names
 }
 
-func Validate(req XAppConfig) (err error) {
+func (cm *ConfigMap) Validate(req XAppConfig) (errList []CMError, err error) {
        c := XAppConfig{}
-       err = ReadSchema(req.Metadata.Name, &c)
+       err = cm.ReadSchema(req.Metadata.Name, &c)
        if err != nil {
                log.Printf("No schema file found for '%s', aborting ...", req.Metadata.Name)
-               return err
+               return
        }
+       return cm.doValidate(c.Descriptor, req.Configuration)
+}
 
-       schemaLoader := gojsonschema.NewGoLoader(c.Descriptor)
-       documentLoader := gojsonschema.NewGoLoader(req.Configuration)
+func (cm *ConfigMap) doValidate(schema, cfg interface{}) (errList []CMError, err error) {
+       schemaLoader := gojsonschema.NewGoLoader(schema)
+       documentLoader := gojsonschema.NewGoLoader(cfg)
 
-       log.Println("Starting validation ...")
        result, err := gojsonschema.Validate(schemaLoader, documentLoader)
        if err != nil {
                log.Println("Validation failed: ", err)
                return
        }
 
-       log.Println("validation done ...", err, result.Valid())
        if result.Valid() == false {
                log.Println("The document is not valid, Errors: ", result.Errors())
-               s := make([]string, 3)
-               for i, desc := range result.Errors() {
-                       s = append(s, fmt.Sprintf(" (%d): %s.\n", i, desc.String()))
+               for _, desc := range result.Errors() {
+                       errList = append(errList, CMError{Field: desc.Field(), Description: desc.Description()})
                }
-               return errors.New(strings.Join(s, " "))
+               return errList, errors.New("Validation failed!")
        }
        return
 }
 
-func ReadFile(name string, data interface{}) (err error) {
+func (cm *ConfigMap) ReadFile(name string, data interface{}) (err error) {
        f, err := ioutil.ReadFile(name)
        if err != nil {
                log.Printf("Reading '%s' file failed: %v", name, err)
@@ -252,7 +271,7 @@ func ReadFile(name string, data interface{}) (err error) {
        return
 }
 
-func FetchChart(name string) (err error) {
+func (cm *ConfigMap) FetchChart(name string) (err error) {
        tarDir := viper.GetString("xapp.tarDir")
        repo := viper.GetString("helm.repo-name")
        fetchArgs := fmt.Sprintf("--untar --untardir %s %s/%s", tarDir, repo, name)
@@ -261,7 +280,7 @@ func FetchChart(name string) (err error) {
        return
 }
 
-func GetMessages(name string) (msgs MessageTypes, err error) {
+func (cm *ConfigMap) GetMessages(name string) (msgs MessageTypes) {
        log.Println("Fetching tx/rx messages for: ", name)
        return
 }