summaryrefslogtreecommitdiffstats
path: root/src/k8splugin/internal
diff options
context:
space:
mode:
Diffstat (limited to 'src/k8splugin/internal')
-rw-r--r--src/k8splugin/internal/app/config.go312
-rw-r--r--src/k8splugin/internal/app/config_backend.go194
-rw-r--r--src/k8splugin/internal/app/config_test.go17
-rw-r--r--src/k8splugin/internal/app/query.go16
-rw-r--r--src/k8splugin/internal/db/etcd.go23
-rw-r--r--src/k8splugin/internal/db/etcd_testing.go12
-rw-r--r--src/k8splugin/internal/rb/config_template.go31
7 files changed, 454 insertions, 151 deletions
diff --git a/src/k8splugin/internal/app/config.go b/src/k8splugin/internal/app/config.go
index 8952c16d..fce163fc 100644
--- a/src/k8splugin/internal/app/config.go
+++ b/src/k8splugin/internal/app/config.go
@@ -22,17 +22,17 @@ import (
"strconv"
"strings"
- "github.com/onap/multicloud-k8s/src/k8splugin/internal/helm"
-
pkgerrors "github.com/pkg/errors"
)
// Config contains the parameters needed for configuration
type Config struct {
- ConfigName string `json:"config-name"`
- TemplateName string `json:"template-name"`
- Description string `json:"description"`
- Values map[string]interface{} `json:"values"`
+ ConfigName string `json:"config-name"`
+ TemplateName string `json:"template-name"`
+ Description string `json:"description"`
+ Values map[string]interface{} `json:"values"`
+ ConfigVersion uint `json:"config-version"`
+ ConfigTag string `json:"config-tag"`
}
//ConfigResult output for Create, Update and delete
@@ -54,6 +54,12 @@ type ConfigRollback struct {
} `json:"anyOf"`
}
+//ConfigRollback input
+type ConfigTag struct {
+ ConfigVersion uint `json:"config-version"`
+ ConfigTag string `json:"config-tag"`
+}
+
//ConfigTagit for Tagging configurations
type ConfigTagit struct {
TagName string `json:"tag-name"`
@@ -63,14 +69,18 @@ type ConfigTagit struct {
type ConfigManager interface {
Create(instanceID string, p Config) (ConfigResult, error)
Get(instanceID, configName string) (Config, error)
+ GetVersion(instanceID, configName, version string) (Config, error)
+ GetTag(instanceID, configName, tagName string) (Config, error)
List(instanceID string) ([]Config, error)
+ VersionList(instanceID, configName string) ([]Config, error)
Help() map[string]string
Update(instanceID, configName string, p Config) (ConfigResult, error)
Delete(instanceID, configName string) (ConfigResult, error)
- DeleteAll(instanceID, configName string) error
- Rollback(instanceID string, configName string, p ConfigRollback) error
+ DeleteAll(instanceID, configName string, deleteConfigOnly bool) error
+ Rollback(instanceID string, configName string, p ConfigRollback, acceptRevert bool) (ConfigResult, error)
Cleanup(instanceID string) error
- Tagit(instanceID string, configName string, p ConfigTagit) error
+ Tagit(instanceID string, configName string, p ConfigTagit) (ConfigTag, error)
+ TagList(instanceID, configName string) ([]ConfigTag, error)
}
// ConfigClient implements the ConfigManager
@@ -99,7 +109,7 @@ func (v *ConfigClient) Help() map[string]string {
func (v *ConfigClient) Create(instanceID string, p Config) (ConfigResult, error) {
log.Printf("[Config Create] Instance %s", instanceID)
// Check required fields
- if p.ConfigName == "" || p.TemplateName == "" || len(p.Values) == 0 {
+ if p.ConfigName == "" || p.TemplateName == "" {
return ConfigResult{}, pkgerrors.New("Incomplete Configuration Provided")
}
// Resolving rbName, Version, etc. not to break response
@@ -123,7 +133,7 @@ func (v *ConfigClient) Create(instanceID string, p Config) (ConfigResult, error)
// Acquire per profile Mutex
lock.Lock()
defer lock.Unlock()
- var appliedResources ([]helm.KubernetesResource)
+ var appliedResources ([]KubernetesConfigResource)
appliedResources, err = applyConfig(instanceID, p, profileChannel, "POST", nil)
if err != nil {
return ConfigResult{}, pkgerrors.Wrap(err, "Apply Config failed")
@@ -160,10 +170,6 @@ func (v *ConfigClient) Create(instanceID string, p Config) (ConfigResult, error)
// Update an entry for the config in the database
func (v *ConfigClient) Update(instanceID, configName string, p Config) (ConfigResult, error) {
log.Printf("[Config Update] Instance %s Config %s", instanceID, configName)
- // Check required fields
- if len(p.Values) == 0 {
- return ConfigResult{}, pkgerrors.New("Incomplete Configuration Provided")
- }
// Resolving rbName, Version, etc. not to break response
rbName, rbVersion, profileName, _, err := resolveModelFromInstance(instanceID)
if err != nil {
@@ -182,7 +188,7 @@ func (v *ConfigClient) Update(instanceID, configName string, p Config) (ConfigRe
// Acquire per profile Mutex
lock.Lock()
defer lock.Unlock()
- var appliedResources ([]helm.KubernetesResource)
+ var appliedResources ([]KubernetesConfigResource)
appliedResources, err = applyConfig(instanceID, p, profileChannel, "PUT", nil)
if err != nil {
return ConfigResult{}, pkgerrors.Wrap(err, "Apply Config failed")
@@ -232,6 +238,59 @@ func (v *ConfigClient) Get(instanceID, configName string) (Config, error) {
if err != nil {
return Config{}, pkgerrors.Wrap(err, "Get Config DB Entry")
}
+
+ cvs := ConfigVersionStore{
+ instanceID: instanceID,
+ configName: configName,
+ }
+ currentVersion, err := cvs.getCurrentVersion(configName)
+ if err != nil {
+ return Config{}, pkgerrors.Wrap(err, "Get Config Version Entry")
+ }
+ cfg.ConfigVersion = currentVersion
+ return cfg, nil
+}
+
+// Get version config entry in the database
+func (v *ConfigClient) GetTag(instanceID, configName, tagName string) (Config, error) {
+ cvs := ConfigVersionStore{
+ instanceID: instanceID,
+ configName: configName,
+ }
+ version, err := cvs.getTagVersion(configName, tagName)
+ if err != nil {
+ return Config{}, pkgerrors.Wrap(err, "Get Config Tag Version Entry")
+ }
+ return v.GetVersion(instanceID, configName, version)
+}
+
+// Get version config entry in the database
+func (v *ConfigClient) GetVersion(instanceID, configName, version string) (Config, error) {
+
+ // Acquire per profile Mutex
+ lock, _ := getProfileData(instanceID)
+ lock.Lock()
+ defer lock.Unlock()
+ // Read Config DB
+ cs := ConfigStore{
+ instanceID: instanceID,
+ configName: configName,
+ }
+ cfg, err := cs.getConfig()
+
+ cvs := ConfigVersionStore{
+ instanceID: instanceID,
+ configName: configName,
+ }
+ versionInt, err := strconv.ParseUint(version, 0, 32)
+ if err != nil {
+ return Config{}, pkgerrors.Wrap(err, "Parsint version string")
+ }
+ _, _, _, _, err = cvs.getConfigVersion(configName, uint(versionInt))
+ if err != nil {
+ return Config{}, pkgerrors.Wrap(err, "Get Config Version Entry")
+ }
+ cfg.ConfigVersion = uint(versionInt)
return cfg, nil
}
@@ -247,14 +306,100 @@ func (v *ConfigClient) List(instanceID string) ([]Config, error) {
instanceID: instanceID,
}
cfg, err := cs.getConfigList()
+ result := make([]Config, 0)
+ for _, config := range cfg {
+ cvs := ConfigVersionStore{
+ instanceID: instanceID,
+ configName: config.ConfigName,
+ }
+ currentVersion, err := cvs.getCurrentVersion(config.ConfigName)
+ if err != nil {
+ return []Config{}, pkgerrors.Wrap(err, "Get Current Config Version ")
+ }
+ config.ConfigVersion = currentVersion
+ result = append(result, config)
+ }
if err != nil {
return []Config{}, pkgerrors.Wrap(err, "Get Config DB Entry")
}
- return cfg, nil
+ return result, nil
+}
+
+// Version List config entry in the database
+func (v *ConfigClient) VersionList(instanceID string, configName string) ([]Config, error) {
+
+ // Acquire per profile Mutex
+ lock, _ := getProfileData(instanceID)
+ lock.Lock()
+ defer lock.Unlock()
+
+ cvs := ConfigVersionStore{
+ instanceID: instanceID,
+ configName: configName,
+ }
+ currentVersion, err := cvs.getCurrentVersion(configName)
+ if err != nil {
+ return []Config{}, pkgerrors.Wrap(err, "Get Current Config Version ")
+ }
+ //Get all configurations
+ var i uint
+ cfgList := make([]Config, 0)
+ for i = 1; i <= currentVersion; i++ {
+ config, _, _, _, err := cvs.getConfigVersion(configName, i)
+ config.ConfigVersion = i
+ if err != nil {
+ return []Config{}, pkgerrors.Wrap(err, "Get Config Version")
+ }
+ cfgList = append(cfgList, config)
+ }
+
+ return cfgList, nil
+}
+
+func (v *ConfigClient) TagList(instanceID, configName string) ([]ConfigTag, error) {
+
+ // Acquire per profile Mutex
+ lock, _ := getProfileData(instanceID)
+ lock.Lock()
+ defer lock.Unlock()
+ // Read Config DB
+ cs := ConfigStore{
+ instanceID: instanceID,
+ configName: configName,
+ }
+ _, err := cs.getConfig()
+ if err != nil {
+ return []ConfigTag{}, pkgerrors.Wrap(err, "Get Config DB Entry")
+ }
+ cvs := ConfigVersionStore{
+ instanceID: instanceID,
+ configName: configName,
+ }
+
+ tagList, err := cvs.getTagList(configName)
+ if err != nil {
+ return []ConfigTag{}, pkgerrors.Wrap(err, "Get Tag list")
+ }
+ result := make([]ConfigTag, 0)
+ for _, tag := range tagList {
+ tagData := ConfigTag{}
+ version, err := cvs.getTagVersion(configName, tag)
+ if err != nil {
+ return []ConfigTag{}, pkgerrors.Wrap(err, "Get Tag version")
+ }
+ versionInt, err := strconv.ParseUint(version, 0, 32)
+ if err != nil {
+ return []ConfigTag{}, pkgerrors.Wrap(err, "Parsint version string")
+ }
+ tagData.ConfigTag = tag
+ tagData.ConfigVersion = uint(versionInt)
+ result = append(result, tagData)
+ }
+ return result, nil
}
// Delete the Config from database
-func (v *ConfigClient) DeleteAll(instanceID, configName string) error {
+func (v *ConfigClient) DeleteAll(instanceID, configName string, deleteConfigOnly bool) error {
log.Printf("[Config Delete All] Instance %s Config %s", instanceID, configName)
// Check if Config exists
cs := ConfigStore{
@@ -270,19 +415,13 @@ func (v *ConfigClient) DeleteAll(instanceID, configName string) error {
instanceID: instanceID,
configName: configName,
}
- currentVersion, err := cvs.getCurrentVersion(configName)
- if err != nil {
- return pkgerrors.Wrap(err, "Current version get failed")
- }
- _, _, action, _, err := cvs.getConfigVersion(configName, currentVersion)
- if err != nil {
- return pkgerrors.Wrap(err, "Config version get failed")
- }
- if action != "DELETE" {
- _, err = v.Delete(instanceID, configName)
+ if !deleteConfigOnly {
+ var rollbackConfig = ConfigRollback{}
+ rollbackConfig.AnyOf.ConfigVersion = "0"
+ _, err = v.Rollback(instanceID, configName, rollbackConfig, true)
if err != nil {
- return pkgerrors.Wrap(err, "Config DELETE version failed")
+ return pkgerrors.Wrap(err, "Rollback to base version")
}
}
// Delete Config from DB
@@ -339,7 +478,7 @@ func (v *ConfigClient) Delete(instanceID, configName string) (ConfigResult, erro
if err != nil {
return ConfigResult{}, pkgerrors.Wrap(err, "Update Config DB Entry")
}
- version, err := cvs.createConfigVersion(p, configPrev, "DELETE", []helm.KubernetesResource{})
+ version, err := cvs.createConfigVersion(p, configPrev, "DELETE", []KubernetesConfigResource{})
if err != nil {
return ConfigResult{}, pkgerrors.Wrap(err, "Create Delete Config Version DB Entry")
}
@@ -358,25 +497,28 @@ func (v *ConfigClient) Delete(instanceID, configName string) (ConfigResult, erro
}
// Rollback starts from current version and rollbacks to the version desired
-func (v *ConfigClient) Rollback(instanceID string, configName string, rback ConfigRollback) error {
+func (v *ConfigClient) Rollback(instanceID string, configName string, rback ConfigRollback, acceptRevert bool) (ConfigResult, error) {
log.Printf("[Config Rollback] Instance %s Config %s", instanceID, configName)
var reqVersion string
var err error
-
+ rbName, rbVersion, profileName, _, err := resolveModelFromInstance(instanceID)
+ if err != nil {
+ return ConfigResult{}, pkgerrors.Wrap(err, "Retrieving model info")
+ }
if rback.AnyOf.ConfigTag != "" {
reqVersion, err = v.GetTagVersion(instanceID, configName, rback.AnyOf.ConfigTag)
if err != nil {
- return pkgerrors.Wrap(err, "Rollback Invalid tag")
+ return ConfigResult{}, pkgerrors.Wrap(err, "Rollback Invalid tag")
}
} else if rback.AnyOf.ConfigVersion != "" {
reqVersion = rback.AnyOf.ConfigVersion
} else {
- return pkgerrors.Errorf("No valid Index for Rollback")
+ return ConfigResult{}, pkgerrors.Errorf("No valid Index for Rollback")
}
index, err := strconv.Atoi(reqVersion)
if err != nil {
- return pkgerrors.Wrap(err, "Rollback Invalid Index")
+ return ConfigResult{}, pkgerrors.Wrap(err, "Rollback Invalid Index")
}
rollbackIndex := uint(index)
@@ -391,62 +533,114 @@ func (v *ConfigClient) Rollback(instanceID string, configName string, rback Conf
}
currentVersion, err := cvs.getCurrentVersion(configName)
if err != nil {
- return pkgerrors.Wrap(err, "Rollback Get Current Config Version ")
+ return ConfigResult{}, pkgerrors.Wrap(err, "Rollback Get Current Config Version ")
+ }
+
+ if (rollbackIndex < 1 && !acceptRevert) || rollbackIndex >= currentVersion {
+ return ConfigResult{}, pkgerrors.Wrap(err, "Rollback Invalid Config Version")
}
- if rollbackIndex < 1 && rollbackIndex >= currentVersion {
- return pkgerrors.Wrap(err, "Rollback Invalid Config Version")
+ if rollbackIndex < 1 && acceptRevert {
+ rollbackIndex = 0
}
//Rollback all the intermettinent configurations
for i := currentVersion; i > rollbackIndex; i-- {
configNew, configPrev, _, resources, err := cvs.getConfigVersion(configName, i)
if err != nil {
- return pkgerrors.Wrap(err, "Rollback Get Config Version")
+ return ConfigResult{}, pkgerrors.Wrap(err, "Rollback Get Config Version")
+ }
+ var prevAction string
+ if i == 1 {
+ prevAction = "POST"
+ configPrev.ConfigName = ""
+ configPrev.TemplateName = ""
+ configPrev.Values = make(map[string]interface{})
+ } else {
+ _, _, prevAction, _, err = cvs.getConfigVersion(configName, i-1)
}
- _, _, prevAction, _, err := cvs.getConfigVersion(configName, i-1)
+ log.Printf("ROLLBACK to version: %d", i-1)
if err != nil {
- return pkgerrors.Wrap(err, "Rollback Get Prev Config Version")
+ return ConfigResult{}, pkgerrors.Wrap(err, "Rollback Get Prev Config Version")
}
cs := ConfigStore{
instanceID: instanceID,
configName: configNew.ConfigName,
}
if prevAction != "DELETE" {
+ var resourcesToDelete = make([]KubernetesConfigResource, 0)
+ for _, res := range resources {
+ if res.Status == "CREATED" {
+ resourcesToDelete = append(resourcesToDelete, res)
+ }
+ }
+ if len(resourcesToDelete) > 0 {
+ _, err := applyConfig(instanceID, configPrev, profileChannel, "DELETE", resources)
+ if err != nil {
+ return ConfigResult{}, pkgerrors.Wrap(err, "Apply Config failed")
+ }
+ }
appliedResources, err := applyConfig(instanceID, configPrev, profileChannel, prevAction, nil)
if err != nil {
- return pkgerrors.Wrap(err, "Apply Config failed")
+ return ConfigResult{}, pkgerrors.Wrap(err, "Apply Config failed")
}
log.Printf("%s result: %s", prevAction, appliedResources)
_, err = cs.updateConfig(configPrev)
if err != nil {
- return pkgerrors.Wrap(err, "Update Config DB Entry")
+ return ConfigResult{}, pkgerrors.Wrap(err, "Update Config DB Entry")
}
} else {
// POST is always preceeded by Config not existing
- _, err := applyConfig(instanceID, configNew, profileChannel, prevAction, resources)
+ _, err := applyConfig(instanceID, configPrev, profileChannel, prevAction, resources)
if err != nil {
- return pkgerrors.Wrap(err, "Delete Config failed")
+ return ConfigResult{}, pkgerrors.Wrap(err, "Delete Config failed")
}
log.Printf("DELETE resources: %s", resources)
_, err = cs.updateConfig(configPrev)
if err != nil {
- return pkgerrors.Wrap(err, "Update Config DB Entry")
+ return ConfigResult{}, pkgerrors.Wrap(err, "Update Config DB Entry")
}
}
}
+ if rollbackIndex == 0 {
+ //this is used only for delete config and remianing configuration 1 will be removed there
+ rollbackIndex = 1
+ }
for i := currentVersion; i > rollbackIndex; i-- {
// Delete rolled back items
err = cvs.deleteConfigVersion(configName)
if err != nil {
- return pkgerrors.Wrap(err, "Delete Config Version ")
+ return ConfigResult{}, pkgerrors.Wrap(err, "Delete Config Version ")
}
}
- return nil
+ currentVersion, err = cvs.getCurrentVersion(configName)
+ if err != nil {
+ return ConfigResult{}, pkgerrors.Wrap(err, "Rollback Get Current Config Version ")
+ }
+ // Check if Config exists
+ cs := ConfigStore{
+ instanceID: instanceID,
+ configName: configName,
+ }
+ currentConfig, err := cs.getConfig()
+ if err != nil {
+ return ConfigResult{}, pkgerrors.Wrap(err, "Update Error - Config doesn't exist")
+ }
+ // Create Result structure
+ cfgRes := ConfigResult{
+ InstanceName: instanceID,
+ DefinitionName: rbName,
+ DefinitionVersion: rbVersion,
+ ProfileName: profileName,
+ ConfigName: configName,
+ TemplateName: currentConfig.TemplateName,
+ ConfigVersion: currentVersion,
+ }
+ return cfgRes, nil
}
// Tagit tags the current version with the tag provided
-func (v *ConfigClient) Tagit(instanceID string, configName string, tag ConfigTagit) error {
+func (v *ConfigClient) Tagit(instanceID string, configName string, tag ConfigTagit) (ConfigTag, error) {
log.Printf("[Config Tag It] Instance %s Config %s", instanceID, configName)
lock, _ := getProfileData(instanceID)
// Acquire per profile Mutex
@@ -459,9 +653,17 @@ func (v *ConfigClient) Tagit(instanceID string, configName string, tag ConfigTag
}
err := cvs.tagCurrentVersion(configName, tag.TagName)
if err != nil {
- return pkgerrors.Wrap(err, "Tag of current version failed")
+ return ConfigTag{}, pkgerrors.Wrap(err, "Tag of current version failed")
}
- return nil
+ currentVersion, err := cvs.getCurrentVersion(configName)
+ if err != nil {
+ return ConfigTag{}, pkgerrors.Wrap(err, "Rollback Get Current Config Version ")
+ }
+
+ var tagResult = ConfigTag{}
+ tagResult.ConfigVersion = currentVersion
+ tagResult.ConfigTag = tag.TagName
+ return tagResult, nil
}
// GetTagVersion returns the version associated with the tag
@@ -489,7 +691,11 @@ func (v *ConfigClient) Cleanup(instanceID string) error {
}
for _, config := range configs {
- err = v.DeleteAll(instanceID, config.ConfigName)
+ _, err = v.Delete(instanceID, config.ConfigName)
+ if err != nil {
+ log.Printf("Config %s delete failed: %s", config.ConfigName, err.Error())
+ }
+ err = v.DeleteAll(instanceID, config.ConfigName, true)
if err != nil {
log.Printf("Config %s delete failed: %s", config.ConfigName, err.Error())
}
@@ -529,7 +735,7 @@ func (v *ConfigClient) ApplyAllConfig(instanceID string, configName string) erro
if action != "DELETE" {
resources = nil
}
- var appliedResources ([]helm.KubernetesResource)
+ var appliedResources ([]KubernetesConfigResource)
appliedResources, err = applyConfig(instanceID, configNew, profileChannel, action, resources)
if err != nil {
return pkgerrors.Wrap(err, "Apply Config failed")
diff --git a/src/k8splugin/internal/app/config_backend.go b/src/k8splugin/internal/app/config_backend.go
index c365363f..4dcbeb57 100644
--- a/src/k8splugin/internal/app/config_backend.go
+++ b/src/k8splugin/internal/app/config_backend.go
@@ -38,10 +38,10 @@ import (
//ConfigStore contains the values that will be stored in the database
type configVersionDBContent struct {
- ConfigNew Config `json:"config-new"`
- ConfigPrev Config `json:"config-prev"`
- Action string `json:"action"` // CRUD opration for this config
- Resources []helm.KubernetesResource `json:"resources"`
+ ConfigNew Config `json:"config-new"`
+ ConfigPrev Config `json:"config-prev"`
+ Action string `json:"action"` // CRUD opration for this config
+ Resources []KubernetesConfigResource `json:"resources"`
}
//ConfigStore to Store the Config
@@ -56,10 +56,15 @@ type ConfigVersionStore struct {
configName string
}
+type KubernetesConfigResource struct {
+ Resource helm.KubernetesResource `json:"resource"`
+ Status string `json:"status"`
+}
+
type configResourceList struct {
resourceTemplates []helm.KubernetesResourceTemplate
- resources []helm.KubernetesResource
- updatedResources chan []helm.KubernetesResource
+ resources []KubernetesConfigResource
+ updatedResources chan []KubernetesConfigResource
profile rb.Profile
action string
}
@@ -181,7 +186,7 @@ func (c ConfigStore) getConfigList() ([]Config, error) {
return []Config{}, pkgerrors.Wrap(err, "Retrieving model info")
}
cfgKey := constructKey(rbName, rbVersion, profileName, c.instanceID, tagConfig)
- values, err := db.Etcd.GetAll(cfgKey)
+ values, err := db.Etcd.GetValues(cfgKey)
if err != nil {
return []Config{}, pkgerrors.Wrap(err, "Get Config DB List")
}
@@ -194,6 +199,9 @@ func (c ConfigStore) getConfigList() ([]Config, error) {
if err != nil {
return []Config{}, pkgerrors.Wrap(err, "Unmarshaling Config Value")
}
+ if cfg.ConfigName == "" {
+ continue
+ }
result = append(result, cfg)
}
return result, nil
@@ -256,7 +264,7 @@ func (c ConfigVersionStore) cleanupIstanceTags(configName string) error {
}
// Create a version for the configuration. If previous config provided that is also stored
-func (c ConfigVersionStore) createConfigVersion(configNew, configPrev Config, action string, resources []helm.KubernetesResource) (uint, error) {
+func (c ConfigVersionStore) createConfigVersion(configNew, configPrev Config, action string, resources []KubernetesConfigResource) (uint, error) {
configName := ""
if configNew.ConfigName != "" {
@@ -281,7 +289,7 @@ func (c ConfigVersionStore) createConfigVersion(configNew, configPrev Config, ac
cs.Action = action
cs.ConfigNew = configNew
cs.ConfigPrev = configPrev
- cs.Resources = resources //[]helm.KubernetesResource{}
+ cs.Resources = resources //[]KubernetesConfigResource{}
configValue, err := db.Serialize(cs)
if err != nil {
@@ -321,27 +329,27 @@ func (c ConfigVersionStore) deleteConfigVersion(configName string) error {
// Read the specified version of the configuration and return its prev and current value.
// Also returns the action for the config version
-func (c ConfigVersionStore) getConfigVersion(configName string, version uint) (Config, Config, string, []helm.KubernetesResource, error) {
+func (c ConfigVersionStore) getConfigVersion(configName string, version uint) (Config, Config, string, []KubernetesConfigResource, error) {
rbName, rbVersion, profileName, _, err := resolveModelFromInstance(c.instanceID)
if err != nil {
- return Config{}, Config{}, "", []helm.KubernetesResource{}, pkgerrors.Wrap(err, "Retrieving model info")
+ return Config{}, Config{}, "", []KubernetesConfigResource{}, pkgerrors.Wrap(err, "Retrieving model info")
}
versionKey := constructKey(rbName, rbVersion, profileName, c.instanceID, tagVersion, configName, strconv.Itoa(int(version)))
configBytes, err := db.Etcd.Get(versionKey)
if err != nil {
- return Config{}, Config{}, "", []helm.KubernetesResource{}, pkgerrors.Wrap(err, "Get Config Version ")
+ return Config{}, Config{}, "", []KubernetesConfigResource{}, pkgerrors.Wrap(err, "Get Config Version ")
}
if configBytes != nil {
pr := configVersionDBContent{}
err = db.DeSerialize(string(configBytes), &pr)
if err != nil {
- return Config{}, Config{}, "", []helm.KubernetesResource{}, pkgerrors.Wrap(err, "DeSerialize Config Version")
+ return Config{}, Config{}, "", []KubernetesConfigResource{}, pkgerrors.Wrap(err, "DeSerialize Config Version")
}
return pr.ConfigNew, pr.ConfigPrev, pr.Action, pr.Resources, nil
}
- return Config{}, Config{}, "", []helm.KubernetesResource{}, pkgerrors.Wrap(err, "Invalid data ")
+ return Config{}, Config{}, "", []KubernetesConfigResource{}, pkgerrors.Wrap(err, "Invalid data ")
}
// Get the counter for the version
@@ -419,6 +427,25 @@ func (c ConfigVersionStore) decrementVersion(configName string) error {
return nil
}
+// Get tag list
+func (c ConfigVersionStore) getTagList(configName string) ([]string, error) {
+ rbName, rbVersion, profileName, _, err := resolveModelFromInstance(c.instanceID)
+ if err != nil {
+ return []string{}, pkgerrors.Wrap(err, "Retrieving model info")
+ }
+ tagKey := constructKey(rbName, rbVersion, profileName, c.instanceID, tagName, configName)
+
+ tagKeyList, err := db.Etcd.GetKeys(tagKey)
+ if err != nil {
+ return []string{}, pkgerrors.Wrap(err, "Config DB Entry Not found")
+ }
+ result := make([]string, 0)
+ for _, tag := range tagKeyList {
+ result = append(result, tag[len(tagKey):len(tag)-1])
+ }
+ return result, nil
+}
+
// Get tag version
func (c ConfigVersionStore) getTagVersion(configName, tagNameValue string) (string, error) {
rbName, rbVersion, profileName, _, err := resolveModelFromInstance(c.instanceID)
@@ -444,28 +471,44 @@ func (c ConfigVersionStore) tagCurrentVersion(configName, tagNameValue string) e
if err != nil {
return pkgerrors.Wrap(err, "Retrieving model info")
}
+ currentConfig, _, _, _, err := c.getConfigVersion(configName, currentVersion)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Retrieving current configuration")
+ }
+
tagKey := constructKey(rbName, rbVersion, profileName, c.instanceID, tagName, configName, tagNameValue)
err = db.Etcd.Put(tagKey, strconv.Itoa(int(currentVersion)))
if err != nil {
return pkgerrors.Wrap(err, "TagIt store DB")
}
+
+ currentConfig.ConfigTag = tagNameValue
+ configValue, err := db.Serialize(currentConfig)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Serialize Config Value")
+ }
+ cfgKey := constructKey(rbName, rbVersion, profileName, c.instanceID, tagConfig, configName)
+ err = db.Etcd.Put(cfgKey, configValue)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Config DB Entry")
+ }
return nil
}
// Apply Config
-func applyConfig(instanceID string, p Config, pChannel chan configResourceList, action string, resources []helm.KubernetesResource) ([]helm.KubernetesResource, error) {
+func applyConfig(instanceID string, p Config, pChannel chan configResourceList, action string, resources []KubernetesConfigResource) ([]KubernetesConfigResource, error) {
rbName, rbVersion, profileName, releaseName, err := resolveModelFromInstance(instanceID)
if err != nil {
- return []helm.KubernetesResource{}, pkgerrors.Wrap(err, "Retrieving model info")
+ return []KubernetesConfigResource{}, pkgerrors.Wrap(err, "Retrieving model info")
}
// Get Template and Resolve the template with values
crl, err := resolve(rbName, rbVersion, profileName, instanceID, p, releaseName)
if err != nil {
- return []helm.KubernetesResource{}, pkgerrors.Wrap(err, "Resolve Config")
+ return []KubernetesConfigResource{}, pkgerrors.Wrap(err, "Resolve Config")
}
- var updatedResources (chan []helm.KubernetesResource) = make(chan []helm.KubernetesResource)
+ var updatedResources (chan []KubernetesConfigResource) = make(chan []KubernetesConfigResource)
crl.action = action
crl.resources = resources
crl.updatedResources = updatedResources
@@ -477,7 +520,7 @@ func applyConfig(instanceID string, p Config, pChannel chan configResourceList,
default:
}
- var resultResources []helm.KubernetesResource = <-updatedResources
+ var resultResources []KubernetesConfigResource = <-updatedResources
return resultResources, nil
}
@@ -492,14 +535,14 @@ func scheduleResources(c chan configResourceList) {
resp, err := ic.Find(data.profile.RBName, data.profile.RBVersion, data.profile.ProfileName, nil)
if (err != nil || len(resp) == 0) && data.action != "STOP" {
log.Println("Error finding a running instance. Retrying later...")
- data.updatedResources <- []helm.KubernetesResource{}
+ data.updatedResources <- []KubernetesConfigResource{}
continue
}
breakThread := false
switch {
- case data.action == "POST":
- log.Printf("[scheduleResources]: POST %v %v", data.profile, data.resourceTemplates)
- var resources []helm.KubernetesResource
+ case data.action == "PUT" || data.action == "POST":
+ log.Printf("[scheduleResources]: %v %v %v", data.action, data.profile, data.resourceTemplates)
+ resources := []KubernetesConfigResource{}
for _, inst := range resp {
k8sClient := KubernetesClient{}
err = k8sClient.Init(inst.Request.CloudRegion, inst.ID)
@@ -508,36 +551,30 @@ func scheduleResources(c chan configResourceList) {
//Move onto the next cloud region
continue
}
- //assuming - the resource is not exist already
- resources, err = k8sClient.createResources(data.resourceTemplates, inst.Namespace)
- errCreate := err
- if err != nil {
- // assuming - the err represent the resource is already exist, so going for update
- resources, err = k8sClient.updateResources(data.resourceTemplates, inst.Namespace)
+ for _, res := range data.resourceTemplates {
+ var resToCreateOrUpdate = []helm.KubernetesResourceTemplate{res}
+ resProceeded, err := k8sClient.createResources(resToCreateOrUpdate, inst.Namespace)
+ errCreate := err
+ var status string = ""
if err != nil {
- log.Printf("Error Creating resources: %s", errCreate.Error())
- log.Printf("Error Updating resources: %s", err.Error())
- continue
+ // assuming - the err represent the resource already exist, so going for update
+ resProceeded, err = k8sClient.updateResources(resToCreateOrUpdate, inst.Namespace)
+ if err != nil {
+ log.Printf("Error Creating resources: %s", errCreate.Error())
+ log.Printf("Error Updating resources: %s", err.Error())
+ break
+ } else {
+ status = "UPDATED"
+ }
+ } else {
+ status = "CREATED"
+ }
+ for _, resCreated := range resProceeded {
+ resource := KubernetesConfigResource{}
+ resource.Resource = resCreated
+ resource.Status = status
+ resources = append(resources, resource)
}
- }
- }
- data.updatedResources <- resources
- case data.action == "PUT":
- log.Printf("[scheduleResources]: PUT %v %v", data.profile, data.resourceTemplates)
- var resources []helm.KubernetesResource
- for _, inst := range resp {
- k8sClient := KubernetesClient{}
- err = k8sClient.Init(inst.Request.CloudRegion, inst.ID)
- if err != nil {
- log.Printf("Getting CloudRegion Information: %s", err.Error())
- //Move onto the next cloud region
- continue
- }
-
- resources, err = k8sClient.updateResources(data.resourceTemplates, inst.Namespace)
- if err != nil {
- log.Printf("Error Updating resources: %s", err.Error())
- continue
}
}
data.updatedResources <- resources
@@ -551,13 +588,17 @@ func scheduleResources(c chan configResourceList) {
//Move onto the next cloud region
continue
}
- err = k8sClient.deleteResources(helm.GetReverseK8sResources(data.resources), inst.Namespace)
+ var tmpResources []helm.KubernetesResource = []helm.KubernetesResource{}
+ for _, res := range data.resources {
+ tmpResources = append(tmpResources, res.Resource)
+ }
+ err = k8sClient.deleteResources(helm.GetReverseK8sResources(tmpResources), inst.Namespace)
if err != nil {
log.Printf("Error Deleting resources: %s", err.Error())
continue
}
}
- data.updatedResources <- []helm.KubernetesResource{}
+ data.updatedResources <- []KubernetesConfigResource{}
case data.action == "STOP":
breakThread = true
@@ -581,17 +622,40 @@ var resolve = func(rbName, rbVersion, profileName, instanceId string, p Config,
return configResourceList{}, pkgerrors.Wrap(err, "Reading Profile Data")
}
- t, err := rb.NewConfigTemplateClient().Get(rbName, rbVersion, p.TemplateName)
- if err != nil {
- return configResourceList{}, pkgerrors.Wrap(err, "Getting Template")
- }
- if t.ChartName == "" {
- return configResourceList{}, pkgerrors.New("Invalid template no Chart.yaml file found")
+ var t rb.ConfigTemplate
+ if p.TemplateName == "" && p.ConfigName == "" {
+ //for rollback to base definition
+ t = rb.ConfigTemplate{}
+ t.HasContent = false
+ } else {
+ t, err = rb.NewConfigTemplateClient().Get(rbName, rbVersion, p.TemplateName)
+ if err != nil {
+ return configResourceList{}, pkgerrors.Wrap(err, "Getting Template")
+ }
+ if t.ChartName == "" {
+ return configResourceList{}, pkgerrors.New("Invalid template no Chart.yaml file found")
+ }
}
- def, err := rb.NewConfigTemplateClient().Download(rbName, rbVersion, p.TemplateName)
- if err != nil {
- return configResourceList{}, pkgerrors.Wrap(err, "Downloading Template")
+ var def []byte
+
+ if t.HasContent {
+ def, err = rb.NewConfigTemplateClient().Download(rbName, rbVersion, p.TemplateName)
+ if err != nil {
+ return configResourceList{}, pkgerrors.Wrap(err, "Downloading Template")
+ }
+ } else {
+ log.Printf("Using Definition Template as a Configuration Template")
+ defClient := rb.NewDefinitionClient()
+ definition, err := defClient.Get(rbName, rbVersion)
+ if err != nil {
+ return configResourceList{}, pkgerrors.Wrap(err, "Get RB Definition")
+ }
+ def, err = defClient.Download(rbName, rbVersion)
+ if err != nil {
+ return configResourceList{}, pkgerrors.Wrap(err, "Downloading RB Definition Template")
+ }
+ t.ChartName = definition.ChartName
}
ic := NewInstanceClient()
@@ -625,8 +689,10 @@ var resolve = func(rbName, rbVersion, profileName, instanceId string, p Config,
return configResourceList{}, pkgerrors.Wrap(err, "Processing values")
}
- for k, v := range p.Values {
- rawValues[k] = v
+ if p.Values != nil {
+ for k, v := range p.Values {
+ rawValues[k] = v
+ }
}
//Create a temp file in the system temp folder for values input
b, err := json.Marshal(rawValues)
diff --git a/src/k8splugin/internal/app/config_test.go b/src/k8splugin/internal/app/config_test.go
index 1aef6656..3b673b86 100644
--- a/src/k8splugin/internal/app/config_test.go
+++ b/src/k8splugin/internal/app/config_test.go
@@ -138,20 +138,23 @@ func TestRollbackConfig(t *testing.T) {
profileName: "testprofile1",
instanceID: "testinstance1",
inp: Config{
- ConfigName: "testconfig1",
- TemplateName: "testtemplate1",
+ ConfigName: "testconfig1",
+ TemplateName: "testtemplate1",
+ ConfigVersion: 1,
Values: map[string]interface{}{
"values": "{\"namespace\": \"kafka\", \"topic\": {\"name\":\"orders\", \"cluster\":\"my-cluster\", \"partitions\": 10,\"replicas\": 2, }}"},
},
inpUpdate1: Config{
- ConfigName: "testconfig1",
- TemplateName: "testtemplate1",
+ ConfigName: "testconfig1",
+ TemplateName: "testtemplate1",
+ ConfigVersion: 2,
Values: map[string]interface{}{
"values": "{\"namespace\": \"kafka\", \"topic\": {\"name\":\"orders\", \"cluster\":\"my-cluster\", \"partitions\": 20,\"replicas\": 2, }}"},
},
inpUpdate2: Config{
- ConfigName: "testconfig1",
- TemplateName: "testtemplate1",
+ ConfigName: "testconfig1",
+ TemplateName: "testtemplate1",
+ ConfigVersion: 3,
Values: map[string]interface{}{
"values": "{\"namespace\": \"kafka\", \"topic\": {\"name\":\"orders\", \"cluster\":\"my-cluster\", \"partitions\": 30,\"replicas\": 2, }}"},
},
@@ -293,7 +296,7 @@ func TestRollbackConfig(t *testing.T) {
}
}
testCase.rollbackConfig.AnyOf.ConfigVersion = "2"
- err = impl.Rollback(testCase.instanceID, testCase.inp.ConfigName, testCase.rollbackConfig)
+ _, err = impl.Rollback(testCase.instanceID, testCase.inp.ConfigName, testCase.rollbackConfig, false)
if err != nil {
if testCase.expectedError == "" {
t.Fatalf("Create returned an unexpected error %s", err)
diff --git a/src/k8splugin/internal/app/query.go b/src/k8splugin/internal/app/query.go
index 251b14e6..6a1b3516 100644
--- a/src/k8splugin/internal/app/query.go
+++ b/src/k8splugin/internal/app/query.go
@@ -19,9 +19,6 @@
package app
import (
- "github.com/onap/multicloud-k8s/src/k8splugin/internal/helm"
- "k8s.io/apimachinery/pkg/runtime/schema"
-
pkgerrors "github.com/pkg/errors"
)
@@ -64,7 +61,7 @@ func (v *QueryClient) Query(namespace, cloudRegion, apiVersion, kind, name, labe
}
var resourcesStatus []ResourceStatus
- if labels != "" {
+ if name != "" {
resList, err := k8sClient.queryResources(apiVersion, kind, labels, namespace)
if err != nil {
return QueryStatus{}, pkgerrors.Wrap(err, "Querying Resources")
@@ -76,22 +73,11 @@ func (v *QueryClient) Query(namespace, cloudRegion, apiVersion, kind, name, labe
for _, res := range resList {
if res.Name == name {
resourcesStatus = append(resourcesStatus, res)
- break
}
}
} else {
resourcesStatus = resList
}
- } else if name != "" {
- resIdentifier := helm.KubernetesResource{
- Name: name,
- GVK: schema.FromAPIVersionAndKind(apiVersion, kind),
- }
- res, err := k8sClient.GetResourceStatus(resIdentifier, namespace)
- if err != nil {
- return QueryStatus{}, pkgerrors.Wrap(err, "Querying Resource")
- }
- resourcesStatus = []ResourceStatus{res}
} else {
resList, err := k8sClient.queryResources(apiVersion, kind, labels, namespace)
if err != nil {
diff --git a/src/k8splugin/internal/db/etcd.go b/src/k8splugin/internal/db/etcd.go
index e455cc1a..5ce8135a 100644
--- a/src/k8splugin/internal/db/etcd.go
+++ b/src/k8splugin/internal/db/etcd.go
@@ -36,7 +36,8 @@ type EtcdConfig struct {
// EtcdStore Interface needed for mocking
type EtcdStore interface {
Get(key string) ([]byte, error)
- GetAll(key string) ([][]byte, error)
+ GetKeys(key string) ([]string, error)
+ GetValues(key string) ([][]byte, error)
Put(key, value string) error
Delete(key string) error
DeletePrefix(keyPrefix string) error
@@ -124,8 +125,24 @@ func (e EtcdClient) Get(key string) ([]byte, error) {
return getResp.Kvs[0].Value, nil
}
-// GetAll sub values from Etcd DB
-func (e EtcdClient) GetAll(key string) ([][]byte, error) {
+// GetKeys sub values from Etcd DB
+func (e EtcdClient) GetKeys(key string) ([]string, error) {
+ if e.cli == nil {
+ return nil, pkgerrors.Errorf("Etcd Client not initialized")
+ }
+ getResp, err := e.cli.Get(context.Background(), key, clientv3.WithPrefix())
+ if err != nil {
+ return nil, pkgerrors.Errorf("Error getting etcd entry: %s", err.Error())
+ }
+ result := make([]string, 0)
+ for _, v := range getResp.Kvs {
+ result = append(result, string(v.Key))
+ }
+ return result, nil
+}
+
+// GetValues sub values from Etcd DB
+func (e EtcdClient) GetValues(key string) ([][]byte, error) {
if e.cli == nil {
return nil, pkgerrors.Errorf("Etcd Client not initialized")
}
diff --git a/src/k8splugin/internal/db/etcd_testing.go b/src/k8splugin/internal/db/etcd_testing.go
index 4b4dfe3e..2f62d365 100644
--- a/src/k8splugin/internal/db/etcd_testing.go
+++ b/src/k8splugin/internal/db/etcd_testing.go
@@ -41,7 +41,17 @@ func (c *MockEtcdClient) Get(key string) ([]byte, error) {
return nil, pkgerrors.Errorf("Key doesn't exist")
}
-func (c *MockEtcdClient) GetAll(key string) ([][]byte, error) {
+func (c *MockEtcdClient) GetKeys(key string) ([]string, error) {
+ result := make([]string, 0)
+ for kvKey := range c.Items {
+ if strings.HasPrefix(kvKey, key) {
+ result = append(result, kvKey)
+ }
+ }
+ return result, nil
+}
+
+func (c *MockEtcdClient) GetValues(key string) ([][]byte, error) {
result := make([][]byte, 0)
for kvKey, kvValue := range c.Items {
if strings.HasPrefix(kvKey, key) {
diff --git a/src/k8splugin/internal/rb/config_template.go b/src/k8splugin/internal/rb/config_template.go
index 97fe0fb4..06576e5d 100644
--- a/src/k8splugin/internal/rb/config_template.go
+++ b/src/k8splugin/internal/rb/config_template.go
@@ -36,14 +36,20 @@ import (
type ConfigTemplate struct {
TemplateName string `json:"template-name"`
Description string `json:"description"`
- ChartName string
+ ChartName string `json:"chart-name"`
+ HasContent bool `json:"has-content"`
+}
+
+type ConfigTemplateList struct {
+ TemplateName string `json:"template-name"`
+ Description string `json:"description"`
}
// ConfigTemplateManager is an interface exposes the resource bundle ConfigTemplate functionality
type ConfigTemplateManager interface {
CreateOrUpdate(rbName, rbVersion string, p ConfigTemplate, update bool) error
Get(rbName, rbVersion, templateName string) (ConfigTemplate, error)
- List(rbName, rbVersion string) ([]ConfigTemplate, error)
+ List(rbName, rbVersion string) ([]ConfigTemplateList, error)
Delete(rbName, rbVersion, templateName string) error
Upload(rbName, rbVersion, templateName string, inp []byte) error
}
@@ -94,7 +100,7 @@ func (v *ConfigTemplateClient) CreateOrUpdate(rbName, rbVersion string, p Config
}
//Check if ConfigTemplate already exists
- _, err := v.Get(rbName, rbVersion, p.TemplateName)
+ prev, err := v.Get(rbName, rbVersion, p.TemplateName)
if err == nil && !update {
return pkgerrors.New(" ConfigTemplate already exists for this Definition")
}
@@ -103,7 +109,7 @@ func (v *ConfigTemplateClient) CreateOrUpdate(rbName, rbVersion string, p Config
}
//Check if provided resource bundle information is valid
- _, err = NewDefinitionClient().Get(rbName, rbVersion)
+ rbDef, err := NewDefinitionClient().Get(rbName, rbVersion)
if err != nil {
return pkgerrors.Errorf("Invalid Resource Bundle ID provided: %s", err.Error())
}
@@ -115,11 +121,15 @@ func (v *ConfigTemplateClient) CreateOrUpdate(rbName, rbVersion string, p Config
}
if update {
+ p.ChartName = prev.ChartName
+ p.HasContent = prev.HasContent
err = db.DBconn.Update(v.storeName, key, v.tagMeta, p)
if err != nil {
return pkgerrors.Wrap(err, "Updating ConfigTemplate DB Entry")
}
} else {
+ p.ChartName = rbDef.ChartName
+ p.HasContent = false
err = db.DBconn.Create(v.storeName, key, v.tagMeta, p)
if err != nil {
return pkgerrors.Wrap(err, "Creating ConfigTemplate DB Entry")
@@ -155,19 +165,19 @@ func (v *ConfigTemplateClient) Get(rbName, rbVersion, templateName string) (Conf
}
// List returns the Resource Bundle ConfigTemplate for corresponding ID
-func (v *ConfigTemplateClient) List(rbName, rbVersion string) ([]ConfigTemplate, error) {
+func (v *ConfigTemplateClient) List(rbName, rbVersion string) ([]ConfigTemplateList, error) {
//Get all config templates
dbres, err := db.DBconn.ReadAll(v.storeName, v.tagMeta)
if err != nil || len(dbres) == 0 {
- return []ConfigTemplate{}, pkgerrors.Wrap(err, "No Config Templates Found")
+ return []ConfigTemplateList{}, pkgerrors.Wrap(err, "No Config Templates Found")
}
- var results []ConfigTemplate
+ var results []ConfigTemplateList
for key, value := range dbres {
//value is a byte array
if value != nil {
- tmp := ConfigTemplate{}
+ tmp := ConfigTemplateList{}
err = db.DBconn.Unmarshal(value, &tmp)
if err != nil {
log.Printf("[ConfigTemplate] Error: %s Unmarshaling value for: %s", err.Error(), key)
@@ -267,6 +277,11 @@ func (v *ConfigTemplateClient) Upload(rbName, rbVersion, templateName string, in
if err != nil {
return pkgerrors.Errorf("Error uploading data to db %s", err.Error())
}
+ t.HasContent = true
+ err = db.DBconn.Update(v.storeName, key, v.tagMeta, t)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Updating ConfigTemplate DB Entry")
+ }
return nil
}