2 ==================================================================================
3 Copyright (c) 2019 AT&T Intellectual Property.
4 Copyright (c) 2019 Nokia
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 ==================================================================================
26 "github.com/spf13/viper"
27 "github.com/valyala/fastjson"
28 "github.com/xeipuuv/gojsonschema"
38 type ConfigMetadata struct {
39 Name string `json:"name"`
40 ConfigName string `json:"configName, omitempty"`
41 Namespace string `json:"namespace, omitempty"`
44 type XAppConfig struct {
45 Metadata ConfigMetadata `json:"metadata"`
46 Descriptor interface{} `json:"descriptor, omitempty"`
47 Configuration interface{} `json:"config, omitempty"`
50 type ConfigMap struct {
51 Kind string `json:"kind"`
52 ApiVersion string `json:"apiVersion"`
53 Data interface{} `json:"data"`
54 Metadata CMMetadata `json:"metadata"`
57 type CMMetadata struct {
58 Name string `json:"name"`
59 Namespace string `json:"namespace"`
63 Field string `json:"field"`
64 Description string `json:"description"`
67 func (cm *ConfigMap) UploadConfig() (cfg []XAppConfig) {
68 for _, name := range cm.GetNamesFromHelmRepo() {
74 Metadata: ConfigMetadata{Name: name, Namespace: "ricxapp", ConfigName: name + "-appconfig"},
77 err := cm.ReadSchema(name, &c)
82 err = cm.ReadConfigMap(c.Metadata.ConfigName, "ricxapp", &c.Configuration)
84 log.Println("No active configMap found, using default!")
92 func (cm *ConfigMap) ReadSchema(name string, c *XAppConfig) (err error) {
93 if err = cm.FetchChart(name); err != nil {
97 tarDir := viper.GetString("xapp.tarDir")
98 err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.schema")), &c.Descriptor)
103 err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.config")), &c.Configuration)
108 if err = os.RemoveAll(path.Join(tarDir, name)); err != nil {
109 log.Println("RemoveAll failed", err)
115 func (cm *ConfigMap) ReadConfigMap(ConfigName string, ns string, c *interface{}) (err error) {
116 args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s", ns, ConfigName)
117 configMapJson, err := KubectlExec(args)
122 err = json.Unmarshal([]byte(configMapJson), &c)
130 func (cm *ConfigMap) ApplyConfigMap(r XAppConfig, action string) (err error) {
134 Metadata: CMMetadata{Name: r.Metadata.Name, Namespace: r.Metadata.Namespace},
135 Data: r.Configuration,
138 cmJson, err := json.Marshal(c.Data)
140 log.Println("Config marshalling failed: ", err)
144 cmFile := viper.GetString("xapp.tmpConfig")
145 err = ioutil.WriteFile(cmFile, cmJson, 0644)
147 log.Println("WriteFile failed: ", err)
151 cmd := " create configmap -n %s %s --from-file=%s -o json --dry-run | kubectl %s -f -"
152 args := fmt.Sprintf(cmd, r.Metadata.Namespace, r.Metadata.ConfigName, cmFile, action)
153 _, err = KubectlExec(args)
157 log.Println("Configmap changes done!")
162 func (cm *ConfigMap) GetConfigMap(m XappDeploy, c *interface{}) (err error) {
163 if m.ConfigName == "" {
164 m.ConfigName = m.Name + "-appconfig"
166 return cm.ReadConfigMap(m.ConfigName, m.Namespace, c)
169 func (cm *ConfigMap) CreateConfigMap(r XAppConfig) (errList []CMError, err error) {
170 if errList, err = cm.Validate(r); err != nil {
173 err = cm.ApplyConfigMap(r, "create")
177 func (cm *ConfigMap) UpdateConfigMap(r XAppConfig) (errList []CMError, err error) {
178 if errList, err = cm.Validate(r); err != nil {
182 // Re-create the configmap with the new parameters
183 err = cm.ApplyConfigMap(r, "apply")
187 func (cm *ConfigMap) DeleteConfigMap(r XAppConfig) (c interface{}, err error) {
188 err = cm.ReadConfigMap(r.Metadata.ConfigName, r.Metadata.Namespace, &c)
190 args := fmt.Sprintf(" delete configmap --namespace=%s %s", r.Metadata.Namespace, r.Metadata.ConfigName)
191 _, err = KubectlExec(args)
196 func (cm *ConfigMap) PurgeConfigMap(m XappDeploy) (c interface{}, err error) {
197 if m.ConfigName == "" {
198 m.ConfigName = m.Name + "-appconfig"
200 md := ConfigMetadata{Name: m.Name, Namespace: m.Namespace, ConfigName: m.ConfigName}
202 return cm.DeleteConfigMap(XAppConfig{Metadata: md})
205 func (cm *ConfigMap) RestoreConfigMap(m XappDeploy, c interface{}) (err error) {
206 if m.ConfigName == "" {
207 m.ConfigName = m.Name + "-appconfig"
209 md := ConfigMetadata{Name: m.Name, Namespace: m.Namespace, ConfigName: m.ConfigName}
210 time.Sleep(time.Duration(10 * time.Second))
212 return cm.ApplyConfigMap(XAppConfig{Metadata: md, Configuration: c}, "create")
215 func (cm *ConfigMap) GetNamesFromHelmRepo() (names []string) {
216 rname := viper.GetString("helm.repo-name")
218 cmdArgs := strings.Join([]string{"search ", rname}, "")
219 out, err := HelmExec(cmdArgs)
224 re := regexp.MustCompile(rname + `/.*`)
225 result := re.FindAllStringSubmatch(string(out), -1)
228 for _, v := range result {
229 fmt.Sscanf(v[0], "%s", &tmp)
230 names = append(names, strings.Split(tmp, "/")[1])
236 func (cm *ConfigMap) Validate(req XAppConfig) (errList []CMError, err error) {
238 err = cm.ReadSchema(req.Metadata.Name, &c)
240 log.Printf("No schema file found for '%s', aborting ...", req.Metadata.Name)
243 return cm.doValidate(c.Descriptor, req.Configuration)
246 func (cm *ConfigMap) doValidate(schema, cfg interface{}) (errList []CMError, err error) {
247 schemaLoader := gojsonschema.NewGoLoader(schema)
248 documentLoader := gojsonschema.NewGoLoader(cfg)
250 result, err := gojsonschema.Validate(schemaLoader, documentLoader)
252 log.Println("Validation failed: ", err)
256 if result.Valid() == false {
257 log.Println("The document is not valid, Errors: ", result.Errors())
258 for _, desc := range result.Errors() {
259 errList = append(errList, CMError{Field: desc.Field(), Description: desc.Description()})
261 return errList, errors.New("Validation failed!")
266 func (cm *ConfigMap) ReadFile(name string, data interface{}) (err error) {
267 f, err := ioutil.ReadFile(name)
269 log.Printf("Reading '%s' file failed: %v", name, err)
273 err = json.Unmarshal(f, &data)
275 log.Printf("Unmarshalling '%s' file failed: %v", name, err)
282 func (cm *ConfigMap) FetchChart(name string) (err error) {
283 tarDir := viper.GetString("xapp.tarDir")
284 repo := viper.GetString("helm.repo-name")
285 fetchArgs := fmt.Sprintf("--untar --untardir %s %s/%s", tarDir, repo, name)
287 _, err = HelmExec(strings.Join([]string{"fetch ", fetchArgs}, ""))
291 func (cm *ConfigMap) GetMessages(name string) (msgs MessageTypes) {
292 log.Println("Fetching tx/rx messages for: ", name)
294 args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n ricxapp %s-appconfig", name)
295 out, err := KubectlExec(args)
300 var p fastjson.Parser
301 v, err := p.Parse(string(out))
303 log.Printf("fastjson.Parser for '%s' failed: %v", name, err)
307 for _, m := range v.GetArray("rmr", "txMessages") {
308 msgs.TxMessages = append(msgs.TxMessages, strings.Trim(m.String(), `"`))
310 for _, m := range v.GetArray("rmr", "rxMessages") {
311 msgs.RxMessages = append(msgs.RxMessages, strings.Trim(m.String(), `"`))