swagger: '2.0'
info:
description: This is a draft API for RIC appmgr
- version: 0.2.0
+ version: 0.3.3
title: RIC appmgr
license:
name: Apache 2.0
description: Xapp not found
'500':
description: Internal error
- /xapps/{xAppName}/instances/{xAppInstanceName}/start:
- put:
- summary: Start given xapp instance
- tags:
- - xapp
- operationId: startXappInstanceByName
- produces:
- - application/json
- parameters:
- - name: xAppName
- in: path
- description: Name of xApp
- required: true
- type: string
- - name: xAppInstanceName
- in: path
- description: Name of xApp instance to get information
- required: true
- type: string
- responses:
- '200':
- description: successful operation
- '400':
- description: Invalid name supplied
- '404':
- description: Xapp not found
- '500':
- description: Internal error
- /xapps/{xAppName}/instances/{xAppInstanceName}/stop:
- put:
- summary: Stop given xapp instance
- tags:
- - xapp
- operationId: stopXappInstanceByName
- produces:
- - application/json
- parameters:
- - name: xAppName
- in: path
- description: Name of xApp
- required: true
- type: string
- - name: xAppInstanceName
- in: path
- description: Name of xApp instance to get information
- required: true
- type: string
- responses:
- '200':
- description: successful operation
- '400':
- description: Invalid name supplied
- '404':
- description: Xapp not found
- '500':
- description: Internal error
/config:
- post:
- summary: Create xApp config
- tags:
- - xapp
- operationId: createXappConfig
- consumes:
- - application/json
- produces:
- - application/json
- parameters:
- - name: XAppConfig
- in: body
- description: xApp config
- schema:
- $ref: '#/definitions/XAppConfig'
- responses:
- '201':
- description: xApp config successfully created
- schema:
- $ref: '#/definitions/ConfigValidationErrors'
- '400':
- description: Invalid input
- '422':
- description: Validation of configuration failed
- '500':
- description: Internal error
put:
summary: Modify xApp config
tags:
$ref: '#/definitions/AllXappConfig'
'500':
description: Internal error
- delete:
- summary: Delete xApp configuration
- tags:
- - xapp
- operationId: deleteXappConfig
- parameters:
- - name: ConfigMetadata
- in: body
- description: xApp configuration information
- schema:
- $ref: '#/definitions/ConfigMetadata'
- responses:
- '204':
- description: Successful deletion of xApp config
- '400':
- description: Invalid parameters supplied
- '500':
- description: Internal error
- /config/{configName}:
+ /config/{element}:
get:
- summary: Returns the configuration of a single xapp
+ summary: Returns the given element of the configuration
tags:
- xapp
- operationId: getXappConfig
+ operationId: GetConfigElement
produces:
- application/json
parameters:
- - name: configName
+ - name: element
in: path
- description: Name of xApp
+ description: Name of configuration element
required: true
type: string
responses:
'200':
- description: successful query of xApp config
+ description: successful query of config elements
schema:
- $ref: '#/definitions/XAppConfig'
+ $ref: '#/definitions/AllXappConfig'
'500':
description: Internal error
/subscriptions:
ConfigMetadata:
type: object
required:
- - name
+ - xappName
+ - namespace
properties:
- name:
+ xappName:
type: string
description: Name of the xApp
- configName:
- type: string
- description: Name of the config map
namespace:
type: string
description: Name of the namespace
type: object
required:
- metadata
- - descriptor
- config
properties:
metadata:
$ref: '#/definitions/ConfigMetadata'
- descriptor:
- type: object
- description: Schema of configuration in JSON format
config:
type: object
description: Configuration in JSON format
# The Jenkins job uses this string for the tag in the image name
# for example nexus3.o-ran-sc.org:10004/my-image-name:my-tag
---
-tag: '0.3.2'
+tag: '0.3.3'
gerrit.o-ran-sc.org/r/com/golog v0.0.1
gerrit.oran-osc.org/r/ric-plt/sdlgo v0.0.0
github.com/BurntSushi/toml v0.3.1 // indirect
+ github.com/RaveNoX/go-jsonmerge v1.0.0
github.com/fsnotify/fsnotify v1.4.7
github.com/ghodss/yaml v1.0.0
github.com/go-openapi/errors v0.19.2
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
+github.com/RaveNoX/go-jsonmerge v1.0.0 h1:2e0nqnadoGUP8rAvcA0hkQelZreVO5X3BHomT2XMrAk=
+github.com/RaveNoX/go-jsonmerge v1.0.0/go.mod h1:qYM/NA77LhO4h51JJM7Z+xBU3ovqrNIACZe+SkSNVFo=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
func Init() {
loadConfig()
Logger = logger.NewLogger("appmgr")
- Logger.SetMdc("xm", "0.3.0")
+ Logger.SetMdc("xm", "0.3.3")
}
"encoding/json"
"errors"
"fmt"
- "github.com/spf13/viper"
- "github.com/valyala/fastjson"
- "github.com/xeipuuv/gojsonschema"
"io/ioutil"
"os"
"path"
"regexp"
"strings"
"strconv"
- "time"
+ "github.com/spf13/viper"
+ "github.com/valyala/fastjson"
+ "github.com/xeipuuv/gojsonschema"
"gerrit.oran-osc.org/r/ric-plt/appmgr/pkg/appmgr"
"gerrit.oran-osc.org/r/ric-plt/appmgr/pkg/models"
return &CM{}
}
-func (cm *CM) UploadConfig() (cfg models.AllXappConfig) {
- ns := cm.GetNamespace("")
+func (cm *CM) UploadConfigAll() (configList models.AllXappConfig) {
+ return cm.UploadConfigElement("")
+}
+
+func (cm *CM) UploadConfigElement(Element string) (configList models.AllXappConfig) {
+ namespace := cm.GetNamespace("")
for _, name := range cm.GetNamesFromHelmRepo() {
- if name == "appmgr" {
+ var activeConfig interface{}
+ xAppName := name
+ if err := cm.GetConfigmap(xAppName, namespace, &activeConfig); err != nil {
+ appmgr.Logger.Info("No active configMap found for '%s', ignoring ...", xAppName)
continue
}
- c := models.XAppConfig{
- Metadata: &models.ConfigMetadata{Name: &name, Namespace: ns, ConfigName: cm.GetConfigMapName(name, ns)},
- }
-
- err := cm.ReadSchema(name, &c)
- if err != nil {
- continue
+ if Element != "" {
+ m := activeConfig.(map[string]interface{})
+ if m[Element] == nil {
+ appmgr.Logger.Info("xApp '%s' doesn't have requested element '%s' in config", name, Element)
+ continue
+ }
+ activeConfig = m[Element]
}
- err = cm.ReadConfigMap(c.Metadata.ConfigName, ns, &c.Config)
- if err != nil {
- appmgr.Logger.Info("No active configMap found, using default!")
+ c := models.XAppConfig{
+ Metadata: &models.ConfigMetadata{XappName: &xAppName, Namespace: &namespace},
+ Config: activeConfig,
}
-
- cfg = append(cfg, &c)
+ configList = append(configList, &c)
}
return
}
-func (cm *CM) ReadSchema(name string, c *models.XAppConfig) (err error) {
- if err = cm.FetchChart(name); err != nil {
- return
+func (cm *CM) GetConfigmap(name, namespace string, c *interface{}) (err error) {
+ cmJson, err := cm.ReadConfigmap(name, namespace)
+ if err != nil {
+ return err
}
- tarDir := viper.GetString("xapp.tarDir")
- err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.schema")), &c.Descriptor)
- if err != nil {
+ return json.Unmarshal([]byte(cmJson), &c)
+}
+
+func (cm *CM) ReadSchema(name string, desc *interface{}) (err error) {
+ if err = cm.FetchChart(name); err != nil {
return
}
- err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.config")), &c.Config)
+ tarDir := viper.GetString("xapp.tarDir")
+ err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.schema")), desc)
if err != nil {
return
}
return
}
-func (cm *CM) 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 := util.KubectlExec(args)
- if err != nil {
- return
+func (cm *CM) UpdateConfigMap(r models.XAppConfig) (models.ConfigValidationErrors, error) {
+ fmt.Printf("Configmap update: xappName=%s namespace=%s config: %v", *r.Metadata.XappName, *r.Metadata.Namespace, r.Config)
+ if validationErrors, err := cm.Validate(r); err != nil {
+ return validationErrors, err
}
- err = json.Unmarshal([]byte(configMapJson), &c)
+ cmContent, err := cm.BuildConfigMap(r)
if err != nil {
- return
+ return nil, err
}
- return
-}
-
-func (cm *CM) ApplyConfigMap(r models.XAppConfig, action string) (err error) {
- c := appmgr.ConfigMap{
- Kind: "ConfigMap",
- ApiVersion: "v1",
- Metadata: appmgr.CMMetadata{Name: *r.Metadata.Name, Namespace: r.Metadata.Namespace},
- Data: r.Config,
+ if err := cm.GenerateJSONFile(cmContent); err != nil {
+ return nil, err
}
+ err = cm.ReplaceConfigMap(*r.Metadata.XappName, *r.Metadata.Namespace)
- cmJson, err := json.Marshal(c.Data)
- if err != nil {
- appmgr.Logger.Info("Config marshalling failed: %v", err)
- return
- }
+ return nil, err
+}
- cmFile := viper.GetString("xapp.tmpConfig")
- err = ioutil.WriteFile(cmFile, cmJson, 0644)
+func (cm *CM) BuildConfigMap(r models.XAppConfig) (string, error) {
+ configJson, err := json.Marshal(r.Config)
if err != nil {
- appmgr.Logger.Info("WriteFile failed: %v", err)
- return
+ appmgr.Logger.Info("Config marshalling failed: %v", err)
+ return "", err
}
- 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 = util.KubectlExec(args)
+ cmContent, err := cm.ReadConfigmap(*r.Metadata.XappName, *r.Metadata.Namespace)
if err != nil {
- return
- }
- appmgr.Logger.Info("Configmap changes done!")
-
- return
-}
-
-func (cm *CM) GetConfigMap(m models.XappDescriptor, c *interface{}) (err error) {
- return cm.ReadConfigMap(cm.GetConfigMapName(*m.XappName, m.Namespace), m.Namespace, c)
-}
-
-func (cm *CM) CreateConfigMap(r models.XAppConfig) (errList models.ConfigValidationErrors, err error) {
- if errList, err = cm.Validate(r); err != nil {
- return
- }
- err = cm.ApplyConfigMap(r, "create")
- return
-}
-
-func (cm *CM) UpdateConfigMap(r models.XAppConfig) (errList models.ConfigValidationErrors, err error) {
- if errList, err = cm.Validate(r); err != nil {
- return
+ return "", err
}
- // Re-create the configmap with the new parameters
- err = cm.ApplyConfigMap(r, "apply")
- return
-}
-
-func (cm *CM) DeleteConfigMap(r models.ConfigMetadata) (c interface{}, err error) {
- err = cm.ReadConfigMap(r.ConfigName, r.Namespace, &c)
+ v, err := cm.ParseJson(cmContent)
if err == nil {
- args := fmt.Sprintf(" delete configmap --namespace=%s %s", r.Namespace, r.ConfigName)
- _, err = util.KubectlExec(args)
+ v.Set("controls", fastjson.MustParse(string(configJson)))
+ fmt.Println(v.String())
+ return v.String(), nil
}
- return
-}
-
-func (cm *CM) PurgeConfigMap(m models.XappDescriptor) (c interface{}, err error) {
- md := models.ConfigMetadata{Name: m.XappName, Namespace: m.Namespace, ConfigName: cm.GetConfigMapName(*m.XappName, m.Namespace)}
- return cm.DeleteConfigMap(md)
+ return "", err
}
-func (cm *CM) RestoreConfigMap(m models.XappDescriptor, c interface{}) (err error) {
- md := &models.ConfigMetadata{Name: m.XappName, Namespace: m.Namespace, ConfigName: cm.GetConfigMapName(*m.XappName, m.Namespace)}
- time.Sleep(time.Duration(10 * time.Second))
-
- return cm.ApplyConfigMap(models.XAppConfig{Metadata: md, Config: c}, "create")
-}
-
-func (cm *CM) GetNamesFromHelmRepo() (names []string) {
- rname := viper.GetString("helm.repo-name")
-
- cmdArgs := strings.Join([]string{"search ", rname}, "")
- out, err := util.HelmExec(cmdArgs)
+func (cm *CM) ParseJson(dsContent string) (*fastjson.Value, error) {
+ var p fastjson.Parser
+ v, err := p.Parse(dsContent)
if err != nil {
- return
+ appmgr.Logger.Info("fastjson.Parser failed: %v", err)
}
-
- 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
+ return v, err
}
-func (cm *CM) Validate(req models.XAppConfig) (errList models.ConfigValidationErrors, err error) {
- c := models.XAppConfig{}
- err = cm.ReadSchema(*req.Metadata.Name, &c)
+
+func (cm *CM) GenerateJSONFile(jsonString string) error {
+ cmJson, err := json.RawMessage(jsonString).MarshalJSON()
if err != nil {
- appmgr.Logger.Info("No schema file found for '%s', aborting ...", *req.Metadata.Name)
- return
+ appmgr.Logger.Error("Config marshalling failed: %v", err)
+ return err
}
- return cm.doValidate(c.Descriptor, req.Config)
-}
-
-func (cm *CM) doValidate(schema, cfg interface{}) (errList models.ConfigValidationErrors, err error) {
- schemaLoader := gojsonschema.NewGoLoader(schema)
- documentLoader := gojsonschema.NewGoLoader(cfg)
- result, err := gojsonschema.Validate(schemaLoader, documentLoader)
+ err = ioutil.WriteFile(viper.GetString("xapp.tmpConfig"), cmJson, 0644)
if err != nil {
- appmgr.Logger.Info("Validation failed: %v", err)
- return
+ appmgr.Logger.Error("WriteFile failed: %v", err)
+ return err
}
- if result.Valid() == false {
- appmgr.Logger.Info("The document is not valid, Errors: %v", result.Errors())
- for _, desc := range result.Errors() {
- field := desc.Field()
- validationError := desc.Description()
- errList = append(errList, &models.ConfigValidationError{Field: &field, Error: &validationError})
- }
- return errList, errors.New("Validation failed!")
- }
- return
+ return nil
}
func (cm *CM) ReadFile(name string, data interface{}) (err error) {
return
}
+func (cm *CM) ReadConfigmap(name string, ns string) (string, error) {
+ args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s", ns, cm.GetConfigMapName(name, ns))
+ out, err := util.KubectlExec(args)
+ return string(out), err
+}
+
+func (cm *CM) ReplaceConfigMap(name, ns string) (error) {
+ cmd := " create configmap -n %s %s --from-file=%s -o json --dry-run | kubectl replace -f -"
+ args := fmt.Sprintf(cmd, ns, cm.GetConfigMapName(name, ns), viper.GetString("xapp.tmpConfig"))
+ _, err := util.KubectlExec(args)
+ return err
+}
+
func (cm *CM) FetchChart(name string) (err error) {
tarDir := viper.GetString("xapp.tarDir")
repo := viper.GetString("helm.repo-name")
for _, m := range v.GetArray("rmr", "txMessages") {
msgs.TxMessages = append(msgs.TxMessages, strings.Trim(m.String(), `"`))
}
+
for _, m := range v.GetArray("rmr", "rxMessages") {
msgs.RxMessages = append(msgs.RxMessages, strings.Trim(m.String(), `"`))
}
+
for _, m := range v.GetArray("rmr", "policies") {
if val, err := strconv.Atoi(strings.Trim(m.String(), `"`)); err == nil {
msgs.Policies = append(msgs.Policies, int64(val))
}
return ns
}
+
+func (cm *CM) GetNamesFromHelmRepo() (names []string) {
+ rname := viper.GetString("helm.repo-name")
+
+ cmdArgs := strings.Join([]string{"search ", rname}, "")
+ out, err := util.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 (cm *CM) Validate(req models.XAppConfig) (errList models.ConfigValidationErrors, err error) {
+ var desc interface{}
+ err = cm.ReadSchema(*req.Metadata.XappName, &desc)
+ if err != nil {
+ appmgr.Logger.Info("No schema file found for '%s', aborting ...", *req.Metadata.XappName)
+ return
+ }
+ return cm.doValidate(desc, req.Config)
+}
+
+func (cm *CM) doValidate(schema, cfg interface{}) (errList models.ConfigValidationErrors, err error) {
+ schemaLoader := gojsonschema.NewGoLoader(schema)
+ documentLoader := gojsonschema.NewGoLoader(cfg)
+
+ result, err := gojsonschema.Validate(schemaLoader, documentLoader)
+ if err != nil {
+ appmgr.Logger.Info("Validation failed: %v", err)
+ return
+ }
+
+ if result.Valid() == false {
+ appmgr.Logger.Info("The document is not valid, Errors: %v", result.Errors())
+ for _, desc := range result.Errors() {
+ field := desc.Field()
+ validationError := desc.Description()
+ errList = append(errList, &models.ConfigValidationError{Field: &field, Error: &validationError})
+ }
+ return errList, errors.New("Validation failed!")
+ }
+ appmgr.Logger.Info("Config validation successful!")
+
+ return
+}
\ No newline at end of file
return
}
-func (cm *MockedConfigMapper) CreateConfigMap(r models.XAppConfig) (errList models.ConfigValidationErrors, err error) {
- return
-}
-
-func (cm *MockedConfigMapper) GetConfigMap(m models.XappDescriptor, c *interface{}) (err error) {
- return
-}
-
func (cm *MockedConfigMapper) UpdateConfigMap(r models.XAppConfig) (errList models.ConfigValidationErrors, err error) {
return
}
-func (cm *MockedConfigMapper) DeleteConfigMap(r models.XAppConfig) (c interface{}, err error) {
- return
-}
-
-func (cm *MockedConfigMapper) PurgeConfigMap(m models.XappDescriptor) (c interface{}, err error) {
- return
-}
-
-func (cm *MockedConfigMapper) RestoreConfigMap(m models.XappDescriptor, c interface{}) (err error) {
- return
-}
-
func (cm *MockedConfigMapper) ReadConfigMap(name string, ns string, c *interface{}) (err error) {
return
}
-func (cm *MockedConfigMapper) ApplyConfigMap(r models.XAppConfig, action string) (err error) {
- return
-}
-
func (cm *MockedConfigMapper) FetchChart(name string) (err error) {
return
}
}
}
-func TestApplyConfigMapSuccess(t *testing.T) {
- name := "dummy-xapp"
- m := models.ConfigMetadata{Name: &name, Namespace: "ricxapp"}
- s := ConfigSample{5, "localhost"}
-
- util.KubectlExec = func(args string) (out []byte, err error) {
- return []byte(`{"logger": {"level": 2}}`), nil
- }
-
- err := NewCM().ApplyConfigMap(models.XAppConfig{Metadata: &m, Config: s}, "create")
- if err != nil {
- t.Errorf("ApplyConfigMap failed: %v", err)
- }
-}
-
-func TestRestoreConfigMapSuccess(t *testing.T) {
+func TestBuildConfigMapSuccess(t *testing.T) {
name := "dummy-xapp"
- m := models.XappDescriptor{XappName: &name, Namespace: "ricxapp"}
- s := ConfigSample{5, "localhost"}
+ namespace := "ricxapp"
+ m := models.ConfigMetadata{XappName: &name, Namespace: &namespace}
+ s := `{"Metadata": {"XappName": "ueec", "Namespace": "ricxapp"}, "Config": {"active": true, "interfaceId":{"globalENBId": {"eNBId": 77, "plmnId": "6666"}}}}`
util.KubectlExec = func(args string) (out []byte, err error) {
return []byte(`{"logger": {"level": 2}}`), nil
}
- err := NewCM().RestoreConfigMap(m, s)
+ cmString, err := NewCM().BuildConfigMap(models.XAppConfig{Metadata: &m, Config: s})
if err != nil {
- t.Errorf("RestoreConfigMap failed: %v", err)
- }
-}
-
-func TestDeleteConfigMapSuccess(t *testing.T) {
- util.HelmExec = func(args string) (out []byte, err error) {
- return []byte("ok"), nil
- }
-
- util.KubectlExec = func(args string) (out []byte, err error) {
- return []byte(`{"logger": {"level": 2}}`), nil
- }
-
- validationErrors, err := NewCM().DeleteConfigMap(models.ConfigMetadata{})
- if err != nil {
- t.Errorf("DeleteConfigMap failed: %v -> %v", err, validationErrors)
- }
-}
-
-func TestPurgeConfigMapSuccess(t *testing.T) {
- util.HelmExec = func(args string) (out []byte, err error) {
- return []byte("ok"), nil
- }
-
- util.KubectlExec = func(args string) (out []byte, err error) {
- return []byte(`{"logger": {"level": 2}}`), nil
- }
-
- name := "dummy-xapp"
- validationErrors, err := NewCM().PurgeConfigMap(models.XappDescriptor{XappName: &name})
- if err != nil {
- t.Errorf("PurgeConfigMap failed: %v -> %v", err, validationErrors)
- }
-}
-
-func TestCreateConfigMapFails(t *testing.T) {
- name := "dummy-xapp"
- validationErrors, err := NewCM().CreateConfigMap(models.XAppConfig{Metadata: &models.ConfigMetadata{Name: &name}})
- if err == nil {
- t.Errorf("CreateConfigMap failed: %v -> %v", err, validationErrors)
+ t.Errorf("BuildConfigMap failed: %v -> %v", err, cmString)
}
}
func TestUpdateConfigMapFails(t *testing.T) {
name := "dummy-xapp"
- validationErrors, err := NewCM().UpdateConfigMap(models.XAppConfig{Metadata: &models.ConfigMetadata{Name: &name}})
+ namespace := "ricxapp"
+ config := models.XAppConfig{Metadata: &models.ConfigMetadata{XappName: &name, Namespace: &namespace}}
+
+ validationErrors, err := NewCM().UpdateConfigMap(config)
if err == nil {
- t.Errorf("CreateConfigMap failed: %v -> %v", err, validationErrors)
+ t.Errorf("UpdateConfigMap failed: %v -> %v", err, validationErrors)
}
}
func TestValidationSuccess(t *testing.T) {
var d interface{}
var cfg map[string]interface{}
- err := json.Unmarshal([]byte(`{"local": {"host": ":8080"}, "logger": {"level": 3}}`), &cfg)
+ err := json.Unmarshal([]byte(`{"active": true, "interfaceId":{"globalENBId": {"eNBId": 77, "plmnId": "6666"}}}`), &cfg)
err = NewCM().ReadFile("../../test/schema.json", &d)
if err != nil {
func TestValidationFails(t *testing.T) {
var d interface{}
var cfg map[string]interface{}
- err := json.Unmarshal([]byte(`{"local": {"host": ":8080"}, "logger": {"level": "INVALID"}}`), &cfg)
+ err := json.Unmarshal([]byte(`{"active": "INVALID", "interfaceId":{"globalENBId": {"eNBId": 77, "plmnId": "6666"}}}`), &cfg)
err = NewCM().ReadFile("../../test/schema.json", &d)
if err != nil {
func (h *Helm) AddRepo() (out []byte, err error) {
// Get helm repo user name and password from files mounted by secret object
- credFile, err := ioutil.ReadFile(viper.GetString("helm.helm-username-file"))
+ username, err := ioutil.ReadFile(viper.GetString("helm.helm-username-file"))
if err != nil {
appmgr.Logger.Info("helm_repo_username ReadFile failed: %v", err.Error())
return
}
- username := " --username " + string(credFile)
- credFile, err = ioutil.ReadFile(viper.GetString("helm.helm-password-file"))
+ password, err := ioutil.ReadFile(viper.GetString("helm.helm-password-file"))
if err != nil {
appmgr.Logger.Info("helm_repo_password ReadFile failed: %v", err.Error())
return
}
- pwd := " --password " + string(credFile)
- rname := viper.GetString("helm.repo-name")
- repo := viper.GetString("helm.repo")
+ repoArgs := fmt.Sprintf(" %s %s ", viper.GetString("helm.repo-name"), viper.GetString("helm.repo"))
+ credentials := fmt.Sprintf(" --username %s --password %s", string(username), string(password))
- return util.HelmExec(strings.Join([]string{"repo add ", rname, " ", repo, username, pwd}, ""))
+ return util.HelmExec(strings.Join([]string{"repo add ", repoArgs, credentials}, ""))
}
func (h *Helm) Install(m models.XappDescriptor) (xapp models.Xapp, err error) {
- var c interface{}
m.Namespace = h.cm.GetNamespace(m.Namespace)
out, err := h.Run(strings.Join([]string{"repo update "}, ""))
return
}
- if err = h.cm.GetConfigMap(m, &c); err != nil {
- out, err = h.Run(h.GetInstallArgs(m, false))
- if err != nil {
- return
- }
- return h.ParseStatus(*m.XappName, string(out))
- }
-
- // ConfigMap exists, try to override
- out, err = h.Run(h.GetInstallArgs(m, true))
- if err == nil {
- return h.ParseStatus(*m.XappName, string(out))
- }
-
- c, cmErr := h.cm.PurgeConfigMap(m)
out, err = h.Run(h.GetInstallArgs(m, false))
if err != nil {
return
}
-
- if cmErr == nil {
- cmErr = h.cm.RestoreConfigMap(m, c)
- }
return h.ParseStatus(*m.XappName, string(out))
}
func (h *Helm) parseAllStatus(names []string) (xapps models.AllDeployedXapps, err error) {
xapps = models.AllDeployedXapps{}
for _, name := range names {
- err := h.cm.ReadSchema(name, &models.XAppConfig{})
+ var desc interface{}
+ err := h.cm.ReadSchema(name, &desc)
if err != nil {
continue
}
}
func (h *Helm) GetInstallArgs(x models.XappDescriptor, cmOverride bool) (args string) {
- args = args + " --namespace=" + x.Namespace
+ args = fmt.Sprintf("%s --namespace=%s", args, x.Namespace)
if x.HelmVersion != "" {
- args = args + " --version=" + x.HelmVersion
+ args = fmt.Sprintf("%s --version=%s", args, x.HelmVersion)
}
if x.ReleaseName != "" {
- args = args + " --name=" + x.ReleaseName
+ args = fmt.Sprintf("%s --name=%s", args, x.ReleaseName)
} else {
- args = args + " --name=" + *x.XappName
+ args = fmt.Sprintf("%s --name=%s", args, *x.XappName)
}
if cmOverride == true {
- args = args + " --set ricapp.appconfig.override=" + *x.XappName + "-appconfig"
+ args = fmt.Sprintf("%s ---set ricapp.appconfig.override=%s-appconfig", args, *x.XappName)
}
if x.OverrideFile != nil {
}
func TestHelmStatus(t *testing.T) {
- //NewHelm().SetCM(&ConfigMap{})
util.KubectlExec = func(args string) (out []byte, err error) {
return []byte("10.102.184.212"), nil
}
package restful
import (
- //"github.com/spf13/viper"
"log"
"os"
"time"
func(params health.GetHealthAliveParams) middleware.Responder {
return health.NewGetHealthAliveOK()
})
- api.HealthGetHealthReadyHandler = health.GetHealthReadyHandlerFunc(
+
+ api.HealthGetHealthReadyHandler = health.GetHealthReadyHandlerFunc(
func(params health.GetHealthReadyParams) middleware.Responder {
return health.NewGetHealthReadyOK()
})
func(params operations.GetSubscriptionsParams) middleware.Responder {
return operations.NewGetSubscriptionsOK().WithPayload(r.rh.GetAllSubscriptions())
})
+
api.GetSubscriptionByIDHandler = operations.GetSubscriptionByIDHandlerFunc(
func(params operations.GetSubscriptionByIDParams) middleware.Responder {
if result, found := r.rh.GetSubscriptionById(params.SubscriptionID); found {
}
return operations.NewGetSubscriptionByIDNotFound()
})
+
api.AddSubscriptionHandler = operations.AddSubscriptionHandlerFunc(
func(params operations.AddSubscriptionParams) middleware.Responder {
return operations.NewAddSubscriptionCreated().WithPayload(r.rh.AddSubscription(*params.SubscriptionRequest))
})
+
api.ModifySubscriptionHandler = operations.ModifySubscriptionHandlerFunc(
func(params operations.ModifySubscriptionParams) middleware.Responder {
if _, ok := r.rh.ModifySubscription(params.SubscriptionID, *params.SubscriptionRequest); ok {
}
return operations.NewModifySubscriptionBadRequest()
})
+
api.DeleteSubscriptionHandler = operations.DeleteSubscriptionHandlerFunc(
func(params operations.DeleteSubscriptionParams) middleware.Responder {
if _, ok := r.rh.DeleteSubscription(params.SubscriptionID); ok {
}
return xapp.NewGetAllXappsInternalServerError()
})
+
api.XappListAllXappsHandler = xapp.ListAllXappsHandlerFunc(
func(params xapp.ListAllXappsParams) middleware.Responder {
if result := r.helm.SearchAll(); err == nil {
}
return xapp.NewListAllXappsInternalServerError()
})
+
api.XappGetXappByNameHandler = xapp.GetXappByNameHandlerFunc(
func(params xapp.GetXappByNameParams) middleware.Responder {
if result, err := r.helm.Status(params.XAppName); err == nil {
}
return xapp.NewGetXappByNameNotFound()
})
+
api.XappGetXappInstanceByNameHandler = xapp.GetXappInstanceByNameHandlerFunc(
func(params xapp.GetXappInstanceByNameParams) middleware.Responder {
if result, err := r.helm.Status(params.XAppName); err == nil {
}
return xapp.NewGetXappInstanceByNameNotFound()
})
+
api.XappDeployXappHandler = xapp.DeployXappHandlerFunc(
func(params xapp.DeployXappParams) middleware.Responder {
if result, err := r.helm.Install(*params.XappDescriptor); err == nil {
}
return xapp.NewUndeployXappInternalServerError()
})
+
api.XappUndeployXappHandler = xapp.UndeployXappHandlerFunc(
func(params xapp.UndeployXappParams) middleware.Responder {
if result, err := r.helm.Delete(params.XAppName); err == nil {
// URL: /ric/v1/config
api.XappGetAllXappConfigHandler = xapp.GetAllXappConfigHandlerFunc(
func(params xapp.GetAllXappConfigParams) middleware.Responder {
- return xapp.NewGetAllXappConfigOK().WithPayload(r.cm.UploadConfig())
+ return xapp.NewGetAllXappConfigOK().WithPayload(r.cm.UploadConfigAll())
})
- api.XappCreateXappConfigHandler = xapp.CreateXappConfigHandlerFunc(
- func(params xapp.CreateXappConfigParams) middleware.Responder {
- result, err := r.cm.CreateConfigMap(*params.XAppConfig)
- if err == nil {
- if err.Error() != "Validation failed!" {
- return xapp.NewCreateXappConfigInternalServerError()
- } else {
- return xapp.NewCreateXappConfigUnprocessableEntity()
- }
- }
- r.rh.PublishSubscription(models.Xapp{}, models.EventTypeCreated)
- return xapp.NewCreateXappConfigCreated().WithPayload(result)
+
+ api.XappGetConfigElementHandler = xapp.GetConfigElementHandlerFunc(
+ func(params xapp.GetConfigElementParams) middleware.Responder {
+ return xapp.NewGetConfigElementOK().WithPayload(r.cm.UploadConfigElement(params.Element))
})
+
api.XappModifyXappConfigHandler = xapp.ModifyXappConfigHandlerFunc(
func(params xapp.ModifyXappConfigParams) middleware.Responder {
result, err := r.cm.UpdateConfigMap(*params.XAppConfig)
- if err == nil {
+ if err != nil {
if err.Error() != "Validation failed!" {
return xapp.NewModifyXappConfigInternalServerError()
} else {
r.rh.PublishSubscription(models.Xapp{}, models.EventTypeModified)
return xapp.NewModifyXappConfigOK().WithPayload(result)
})
- api.XappDeleteXappConfigHandler = xapp.DeleteXappConfigHandlerFunc(
- func(params xapp.DeleteXappConfigParams) middleware.Responder {
- _, err := r.cm.DeleteConfigMap(*params.ConfigMetadata)
- if err == nil {
- return xapp.NewDeleteXappConfigInternalServerError()
- }
- r.rh.PublishSubscription(models.Xapp{}, models.EventTypeDeleted)
- return xapp.NewDeleteXappConfigNoContent()
- })
-
- // LCM: /xapps/{xAppName}/instances/{xAppInstanceName}/stop/start
- api.XappStartXappInstanceByNameHandler = xapp.StartXappInstanceByNameHandlerFunc(
- func(params xapp.StartXappInstanceByNameParams) middleware.Responder {
- return xapp.NewStartXappInstanceByNameOK()
- })
- api.XappStopXappInstanceByNameHandler = xapp.StopXappInstanceByNameHandlerFunc(
- func(params xapp.StopXappInstanceByNameParams) middleware.Responder {
- return xapp.NewStopXappInstanceByNameOK()
- })
return api
}
}
for i := 0; i < 5; i++ {
+ time.Sleep(time.Duration(5) * time.Second)
if result, _ := r.helm.Status(name); result.Instances != nil {
r.rh.PublishSubscription(result, models.EventTypeDeployed)
break
}
- time.Sleep(time.Duration(5) * time.Second)
}
}
"type": "object",
"title": "The Root Schema",
"required": [
- "local",
- "logger"
+ "active",
+ "interfaceId"
],
"properties": {
- "local": {
- "$id": "#/properties/local",
- "type": "object",
- "title": "The Local Schema",
- "required": [
- "host"
- ],
- "properties": {
- "host": {
- "$id": "#/properties/local/properties/host",
- "type": "string",
- "title": "The Host Schema",
- "default": "",
- "pattern": "^(.*)$"
- }
- }
+ "active": {
+ "$id": "#/properties/active",
+ "type": "boolean",
+ "title": "The Active Schema",
+ "default": false,
+ "examples": [
+ false
+ ]
},
- "logger": {
- "$id": "#/properties/logger",
+ "interfaceId": {
+ "$id": "#/properties/interfaceId",
"type": "object",
- "title": "The Logger Schema",
+ "title": "The Interfaceid Schema",
"required": [
- "level"
+ "globalENBId"
],
"properties": {
- "level": {
- "$id": "#/properties/logger/properties/level",
- "type": "integer",
- "title": "The Level Schema",
- "default": 0
+ "globalENBId": {
+ "$id": "#/properties/interfaceId/properties/globalENBId",
+ "type": "object",
+ "title": "The Globalenbid Schema",
+ "required": [
+ "plmnId",
+ "eNBId"
+ ],
+ "properties": {
+ "plmnId": {
+ "$id": "#/properties/interfaceId/properties/globalENBId/properties/plmnId",
+ "type": "string",
+ "title": "The Plmnid Schema",
+ "default": "",
+ "examples": [
+ "310150"
+ ],
+ "pattern": "^(.*)$"
+ },
+ "eNBId": {
+ "$id": "#/properties/interfaceId/properties/globalENBId/properties/eNBId",
+ "type": "integer",
+ "title": "The Enbid Schema",
+ "default": 0,
+ "examples": [
+ 202251
+ ]
+ }
+ }
}
}
}
}
-}
\ No newline at end of file
+}