Skip to content

Commit

Permalink
Bug 1625751 - Use uuids for service_instance labels (#128)
Browse files Browse the repository at this point in the history
Add support for tracking of provisioned service instances, and provide a friendlier deprovision experience by allowing a user to select one of several provisioned instances from a list.

* Bug 1625751 - Use uuids for service_instance labels

* Updates for depro fix

* Updates for deprovision

* Remove debug statement

* Add updates for namespace scoped instances

* Typo
  • Loading branch information
dymurray authored and djwhatle committed Jan 4, 2019
1 parent fe145a1 commit d3d5493
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 7 deletions.
80 changes: 80 additions & 0 deletions cmd/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"os"
"path/filepath"
"regexp"
"strings"
"time"

"github.com/automationbroker/apb/pkg/config"
Expand Down Expand Up @@ -249,6 +250,23 @@ func executeBundle(action string, args []string) (podName string) {
log.Errorf("Failed to execute bundle [%v]: %v", args[0], err)
return ""
}
id := strings.Split(pn, "bundle-")[1]
id = strings.TrimPrefix(id, "provision-")
id = strings.TrimPrefix(id, "deprovision-")
switch action {
case "provision":
// Add instance to ProvisionedInstances
err = addInstance(args[0], bundleNamespace, id)
if err != nil {
log.Errorf("Failed to add instance ID to list of provisioned instances")
}
case "deprovision":
// Remove instance from ProvisionedInstances
err = removeInstance(args[0], bundleNamespace, id)
if err != nil {
log.Errorf("Failed to remove instance ID from list of provisioned instances")
}
}
return pn
}

Expand Down Expand Up @@ -479,3 +497,65 @@ func processLineBreaks(text []byte, lineBreakText []byte, breakAfter int) []byte
}
return newText
}

func addInstance(name, namespace, id string) error {
var instanceConfigs []config.ProvisionedInstance
err := config.ProvisionedInstances.UnmarshalKey("ProvisionedInstances", &instanceConfigs)
if err != nil {
return err
}

for i, instance := range instanceConfigs {
if instance.BundleName == name {
log.Debugf("Adding instance")
instanceConfigs[i].InstanceIDs[namespace] = append(instance.InstanceIDs[namespace], id)
err = config.UpdateCachedInstances(config.ProvisionedInstances, instanceConfigs)
if err != nil {
return err
}
return nil
}
}

idMap := make(map[string][]string)
idMap[namespace] = []string{id}
instance := config.ProvisionedInstance{
BundleName: name,
InstanceIDs: idMap,
}

instanceConfigs = append(instanceConfigs, instance)
err = config.UpdateCachedInstances(config.ProvisionedInstances, instanceConfigs)
if err != nil {
return err
}
return nil
}

