From 76b908db43d3417b846ac0128625e3a04247637b Mon Sep 17 00:00:00 2001 From: Yuwen Ma Date: Tue, 10 Aug 2021 12:49:07 -0700 Subject: [PATCH] [v2] Improve user experience on specifying inventory in kpt v2 deployer. (#6397) --- pkg/skaffold/deploy/v2/kpt/errors.go | 2 +- pkg/skaffold/deploy/v2/kpt/kpt.go | 45 ++++++++++++++++--------- pkg/skaffold/schema/latest/v2/config.go | 8 ++++- pkg/skaffold/schema/v3alpha1/config.go | 13 ++++--- 4 files changed, 47 insertions(+), 21 deletions(-) diff --git a/pkg/skaffold/deploy/v2/kpt/errors.go b/pkg/skaffold/deploy/v2/kpt/errors.go index f663e888889..7b6b0f961b7 100644 --- a/pkg/skaffold/deploy/v2/kpt/errors.go +++ b/pkg/skaffold/deploy/v2/kpt/errors.go @@ -86,7 +86,7 @@ func liveApplyErr(err error, path string) error { Action: fmt.Sprintln("if you encounter an inventory mismatch (or can't adopt) error, it indicates " + "the manifests have been deployed before and may not be properly cleaned up. We provide two solutions:\n " + "#1: Update your skaffold.yaml by adding the `--inventory-policy=adopt` in the " + - "`.deploy.kpt.flags`. This will override the resources' inventory.\n " + + "`.deploy.kpt.applyFlags`. This will override the resources' inventory.\n " + "#2: Find the existing inventory from your cluster resource's annotation \"cli-utils.sigs.k8s.io/inventory-id\", " + " then use this inventory-id to look for the inventory name and namespace by running " + "`kubectl get resourcegroups.kpt.dev -oyaml | grep -C20 | grep \"name: inventory-\" -C1` " + diff --git a/pkg/skaffold/deploy/v2/kpt/kpt.go b/pkg/skaffold/deploy/v2/kpt/kpt.go index bf27dbb659d..b2be8252f24 100644 --- a/pkg/skaffold/deploy/v2/kpt/kpt.go +++ b/pkg/skaffold/deploy/v2/kpt/kpt.go @@ -49,7 +49,10 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" ) -const deployerName = "kptV2" +const ( + deployerName = "kptV2" + defaultNs = "default" +) var ( openFile = os.Open @@ -167,7 +170,7 @@ func kptfileInitIfNot(ctx context.Context, out io.Writer, k *Deployer) error { kptFilePath := filepath.Join(k.applyDir, kptfile.KptFileName) if _, err := os.Stat(kptFilePath); os.IsNotExist(err) { _, endTrace := instrumentation.StartTrace(ctx, "Deploy_InitKptfile") - cmd := exec.CommandContext(ctx, "kpt", k.kptArgs("pkg", "init", k.applyDir)...) + cmd := exec.CommandContext(ctx, "kpt", "pkg", "init", k.applyDir) cmd.Stdout = out cmd.Stderr = out if err := util.RunCmd(cmd); err != nil { @@ -189,7 +192,8 @@ func kptfileInitIfNot(ctx context.Context, out io.Writer, k *Deployer) error { // If "Inventory" already exist, running `kpt live init` raises error. if kfConfig.Inventory == nil { _, endTrace := instrumentation.StartTrace(ctx, "Deploy_InitKptfileInventory") - args := k.kptArgs("live", "init", k.applyDir) + args := []string{"live", "init", k.applyDir} + args = append(args, k.KptV2Deploy.Flags...) if k.Name != "" { args = append(args, "--name", k.Name) } @@ -201,6 +205,9 @@ func kptfileInitIfNot(ctx context.Context, out io.Writer, k *Deployer) error { } else if k.InventoryNamespace != "" { args = append(args, "--namespace", k.InventoryNamespace) } + if k.Force { + args = append(args, "--force", "true") + } cmd := exec.CommandContext(ctx, "kpt", args...) cmd.Stdout = out cmd.Stderr = out @@ -209,18 +216,25 @@ func kptfileInitIfNot(ctx context.Context, out io.Writer, k *Deployer) error { return liveInitErr(err, k.applyDir) } } else { - if kfConfig.Inventory.InventoryID != k.InventoryID { + if k.InventoryID != "" && k.InventoryID != kfConfig.Inventory.InventoryID { logrus.Warnf("Updating Kptfile inventory from %v to %v", kfConfig.Inventory.InventoryID, k.InventoryID) kfConfig.Inventory.InventoryID = k.InventoryID } - if kfConfig.Inventory.Name != k.Name { + if k.Name != "" && k.Name != kfConfig.Inventory.Name { logrus.Warnf("Updating Kptfile name from %v to %v", kfConfig.Inventory.Name, k.Name) kfConfig.Inventory.Name = k.Name } - if k.namespace != "" && k.namespace != kfConfig.Inventory.Namespace { + // Set the namespace to be a valid kubernetes namespace value. If not specified, the value shall be "default". + if k.namespace == "" { + k.namespace = defaultNs + } + if k.InventoryNamespace == "" { + k.InventoryNamespace = defaultNs + } + if k.namespace != kfConfig.Inventory.Namespace { logrus.Warnf("Updating Kptfile namespace from %v to %v", kfConfig.Inventory.Namespace, k.namespace) kfConfig.Inventory.Namespace = k.namespace - } else if k.InventoryNamespace != "" && k.InventoryNamespace != kfConfig.Inventory.Namespace { + } else if k.InventoryNamespace != kfConfig.Inventory.Namespace { logrus.Warnf("Updating Kptfile namespace from %v to %v", kfConfig.Inventory.Namespace, k.InventoryNamespace) kfConfig.Inventory.Namespace = k.InventoryNamespace } @@ -259,7 +273,11 @@ func (k *Deployer) Deploy(ctx context.Context, out io.Writer, builds []graph.Art endTrace() childCtx, endTrace := instrumentation.StartTrace(ctx, "Deploy_execKptCommand") - cmd := exec.CommandContext(childCtx, "kpt", k.kptArgs("live", "apply", k.applyDir)...) + args := []string{"live", "apply", k.applyDir} + + args = append(args, k.Flags...) + args = append(args, k.ApplyFlags...) + cmd := exec.CommandContext(childCtx, "kpt", args...) cmd.Stdout = out cmd.Stderr = out if err := util.RunCmd(cmd); err != nil { @@ -289,7 +307,10 @@ func (k *Deployer) Cleanup(ctx context.Context, out io.Writer) error { if err := kptInitFunc(ctx, out, k); err != nil { return err } - cmd := exec.CommandContext(ctx, "kpt", k.kptArgs("live", "destroy", k.applyDir)...) + + args := []string{"live", "destroy", k.applyDir} + args = append(args, k.Flags...) + cmd := exec.CommandContext(ctx, "kpt", args...) cmd.Stdout = out cmd.Stderr = out if err := util.RunCmd(cmd); err != nil { @@ -298,9 +319,3 @@ func (k *Deployer) Cleanup(ctx context.Context, out io.Writer) error { return nil } - -// kptArgs returns the `kpt` args and global flags. -func (k *Deployer) kptArgs(args ...string) []string { - args = append(args, k.KptV2Deploy.Flags...) - return args -} diff --git a/pkg/skaffold/schema/latest/v2/config.go b/pkg/skaffold/schema/latest/v2/config.go index ee3427e1d28..938b6194ac6 100644 --- a/pkg/skaffold/schema/latest/v2/config.go +++ b/pkg/skaffold/schema/latest/v2/config.go @@ -555,7 +555,10 @@ type KptV2Deploy struct { // hydrated path `/.kpt-pipeline`. Dir string `yaml:"dir,omitempty"` - // Flags are additional flags passed to `kpt live apply`. + // ApplyFlags are additional flags passed to `kpt live apply`. + ApplyFlags []string `yaml:"applyFlags,omitempty"` + + // Flags are kpt global flags. Flags []string `yaml:"flags,omitempty"` // Name *alpha* is the inventory object name. @@ -565,6 +568,9 @@ type KptV2Deploy struct { // InventoryNamespace *alpha* sets the inventory namespace. InventoryNamespace string `yaml:"namespace,omitempty"` + // Forces is used in `kpt live init`, which forces the inventory values to be updated, even if they are already set. + Force bool `yaml:"false,omitempty"` + // LifecycleHooks describes a set of lifecycle hooks that are executed before and after every deploy. LifecycleHooks DeployHooks `yaml:"-"` } diff --git a/pkg/skaffold/schema/v3alpha1/config.go b/pkg/skaffold/schema/v3alpha1/config.go index f780d096dc8..a8322cb1d00 100644 --- a/pkg/skaffold/schema/v3alpha1/config.go +++ b/pkg/skaffold/schema/v3alpha1/config.go @@ -551,12 +551,14 @@ type Validator struct { // KptV2Deploy contains all the configuration needed by the deploy steps. type KptV2Deploy struct { - - // Dir is equivalent to the dir in `kpt live apply `. If not provided, skaffold renders the raw manifests - // and store them to a a hidden directory `.kpt-pipeline`, and deploys the hidden directory. + // Dir is equivalent to the dir in `kpt live apply `. If not provided, skaffold deploys from the default + // hydrated path `/.kpt-pipeline`. Dir string `yaml:"dir,omitempty"` - // Flags are additional flags passed to `kpt live apply`. + // ApplyFlags are additional flags passed to `kpt live apply`. + ApplyFlags []string `yaml:"applyFlags,omitempty"` + + // Flags are kpt global flags. Flags []string `yaml:"flags,omitempty"` // Name *alpha* is the inventory object name. @@ -566,6 +568,9 @@ type KptV2Deploy struct { // InventoryNamespace *alpha* sets the inventory namespace. InventoryNamespace string `yaml:"namespace,omitempty"` + // Forces is used in `kpt live init`, which forces the inventory values to be updated, even if they are already set. + Force bool `yaml:"false,omitempty"` + // LifecycleHooks describes a set of lifecycle hooks that are executed before and after every deploy. LifecycleHooks DeployHooks `yaml:"-"` }