Skip to content

Commit

Permalink
Getting image metadata in case of cp down (#237)
Browse files Browse the repository at this point in the history
* getting image metadata in case of cp down
* getting image metadata refactor

Signed-off-by: Peter Balogh <[email protected]>
  • Loading branch information
pbalogh-sa authored Apr 29, 2020
1 parent fe37208 commit ed06aef
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 144 deletions.
31 changes: 11 additions & 20 deletions internal/cli/command/controlplane/down.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"emperror.dev/errors"
"github.com/AlecAivazis/survey/v2"
"github.com/banzaicloud/banzai-cli/internal/cli"
"github.com/banzaicloud/banzai-cli/internal/cli/input"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -75,29 +74,27 @@ func runDestroy(options destroyOptions, banzaiCli cli.Cli) error {
}
}

awsAccessKeyID, env, err := getImageMetadata(options.cpContext, values, false)
if err != nil {
return err
}

// TODO: check if there are any clusters are created with the pipeline instance

log.Info("controlplane is being destroyed")
var env map[string]string
switch values["provider"] {
case providerEc2:
id, creds, err := input.GetAmazonCredentials()
if err != nil {
return errors.WrapIf(err, "failed to get AWS credentials")
}

if valuesConfig, ok := values["providerConfig"]; ok {
if valuesConfig, ok := valuesConfig.(map[string]interface{}); ok {
if ak := valuesConfig["accessKey"]; ak != "" {
if ak != id {
return errors.Errorf("Current AWS access key %q differs from the one used earlier: %q", ak, id)
if ak != awsAccessKeyID {
return errors.Errorf("Current AWS access key %q differs from the one used earlier: %q", ak, awsAccessKeyID)
}
}
}
}
env = creds

err = deleteEC2Cluster(options.cpContext, env)
err := deleteEC2Cluster(options.cpContext, env)
if err != nil {
return errors.WrapIf(err, "EC2 cluster destroy failed")
}
Expand All @@ -120,24 +117,18 @@ func runDestroy(options destroyOptions, banzaiCli cli.Cli) error {
}

case providerCustom:
creds := map[string]string{}
if pc, ok := values["providerConfig"]; ok {
pc := cast.ToStringMap(pc)
if _, ok := pc["accessKey"]; ok {
id, awsCreds, err := input.GetAmazonCredentials()
if err != nil {
return errors.WrapIf(err, "failed to get AWS credentials")
}
if ak := pc["accessKey"]; ak != "" {
if ak != id {
return errors.Errorf("Current AWS access key %q differs from the one used earlier: %q", ak, id)
if ak != awsAccessKeyID {
return errors.Errorf("Current AWS access key %q differs from the one used earlier: %q", ak, awsAccessKeyID)
}
}
creds = awsCreds
}
}

if err := deleteCustomCluster(options.cpContext, creds); err != nil {
if err := deleteCustomCluster(options.cpContext, env); err != nil {
return errors.WrapIf(err, "Custom Kubernetes cluster destroy failed")
}

Expand Down
125 changes: 2 additions & 123 deletions internal/cli/command/controlplane/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,20 @@
package controlplane

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"os"
"os/exec"
"path/filepath"
"strings"

"emperror.dev/errors"
"github.com/AlecAivazis/survey/v2"
"github.com/google/uuid"
"github.com/imdario/mergo"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"

"github.com/banzaicloud/banzai-cli/internal/cli"
"github.com/banzaicloud/banzai-cli/internal/cli/command/login"
"github.com/banzaicloud/banzai-cli/internal/cli/input"
)

const (
Expand Down Expand Up @@ -131,38 +124,11 @@ func runUp(options *createOptions, banzaiCli cli.Cli) error {
return errors.New("workspace is already initialized but a different --provider is specified")
}

var defaultValues map[string]interface{}
exportHandlers := []ExportedFilesHandler{
defaultValuesExporter("export/values.yaml", &defaultValues),
}

var imageMeta ImageMetadata
if values["provider"] == providerCustom {
log.Debug("parsing metadata")
exportHandlers = append(exportHandlers, metadataExporter(metadataFile, &imageMeta))
}

if err := processExports(options.cpContext, exportPath, exportHandlers); err != nil {
return err
}

log.Debugf("custom image metadata: %+v", imageMeta)

if err := writeMergedValues(options.cpContext, defaultValues, values); err != nil {
_, env, err := getImageMetadata(options.cpContext, values, true)
if err != nil {
return err
}

env := make(map[string]string)

if values["provider"] == providerEc2 || imageMeta.Custom.CredentialType == "aws" {
log.Debug("using local AWS credentials")
_, creds, err := input.GetAmazonCredentials()
if err != nil {
return errors.WrapIf(err, "failed to get AWS credentials")
}
env = creds
}

if options.terraformInit {
if err := initStateBackend(options.cpContext, values, env); err != nil {
return errors.WrapIf(err, "failed to initialize state backend")
Expand Down Expand Up @@ -269,82 +235,6 @@ func postInstall(options *createOptions, banzaiCli cli.Cli, values map[string]in
return nil
}

type ExportedFilesHandler func(map[string][]byte) error

func processExports(options *cpContext, source string, exportedFilesHandlers []ExportedFilesHandler) error {
files, err := readFilesFromContainerToMemory(options, source)
if err != nil {
return errors.WrapIf(err, "failed to export files from the image")
}

for _, h := range exportedFilesHandlers {
if err := h(files); err != nil {
return errors.WrapIf(err, "failed to run handler on exported files")
}
}
return nil
}

func writeMergedValues(options *cpContext, defaultValues, overrideValues map[string]interface{}) error {
var mergedValues map[string]interface{}
if err := mergeValues(&mergedValues, defaultValues, overrideValues); err != nil {
return err
}
bytes, err := yaml.Marshal(&mergedValues)
if err != nil {
return errors.Wrap(err, "failed to marshal merged values")
}
if err := ioutil.WriteFile(filepath.Join(options.workspace, generatedValuesFileName), bytes, 0600); err != nil {
return errors.Wrap(err, "failed to write out generated values file")
}
return nil
}

func mergeValues(mergedValues *map[string]interface{}, defaultValues, overrideValues map[string]interface{}) error {
if err := mergo.Merge(mergedValues, &defaultValues, mergo.WithOverride); err != nil {
return errors.Wrap(err, "failed to process default values in the image")
}
if err := mergo.Merge(mergedValues, &overrideValues, mergo.WithOverride); err != nil {
return errors.Wrap(err, "failed to merge override values from the workspace on top of default values in the image")
}
return nil
}

func imageFileExists(options *cpContext, source string) (bool, error) {
errorMsg := &bytes.Buffer{}
cmdOpt := func(cmd *exec.Cmd) error {
cmd.Stderr = errorMsg
return nil
}
if err := runContainerCommandGeneric(options, []string{"ls", source}, nil, cmdOpt); err != nil {
if strings.Contains(errorMsg.String(), "No such file or directory") {
return false, nil
}
return false, err
} else {
return true, nil
}
}

func stringifyMap(m interface{}) interface{} {
switch v := m.(type) {
case map[string]interface{}:
out := make(map[string]interface{})
for k, v := range v {
out[k] = stringifyMap(v)
}
return out
case map[interface{}]interface{}:
out := make(map[string]interface{})
for k, v := range v {
out[fmt.Sprint(k)] = stringifyMap(v)
}
return out
default:
return v
}
}

func initStateBackend(options *cpContext, values map[string]interface{}, env map[string]string) error {
var stateData []byte

Expand Down Expand Up @@ -385,14 +275,3 @@ func initStateBackend(options *cpContext, values map[string]interface{}, env map

return nil
}

func defaultValuesExporter(source string, defaultValues *map[string]interface{}) ExportedFilesHandler {
return ExportedFilesHandler(func(files map[string][]byte) error {
if valuesFileContent, ok := files[source]; ok {
if err := yaml.Unmarshal(valuesFileContent, defaultValues); err != nil {
return errors.Wrap(err, "failed to unmarshal default values exported from the image")
}
}
return nil
})
}
141 changes: 140 additions & 1 deletion internal/cli/command/controlplane/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,21 @@

package controlplane

import "os"
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"

"emperror.dev/errors"
"github.com/banzaicloud/banzai-cli/internal/cli/input"
"github.com/imdario/mergo"
log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v2"
)

func fileExists(filename string) bool {
info, err := os.Stat(filename)
Expand All @@ -24,3 +38,128 @@ func fileExists(filename string) bool {

return !info.IsDir()
}

type ExportedFilesHandler func(map[string][]byte) error

func processExports(options *cpContext, source string, exportedFilesHandlers []ExportedFilesHandler) error {
files, err := readFilesFromContainerToMemory(options, source)
if err != nil {
return errors.WrapIf(err, "failed to export files from the image")
}

for _, h := range exportedFilesHandlers {
if err := h(files); err != nil {
return errors.WrapIf(err, "failed to run handler on exported files")
}
}
return nil
}

func writeMergedValues(options *cpContext, defaultValues, overrideValues map[string]interface{}) error {
var mergedValues map[string]interface{}
if err := mergeValues(&mergedValues, defaultValues, overrideValues); err != nil {
return err
}
bytes, err := yaml.Marshal(&mergedValues)
if err != nil {
return errors.Wrap(err, "failed to marshal merged values")
}
if err := ioutil.WriteFile(filepath.Join(options.workspace, generatedValuesFileName), bytes, 0600); err != nil {
return errors.Wrap(err, "failed to write out generated values file")
}
return nil
}

func mergeValues(mergedValues *map[string]interface{}, defaultValues, overrideValues map[string]interface{}) error {
if err := mergo.Merge(mergedValues, &defaultValues, mergo.WithOverride); err != nil {
return errors.Wrap(err, "failed to process default values in the image")
}
if err := mergo.Merge(mergedValues, &overrideValues, mergo.WithOverride); err != nil {
return errors.Wrap(err, "failed to merge override values from the workspace on top of default values in the image")
}
return nil
}

func imageFileExists(options *cpContext, source string) (bool, error) {
errorMsg := &bytes.Buffer{}
cmdOpt := func(cmd *exec.Cmd) error {
cmd.Stderr = errorMsg
return nil
}
if err := runContainerCommandGeneric(options, []string{"ls", source}, nil, cmdOpt); err != nil {
if strings.Contains(errorMsg.String(), "No such file or directory") {
return false, nil
}
return false, err
} else {
return true, nil
}
}

func stringifyMap(m interface{}) interface{} {
switch v := m.(type) {
case map[string]interface{}:
out := make(map[string]interface{})
for k, v := range v {
out[k] = stringifyMap(v)
}
return out
case map[interface{}]interface{}:
out := make(map[string]interface{})
for k, v := range v {
out[fmt.Sprint(k)] = stringifyMap(v)
}
return out
default:
return v
}
}

func defaultValuesExporter(source string, defaultValues *map[string]interface{}) ExportedFilesHandler {
return ExportedFilesHandler(func(files map[string][]byte) error {
if valuesFileContent, ok := files[source]; ok {
if err := yaml.Unmarshal(valuesFileContent, defaultValues); err != nil {
return errors.Wrap(err, "failed to unmarshal default values exported from the image")
}
}
return nil
})
}

func getImageMetadata(cpContext *cpContext, values map[string]interface{}, writeValues bool) (string, map[string]string, error) {
var defaultValues map[string]interface{}
exportHandlers := []ExportedFilesHandler{
defaultValuesExporter("export/values.yaml", &defaultValues),
}

env := make(map[string]string)
var imageMeta ImageMetadata
if values["provider"] == providerCustom {
log.Debug("parsing metadata")
exportHandlers = append(exportHandlers, metadataExporter(metadataFile, &imageMeta))
}

if err := processExports(cpContext, exportPath, exportHandlers); err != nil {
return "", env, err
}

log.Debugf("custom image metadata: %+v", imageMeta)

if writeValues {
if err := writeMergedValues(cpContext, defaultValues, values); err != nil {
return "", env, err
}
}

awsAccessKeyID := ""
if values["provider"] == providerEc2 || imageMeta.Custom.CredentialType == "aws" {
log.Debug("using local AWS credentials")
id, creds, err := input.GetAmazonCredentials()
if err != nil {
return "", env, errors.WrapIf(err, "failed to get AWS credentials")
}
env = creds
awsAccessKeyID = id
}
return awsAccessKeyID, env, nil
}

0 comments on commit ed06aef

Please sign in to comment.