func removeInstance(name, namespace, id string) error {
var instanceConfigs []config.ProvisionedInstance
var foundBundle = false
err := config.ProvisionedInstances.UnmarshalKey("ProvisionedInstances", &instanceConfigs)
if err != nil {
return err
}
for i, instance := range instanceConfigs {
if instance.BundleName == name {
foundBundle = true
for j, instanceID := range instance.InstanceIDs[namespace] {
if instanceID == id {
// Remove instance
instanceConfigs[i].InstanceIDs[namespace] = append(instance.InstanceIDs[namespace][:j], instance.InstanceIDs[namespace][j+1:]...)
err = config.UpdateCachedInstances(config.ProvisionedInstances, instanceConfigs)
if err != nil {
return err
}
}
}
}
}
if foundBundle == false {
log.Errorf("Found no provisioned instances of [%v]", name)
}
return nil
}
2 changes: 2 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ func initConfig() {

// Load or create registries.json
config.Registries, _ = config.InitJSONConfig(cfgDir, "registries")
// Load or create instances.json
config.ProvisionedInstances, _ = config.InitJSONConfig(cfgDir, "instances")
// Load or create defaults.json
config.Defaults, isNewDefaultsConfig = config.InitJSONConfig(cfgDir, "defaults")
if isNewDefaultsConfig {
Expand Down
23 changes: 21 additions & 2 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ var LoadedDefaults DefaultSettings
// Registries stores APB registry and spec data
var Registries *viper.Viper

// ProvisionedInstances stores APB instances
var ProvisionedInstances *viper.Viper

// InitJSONConfig will load (or create if needed) a JSON config at ~/home/.apb/configName.json or configDir/configName.json
func InitJSONConfig(configDir string, configName string) (config *viper.Viper, isNewConfig bool) {
var configPath string
Expand Down Expand Up @@ -70,17 +73,33 @@ func InitJSONConfig(configDir string, configName string) (config *viper.Viper, i
return viperConfig, isNewConfig
}

// UpdateCachedInstances saves the contents of instanceList to a configuration file
func UpdateCachedInstances(viperConfig *viper.Viper, instanceList []ProvisionedInstance) error {
viperConfig.Set("ProvisionedInstances", instanceList)
err := viperConfig.WriteConfig()
if err != nil {
return err
}
return nil
}

// UpdateCachedRegistries saves the contents of regList to a configuration file
func UpdateCachedRegistries(viperConfig *viper.Viper, regList []Registry) error {
viperConfig.Set("Registries", regList)
viperConfig.WriteConfig()
err := viperConfig.WriteConfig()
if err != nil {
return err
}
return nil
}

// UpdateCachedDefaults saves the contents of defaults to a configuration file
func UpdateCachedDefaults(viperConfig *viper.Viper, defaults *DefaultSettings) error {
viperConfig.Set("Defaults", defaults)
viperConfig.WriteConfig()
err := viperConfig.WriteConfig()
if err != nil {
return err
}
return nil
}

Expand Down
6 changes: 6 additions & 0 deletions pkg/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import (
"github.com/automationbroker/bundle-lib/registries"
)

// ProvisionedInstance stores a list of provisioned uuids associated with a bundle
type ProvisionedInstance struct {
BundleName string
InstanceIDs map[string][]string
}

// Registry stores a single registry config and references all associated bundle specs
type Registry struct {
Config registries.Config
Expand Down
65 changes: 60 additions & 5 deletions pkg/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,20 @@ import (
// RunBundle will run the bundle's action in the given namespace
func RunBundle(action string, ns string, bundleName string, sandboxRole string, bundleRegistry string, printLogs bool, skipParams bool, args []string) (podName string, err error) {
reg := []config.Registry{}
var id string
var targetSpec *bundle.Spec
var candidateSpecs []*bundle.Spec
podName = fmt.Sprintf("bundle-%s", uuid.New())

if action == "deprovision" {
id, err = getProvisionedInstanceId(bundleName, ns)
if err != nil {
return "", err
}
} else {
id = uuid.New()
}

podName = fmt.Sprintf("bundle-%s-%s", action, id)
config.Registries.UnmarshalKey("Registries", &reg)
for _, r := range reg {
if len(bundleRegistry) > 0 && r.Config.Name != bundleRegistry {
Expand Down Expand Up @@ -88,7 +99,7 @@ func RunBundle(action string, ns string, bundleName string, sandboxRole string,
}
}

extraVars, err := createExtraVars(ns, &params, plan)
extraVars, err := createExtraVars(id, ns, &params, plan)
if err != nil {
return "", err
}
Expand All @@ -107,6 +118,7 @@ func RunBundle(action string, ns string, bundleName string, sandboxRole string,
serviceAccount, namespace, err := runtime.Provider.CreateSandbox(podName, ns, targets, sandboxRole, labels)
if err != nil {
fmt.Printf("\nProblem creating sandbox [%s] to run APB. Did you run `oc new-project %s` first?\n\n", podName, ns)
log.Errorf("error creating sandbox: %v", err)
os.Exit(-1)
}

Expand Down Expand Up @@ -343,7 +355,7 @@ func createPodEnv(executionContext runtime.ExecutionContext) []v1.EnvVar {
return podEnv
}

func createExtraVars(targetNamespace string, parameters *bundle.Parameters, plan bundle.Plan) (string, error) {
func createExtraVars(id string, targetNamespace string, parameters *bundle.Parameters, plan bundle.Plan) (string, error) {
var paramsCopy bundle.Parameters
if parameters != nil && *parameters != nil {
paramsCopy = *parameters
Expand All @@ -357,8 +369,8 @@ func createExtraVars(targetNamespace string, parameters *bundle.Parameters, plan

paramsCopy["cluster"] = "openshift"
paramsCopy["_apb_plan_id"] = plan.Name
paramsCopy["_apb_service_instance_id"] = "1234"
paramsCopy["_apb_service_class_id"] = "1234"
paramsCopy["_apb_service_instance_id"] = id
paramsCopy["_apb_service_class_id"] = id
extraVars, err := json.Marshal(paramsCopy)
return string(extraVars), err
}
Expand Down Expand Up @@ -400,3 +412,46 @@ func contains(s []string, t string) bool {
}
return false
}

func getProvisionedInstanceId(name, namespace string) (string, error) {
var instanceConfigs []config.ProvisionedInstance
err := config.ProvisionedInstances.UnmarshalKey("ProvisionedInstances", &instanceConfigs)
if err != nil {
return "", err
}
for _, instance := range instanceConfigs {
if instance.BundleName == name {
if len(instance.InstanceIDs[namespace]) == 1 {
return instance.InstanceIDs[namespace][0], nil
} else if len(instance.InstanceIDs[namespace]) == 0 {
return "", fmt.Errorf("found no available instances in namespace [%v]", namespace)
} else {
// Select instance
fmt.Printf("Found more than one service instance for bundle [%v]:\n", name)
for i, instance := range instance.InstanceIDs[namespace] {
fmt.Printf("[%v] - %v\n", i, instance)
}
var inputValid = false
for !inputValid {
var input string
fmt.Printf("Enter the number of the instance ID you would wish to deprovision: ")
fmt.Scanln(&input)
if input == "" {
continue
}
intInput, err := strconv.Atoi(input)
if err != nil {
fmt.Printf("Input was not a valid integer, please enter again.\n")
continue
}
if intInput >= len(instance.InstanceIDs[namespace]) || intInput < 0 {
fmt.Printf("Input is out of range. Please select an integer from 0-%v\n", len(instance.InstanceIDs[namespace])-1)
continue
}
return instance.InstanceIDs[namespace][intInput], nil
}
}
}
}
return "", fmt.Errorf("No provisioned instances for bundle [%v] in namespace [%v]", name, namespace)
}

0 comments on commit d3d5493

Please sign in to comment.