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 ns := cm.GetNamespace("")
69 for _, name := range cm.GetNamesFromHelmRepo() {
75 Metadata: ConfigMetadata{Name: name, Namespace: ns, ConfigName: name + "-appconfig"},
78 err := cm.ReadSchema(name, &c)
83 err = cm.ReadConfigMap(c.Metadata.ConfigName, ns, &c.Configuration)
85 log.Println("No active configMap found, using default!")
93 func (cm *ConfigMap) ReadSchema(name string, c *XAppConfig) (err error) {
94 if err = cm.FetchChart(name); err != nil {
98 tarDir := viper.GetString("xapp.tarDir")
99 err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.schema")), &c.Descriptor)
104 err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.config")), &c.Configuration)
109 if err = os.RemoveAll(path.Join(tarDir, name)); err != nil {
110 log.Println("RemoveAll failed", err)
116 func (cm *ConfigMap) ReadConfigMap(ConfigName string, ns string, c *interface{}) (err error) {
117 args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s", ns, ConfigName)
118 configMapJson, err := KubectlExec(args)
123 err = json.Unmarshal([]byte(configMapJson), &c)
131 func (cm *ConfigMap) ApplyConfigMap(r XAppConfig, action string) (err error) {
135 Metadata: CMMetadata{Name: r.Metadata.Name, Namespace: r.Metadata.Namespace},
136 Data: r.Configuration,
139 cmJson, err := json.Marshal(c.Data)
141 log.Println("Config marshalling failed: ", err)
145 cmFile := viper.GetString("xapp.tmpConfig")
146 err = ioutil.WriteFile(cmFile, cmJson, 0644)
148 log.Println("WriteFile failed: ", err)
152 cmd := " create configmap -n %s %s --from-file=%s -o json --dry-run | kubectl %s -f -"
153 args := fmt.Sprintf(cmd, r.Metadata.Namespace, r.Metadata.ConfigName, cmFile, action)
154 _, err = KubectlExec(args)
158 log.Println("Configmap changes done!")
163 func (cm *ConfigMap) GetConfigMap(m XappDeploy, c *interface{}) (err error) {
164 if m.ConfigName == "" {
165 m.ConfigName = m.Name + "-appconfig"
167 return cm.ReadConfigMap(m.ConfigName, m.Namespace, c)
170 func (cm *ConfigMap) CreateConfigMap(r XAppConfig) (errList []CMError, err error) {
171 if errList, err = cm.Validate(r); err != nil {
174 err = cm.ApplyConfigMap(r, "create")
178 func (cm *ConfigMap) UpdateConfigMap(r XAppConfig) (errList []CMError, err error) {
179 if errList, err = cm.Validate(r); err != nil {
183 // Re-create the configmap with the new parameters
184 err = cm.ApplyConfigMap(r, "apply")
188 func (cm *ConfigMap) DeleteConfigMap(r XAppConfig) (c interface{}, err error) {
189 err = cm.ReadConfigMap(r.Metadata.ConfigName, r.Metadata.Namespace, &c)
191 args := fmt.Sprintf(" delete configmap --namespace=%s %s", r.Metadata.Namespace, r.Metadata.ConfigName)
192 _, err = KubectlExec(args)
197 func (cm *ConfigMap) PurgeConfigMap(m XappDeploy) (c interface{}, err error) {
198 if m.ConfigName == "" {
199 m.ConfigName = m.Name + "-appconfig"
201 md := ConfigMetadata{Name: m.Name, Namespace: m.Namespace, ConfigName: m.ConfigName}
203 return cm.DeleteConfigMap(XAppConfig{Metadata: md})
206 func (cm *ConfigMap) RestoreConfigMap(m XappDeploy, c interface{}) (err error) {
207 if m.ConfigName == "" {
208 m.ConfigName = m.Name + "-appconfig"
210 md := ConfigMetadata{Name: m.Name, Namespace: m.Namespace, ConfigName: m.ConfigName}
211 time.Sleep(time.Duration(10 * time.Second))
213 return cm.ApplyConfigMap(XAppConfig{Metadata: md, Configuration: c}, "create")
216 func (cm *ConfigMap) GetNamesFromHelmRepo() (names []string) {
217 rname := viper.GetString("helm.repo-name")
219 cmdArgs := strings.Join([]string{"search ", rname}, "")
220 out, err := HelmExec(cmdArgs)
225 re := regexp.MustCompile(rname + `/.*`)
226 result := re.FindAllStringSubmatch(string(out), -1)
229 for _, v := range result {
230 fmt.Sscanf(v[0], "%s", &tmp)
231 names = append(names, strings.Split(tmp, "/")[1])
237 func (cm *ConfigMap) Validate(req XAppConfig) (errList []CMError, err error) {
239 err = cm.ReadSchema(req.Metadata.Name, &c)
241 log.Printf("No schema file found for '%s', aborting ...", req.Metadata.Name)
244 return cm.doValidate(c.Descriptor, req.Configuration)
247 func (cm *ConfigMap) doValidate(schema, cfg interface{}) (errList []CMError, err error) {
248 schemaLoader := gojsonschema.NewGoLoader(schema)
249 documentLoader := gojsonschema.NewGoLoader(cfg)
251 result, err := gojsonschema.Validate(schemaLoader, documentLoader)
253 log.Println("Validation failed: ", err)
257 if result.Valid() == false {
258 log.Println("The document is not valid, Errors: ", result.Errors())
259 for _, desc := range result.Errors() {
260 errList = append(errList, CMError{Field: desc.Field(), Description: desc.Description()})
262 return errList, errors.New("Validation failed!")
267 func (cm *ConfigMap) ReadFile(name string, data interface{}) (err error) {
268 f, err := ioutil.ReadFile(name)
270 log.Printf("Reading '%s' file failed: %v", name, err)
274 err = json.Unmarshal(f, &data)
276 log.Printf("Unmarshalling '%s' file failed: %v", name, err)
283 func (cm *ConfigMap) FetchChart(name string) (err error) {
284 tarDir := viper.GetString("xapp.tarDir")
285 repo := viper.GetString("helm.repo-name")
286 fetchArgs := fmt.Sprintf("--untar --untardir %s %s/%s", tarDir, repo, name)
288 _, err = HelmExec(strings.Join([]string{"fetch ", fetchArgs}, ""))
292 func (cm *ConfigMap) GetMessages(name string) (msgs MessageTypes) {
293 log.Println("Fetching tx/rx messages for: ", name)
295 ns := cm.GetNamespace("")
296 args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s-appconfig", ns, name)
297 out, err := KubectlExec(args)
302 var p fastjson.Parser
303 v, err := p.Parse(string(out))
305 log.Printf("fastjson.Parser for '%s' failed: %v", name, err)
309 for _, m := range v.GetArray("rmr", "txMessages") {
310 msgs.TxMessages = append(msgs.TxMessages, strings.Trim(m.String(), `"`))
312 for _, m := range v.GetArray("rmr", "rxMessages") {
313 msgs.RxMessages = append(msgs.RxMessages, strings.Trim(m.String(), `"`))
319 func (cm *ConfigMap) GetNamespace(ns string) string {
324 ns = viper.GetString("xapp.namespace")