+/*
+==================================================================================
+ Copyright (c) 2019 AT&T Intellectual Property.
+ Copyright (c) 2019 Nokia
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================================
+*/
+
+package main
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "github.com/spf13/viper"
+ "github.com/xeipuuv/gojsonschema"
+ "io/ioutil"
+ "log"
+ "os"
+ "path"
+ "regexp"
+ "strings"
+ "time"
+)
+
+type ConfigMetadata struct {
+ Name string `json:"name"`
+ ConfigName string `json:"configName, omitempty"`
+ Namespace string `json:"namespace, omitempty"`
+}
+
+type XAppConfig struct {
+ Metadata ConfigMetadata `json:"metadata"`
+ Descriptor interface{} `json:"descriptor, omitempty"`
+ Configuration interface{} `json:"config, omitempty"`
+}
+
+type ConfigMap struct {
+ Kind string `json:"kind"`
+ ApiVersion string `json:"apiVersion"`
+ Data interface{} `json:"data"`
+ Metadata CMMetadata `json:"metadata"`
+}
+
+type CMMetadata struct {
+ Name string `json:"name"`
+ Namespace string `json:"namespace"`
+}
+
+func UploadConfig() (cfg []XAppConfig) {
+ for _, name := range GetNamesFromHelmRepo() {
+ if name == "appmgr" {
+ continue
+ }
+
+ c := XAppConfig{
+ Metadata: ConfigMetadata{Name: name, Namespace: "ricxapp", ConfigName: name + "-appconfig"},
+ }
+
+ err := ReadSchema(name, &c)
+ if err != nil {
+ continue
+ }
+
+ err = ReadConfigMap(name, "ricxapp", &c.Configuration)
+ if err != nil {
+ log.Println("No active configMap found, using default!")
+ }
+
+ cfg = append(cfg, c)
+ }
+ return
+}
+
+func ReadSchema(name string, c *XAppConfig) (err error) {
+ if err = FetchChart(name); err != nil {
+ return
+ }
+
+ tarDir := viper.GetString("xapp.tarDir")
+ err = 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)
+ if err != nil {
+ return
+ }
+
+ if err = os.RemoveAll(path.Join(tarDir, name)); err != nil {
+ log.Println("RemoveAll failed", err)
+ }
+
+ 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)
+ configMapJson, err := KubectlExec(args)
+ if err != nil {
+ return
+ }
+
+ err = json.Unmarshal([]byte(configMapJson), &c)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+func ApplyConfigMap(r XAppConfig) (err error) {
+ cm := ConfigMap{
+ Kind: "ConfigMap",
+ ApiVersion: "v1",
+ Metadata: CMMetadata{Name: r.Metadata.Name, Namespace: r.Metadata.Namespace},
+ Data: r.Configuration,
+ }
+
+ cmJson, err := json.Marshal(cm)
+ if err != nil {
+ log.Println("Config marshalling failed: ", err)
+ return
+ }
+
+ cmFile := viper.GetString("xapp.tmpConfig")
+ err = ioutil.WriteFile(cmFile, cmJson, 0644)
+ if err != nil {
+ log.Println("WriteFile failed: ", err)
+ 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)
+ _, err = KubectlExec(args)
+ if err != nil {
+ return
+ }
+ log.Println("Configmap changes created!")
+
+ return
+}
+
+func CreateConfigMap(r XAppConfig) (err error) {
+ if err = Validate(r); err != nil {
+ return
+ }
+ return ApplyConfigMap(r)
+}
+
+func DeleteConfigMap(r XAppConfig) (cm interface{}, err error) {
+ err = ReadConfigMap(r.Metadata.Name, r.Metadata.Namespace, &cm)
+ if err == nil {
+ args := fmt.Sprintf(" delete configmap --namespace=%s %s", r.Metadata.Namespace, r.Metadata.ConfigName)
+ _, err = KubectlExec(args)
+ }
+ return
+}
+
+func PurgeConfigMap(m ConfigMetadata) (cm interface{}, err error) {
+ if m.ConfigName == "" {
+ m.ConfigName = m.Name + "-appconfig"
+ }
+ return DeleteConfigMap(XAppConfig{Metadata: m})
+}
+
+func RestoreConfigMap(m ConfigMetadata, cm interface{}) (err error) {
+ if m.ConfigName == "" {
+ m.ConfigName = m.Name + "-appconfig"
+ }
+ time.Sleep(time.Duration(10 * time.Second))
+
+ return ApplyConfigMap(XAppConfig{Metadata: m, Configuration: cm})
+}
+
+func GetNamesFromHelmRepo() (names []string) {
+ rname := viper.GetString("helm.repo-name")
+
+ cmdArgs := strings.Join([]string{"search ", rname}, "")
+ out, err := HelmExec(cmdArgs)
+ if err != nil {
+ return
+ }
+
+ re := regexp.MustCompile(rname + `/.*`)
+ result := re.FindAllStringSubmatch(string(out), -1)
+ if result != nil {
+ var tmp string
+ for _, v := range result {
+ fmt.Sscanf(v[0], "%s", &tmp)
+ names = append(names, strings.Split(tmp, "/")[1])
+ }
+ }
+ return names
+}
+
+func Validate(req XAppConfig) (err error) {
+ c := XAppConfig{}
+ err = ReadSchema(req.Metadata.Name, &c)
+ if err != nil {
+ log.Printf("No schema file found for '%s', aborting ...", req.Metadata.Name)
+ return err
+ }
+
+ schemaLoader := gojsonschema.NewGoLoader(c.Descriptor)
+ documentLoader := gojsonschema.NewGoLoader(req.Configuration)
+
+ 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()))
+ }
+ return errors.New(strings.Join(s, " "))
+ }
+ return
+}
+
+func ReadFile(name string, data interface{}) (err error) {
+ f, err := ioutil.ReadFile(name)
+ if err != nil {
+ log.Printf("Reading '%s' file failed: %v", name, err)
+ return
+ }
+
+ err = json.Unmarshal(f, &data)
+ if err != nil {
+ log.Printf("Unmarshalling '%s' file failed: %v", name, err)
+ return
+ }
+
+ return
+}
+
+func 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)
+
+ _, err = HelmExec(strings.Join([]string{"fetch ", fetchArgs}, ""))
+ return
+}
+
+func GetMessages(name string) (msgs MessageTypes, err error) {
+ log.Println("Fetching tx/rx messages for: ", name)
+ return
+}