Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: perform early exit when no values file is given for vcluster < v0.20 #1686

Merged
merged 2 commits into from
Apr 16, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 88 additions & 27 deletions cmd/vclusterctl/cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ import (
"strings"
"time"

"github.com/ghodss/yaml"
"github.com/loft-sh/log/survey"
"github.com/loft-sh/log/terminal"
"github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/app/localkubernetes"
"github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/find"
"github.com/loft-sh/vcluster/config"
"github.com/loft-sh/vcluster/pkg/config/legacyconfig"
"github.com/loft-sh/vcluster/pkg/embed"
"github.com/loft-sh/vcluster/pkg/util/cliconfig"
"github.com/loft-sh/vcluster/pkg/util/clihelper"
Expand Down Expand Up @@ -179,6 +181,49 @@ func (cmd *CreateCmd) Run(ctx context.Context, args []string) error {
return err
}

err = cmd.prepare(ctx, args[0])
if err != nil {
return err
}

release, err := helm.NewSecrets(cmd.kubeClient).Get(ctx, args[0], cmd.Namespace)
if err != nil && !kerrors.IsNotFound(err) {
return errors.Wrap(err, "get current helm release")
}

// check if vcluster already exists
if !cmd.Upgrade {
if isVClusterDeployed(release) {
if cmd.Connect {
connectCmd := &ConnectCmd{
GlobalFlags: cmd.GlobalFlags,
UpdateCurrent: cmd.UpdateCurrent,
KubeConfigContextName: cmd.KubeConfigContextName,
KubeConfig: "./kubeconfig.yaml",
Log: cmd.log,
}

return connectCmd.Connect(ctx, args[0], nil)
}

return fmt.Errorf("vcluster %s already exists in namespace %s\n- Use `vcluster create %s -n %s --upgrade` to upgrade the vcluster\n- Use `vcluster connect %s -n %s` to access the vcluster", args[0], cmd.Namespace, args[0], cmd.Namespace, args[0], cmd.Namespace)
}
}

// TODO Delete after vCluster 0.19.x resp. the old config format is out of support.
if isVClusterDeployed(release) {
migratedValues, err := migrateLegacyHelmValues(release)
if err != nil {
return err
}

// we do not simply upgrade a vcluster without providing a values.yaml file when it is running with a previous release, as this might result in a distro/backingstore switch.
if len(cmd.Values) <= 0 && migratedValues != "" {
return fmt.Errorf("abort upgrade: no values files were provided while the current virtual cluster is running with an old values format (< v0.20)\nConsider updating your config values to the following new v0.20 format:\n\n%s", migratedValues)
}
}
// TODO end

var newExtraValues []string
for _, value := range cmd.Values {
decodedString, err := getBase64DecodedString(value)
Expand Down Expand Up @@ -223,7 +268,7 @@ func (cmd *CreateCmd) Run(ctx context.Context, args []string) error {
err = cfg.DecodeYAML(f)
if err != nil {
if errors.Is(err, config.ErrInvalidFileFormat) {
cmd.log.Infof("If you are using the old values format, consider using %q to convert it to the new 0.20 format", "vcluster migrate values")
cmd.log.Infof("If you are using the old values format, consider using %q to convert it to the new v0.20 format", "vcluster migrate values")
}
return err
}
Expand All @@ -232,11 +277,8 @@ func (cmd *CreateCmd) Run(ctx context.Context, args []string) error {
cmd.log.Warnf("In order to use a Pro feature, please contact us at https://www.vcluster.com/pro-demo or downgrade by running `vcluster upgrade --version v0.19.5`")
os.Exit(0)
}
}

err = cmd.prepare(ctx, args[0])
if err != nil {
return err
// TODO(johannesfrey): We would also need to validate here if the user is about to perform changes which would lead to distro/store changes
}

// resetting this as the base64 encoded strings should be removed and only valid file names should be kept.
Expand All @@ -258,28 +300,6 @@ func (cmd *CreateCmd) Run(ctx context.Context, args []string) error {
return err
}

// check if vcluster already exists
if !cmd.Upgrade {
release, err := helm.NewSecrets(cmd.kubeClient).Get(ctx, args[0], cmd.Namespace)
if err != nil && !kerrors.IsNotFound(err) {
return errors.Wrap(err, "get helm releases")
} else if release != nil && release.Chart != nil && release.Chart.Metadata != nil && (release.Chart.Metadata.Name == "vcluster" || release.Chart.Metadata.Name == "vcluster-k0s" || release.Chart.Metadata.Name == "vcluster-k8s") && release.Secret != nil && release.Secret.Labels != nil && release.Secret.Labels["status"] == "deployed" {
if cmd.Connect {
connectCmd := &ConnectCmd{
GlobalFlags: cmd.GlobalFlags,
UpdateCurrent: cmd.UpdateCurrent,
KubeConfigContextName: cmd.KubeConfigContextName,
KubeConfig: "./kubeconfig.yaml",
Log: cmd.log,
}

return connectCmd.Connect(ctx, args[0], nil)
}

return fmt.Errorf("vcluster %s already exists in namespace %s\n- Use `vcluster create %s -n %s --upgrade` to upgrade the vcluster\n- Use `vcluster connect %s -n %s` to access the vcluster", args[0], cmd.Namespace, args[0], cmd.Namespace, args[0], cmd.Namespace)
}
}

// we have to upgrade / install the chart
err = cmd.deployChart(ctx, args[0], chartValues, helmBinaryPath)
if err != nil {
Expand Down Expand Up @@ -309,6 +329,47 @@ func (cmd *CreateCmd) Run(ctx context.Context, args []string) error {
return nil
}

func isVClusterDeployed(release *helm.Release) bool {
return release != nil &&
release.Chart != nil &&
release.Chart.Metadata != nil &&
(release.Chart.Metadata.Name == "vcluster" || release.Chart.Metadata.Name == "vcluster-k0s" ||
release.Chart.Metadata.Name == "vcluster-k8s" || release.Chart.Metadata.Name == "vcluster-eks") &&
release.Secret != nil &&
release.Secret.Labels != nil &&
release.Secret.Labels["status"] == "deployed"
}

// TODO Delete after vCluster 0.19.x resp. the old config format is out of support.
// migratelegacyHelmValues migrates the values of the current vCluster to the new config format.
// Only returns a non-empty string if the passed in release is < v0.20.0.
func migrateLegacyHelmValues(release *helm.Release) (string, error) {
if semver.Compare(release.Chart.Metadata.Version, "v0.20.0-alpha.0") != -1 {
// No need to migrate new releases.
return "", nil
}

// If we are upgrading a vCluster < 0.20 the old k3s chart is the one without a prefix.
distro := strings.TrimPrefix(release.Chart.Metadata.Name, "vcluster-")
if distro == "vcluster" {
distro = "k3s"
}

cfg := release.Config
y, err := yaml.Marshal(cfg)
if err != nil {
return "", err
}
migratedValues, err := legacyconfig.MigrateLegacyConfig(distro, string(y))
if err != nil {
return "", err
}

return migratedValues, nil
}

// TODO end

func getBase64DecodedString(values string) (string, error) {
strDecoded, err := base64.StdEncoding.DecodeString(values)
if err != nil {
Expand Down
Loading