diff --git a/docs/content/en/schemas/v2beta7.json b/docs/content/en/schemas/v2beta7.json
index ef1aabff5da..d08ce2bc844 100755
--- a/docs/content/en/schemas/v2beta7.json
+++ b/docs/content/en/schemas/v2beta7.json
@@ -1623,8 +1623,8 @@
}
},
"preferredOrder": [
- "dir",
"applyDir",
+ "dir",
"fn",
"live"
],
@@ -1639,15 +1639,45 @@
"description": "a directory to read functions from instead of the configuration directory.",
"x-intellij-html-description": "a directory to read functions from instead of the configuration directory."
},
+ "globalScope": {
+ "type": "boolean",
+ "description": "sets global scope for functions.",
+ "x-intellij-html-description": "sets global scope for functions.",
+ "default": "false"
+ },
"image": {
"type": "string",
"description": "an image to be run as a function in lieu of running functions from a directory.",
"x-intellij-html-description": "an image to be run as a function in lieu of running functions from a directory."
+ },
+ "mount": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "description": "a list of storage options to mount to the fn image.",
+ "x-intellij-html-description": "a list of storage options to mount to the fn image.",
+ "default": "[]"
+ },
+ "network": {
+ "type": "boolean",
+ "description": "enables network access for functions that declare it.",
+ "x-intellij-html-description": "enables network access for functions that declare it.",
+ "default": "false"
+ },
+ "networkName": {
+ "type": "string",
+ "description": "docker network to run the container in (default \"bridge\").",
+ "x-intellij-html-description": "docker network to run the container in (default "bridge")."
}
},
"preferredOrder": [
"fnPath",
- "image"
+ "image",
+ "networkName",
+ "globalScope",
+ "network",
+ "mount"
],
"additionalProperties": false,
"description": "adds additional configurations used when calling `kpt fn`.",
@@ -1656,21 +1686,62 @@
"KptLive": {
"properties": {
"apply": {
- "items": {
- "type": "string"
- },
- "type": "array",
- "description": "additional flags passed on creations (`kpt live apply`).",
- "x-intellij-html-description": "additional flags passed on creations (kpt live apply
).",
- "default": "[]"
+ "$ref": "#/definitions/KptLiveApply",
+ "description": "adds additional configurations for `kpt live apply` commands.",
+ "x-intellij-html-description": "adds additional configurations for kpt live apply
commands."
+ },
+ "inventoryID": {
+ "type": "string",
+ "description": "identifier for a group of applied resources. This configuration is used when users do not specify `KptDeploy.ApplyDir` and `.kpt-hydrated/inventory-template.yaml` does not exist.",
+ "x-intellij-html-description": "identifier for a group of applied resources. This configuration is used when users do not specify KptDeploy.ApplyDir
and .kpt-hydrated/inventory-template.yaml
does not exist."
+ },
+ "inventoryNamespace": {
+ "type": "string",
+ "description": "sets the namespace scope for `kpt live init`.",
+ "x-intellij-html-description": "sets the namespace scope for kpt live init
."
+ }
+ },
+ "preferredOrder": [
+ "apply",
+ "inventoryID",
+ "inventoryNamespace"
+ ],
+ "additionalProperties": false,
+ "description": "adds additional configurations used when calling `kpt live`.",
+ "x-intellij-html-description": "adds additional configurations used when calling kpt live
."
+ },
+ "KptLiveApply": {
+ "properties": {
+ "pollPeriod": {
+ "type": "string",
+ "description": "sets for the polling period for resource statuses. Default to 2s.",
+ "x-intellij-html-description": "sets for the polling period for resource statuses. Default to 2s."
+ },
+ "prunePropagationPolicy": {
+ "type": "string",
+ "description": "sets the propagation policy for pruning. Possible settings are Background, Foreground, Orphan. Default to \"Background\".",
+ "x-intellij-html-description": "sets the propagation policy for pruning. Possible settings are Background, Foreground, Orphan. Default to "Background"."
+ },
+ "pruneTimeout": {
+ "type": "string",
+ "description": "sets the time threshold to wait for all pruned resources to be deleted.",
+ "x-intellij-html-description": "sets the time threshold to wait for all pruned resources to be deleted."
+ },
+ "reconcileTimeout": {
+ "type": "string",
+ "description": "sets the time threshold to wait for all resources to reach the current status.",
+ "x-intellij-html-description": "sets the time threshold to wait for all resources to reach the current status."
}
},
"preferredOrder": [
- "apply"
+ "pollPeriod",
+ "prunePropagationPolicy",
+ "pruneTimeout",
+ "reconcileTimeout"
],
"additionalProperties": false,
- "description": "adds additional configurations used when calling `kpt live` on every command (Global), creations (Apply), or deletions (Destroy).",
- "x-intellij-html-description": "adds additional configurations used when calling kpt live
on every command (Global), creations (Apply), or deletions (Destroy)."
+ "description": "adds additional configurations used when calling `kpt live apply`.",
+ "x-intellij-html-description": "adds additional configurations used when calling kpt live apply
."
},
"KubectlDeploy": {
"properties": {
diff --git a/pkg/skaffold/deploy/kpt.go b/pkg/skaffold/deploy/kpt.go
index d7d82d96934..b77f9390928 100644
--- a/pkg/skaffold/deploy/kpt.go
+++ b/pkg/skaffold/deploy/kpt.go
@@ -87,7 +87,7 @@ func (k *KptDeployer) Deploy(ctx context.Context, out io.Writer, builds []build.
outputRenderedManifests(manifests.String(), filepath.Join(applyDir, "resources.yaml"), out)
- cmd := exec.CommandContext(ctx, "kpt", kptCommandArgs(applyDir, []string{"live", "apply"}, k.Live.Apply, nil)...)
+ cmd := exec.CommandContext(ctx, "kpt", kptCommandArgs(applyDir, []string{"live", "apply"}, k.getKptLiveApplyArgs(), nil)...)
cmd.Stdout = out
cmd.Stderr = out
if err := util.RunCmd(cmd); err != nil {
@@ -253,21 +253,9 @@ func (k *KptDeployer) kustomizeBuild(ctx context.Context) error {
func (k *KptDeployer) kptFnRun(ctx context.Context) (deploy.ManifestList, error) {
var manifests deploy.ManifestList
- // --dry-run sets the pipeline's output to STDOUT, otherwise output is set to sinkDir.
- // For now, k.Dir will be treated as sinkDir (and sourceDir).
- flags := []string{"--dry-run"}
- count := 0
-
- if len(k.Fn.FnPath) > 0 {
- flags = append(flags, "--fn-path", k.Fn.FnPath)
- count++
- }
- if len(k.Fn.Image) > 0 {
- flags = append(flags, "--image", k.Fn.Image)
- count++
- }
- if count > 1 {
- return nil, errors.New("only one of `fn-path` or `image` configs can be specified at most")
+ flags, err := k.getKptFnRunArgs()
+ if err != nil {
+ return nil, fmt.Errorf("getting kpt fn run args: %w", err)
}
cmd := exec.CommandContext(ctx, "kpt", kptCommandArgs(pipeline, []string{"fn", "run"}, flags, nil)...)
@@ -300,7 +288,7 @@ func (k *KptDeployer) getApplyDir(ctx context.Context) (string, error) {
}
if _, err := os.Stat(filepath.Join(kptHydrated, inventoryTemplate)); os.IsNotExist(err) {
- cmd := exec.CommandContext(ctx, "kpt", kptCommandArgs(kptHydrated, []string{"live", "init"}, nil, nil)...)
+ cmd := exec.CommandContext(ctx, "kpt", kptCommandArgs(kptHydrated, []string{"live", "init"}, k.getKptLiveInitArgs(), nil)...)
if _, err := util.RunCmdOut(cmd); err != nil {
return "", err
}
@@ -360,3 +348,82 @@ func getResources(root string) ([]string, error) {
return files, err
}
+
+// getKptFnRunArgs returns a list of arguments that the user specified for the `kpt fn run` command.
+func (k *KptDeployer) getKptFnRunArgs() ([]string, error) {
+ // --dry-run sets the pipeline's output to STDOUT, otherwise output is set to sinkDir.
+ // For now, k.Dir will be treated as sinkDir (and sourceDir).
+ flags := []string{"--dry-run"}
+
+ if k.Fn.GlobalScope {
+ flags = append(flags, "--global-scope")
+ }
+
+ if len(k.Fn.Mount) > 0 {
+ flags = append(flags, "--mount", strings.Join(k.Fn.Mount, ","))
+ }
+
+ if k.Fn.Network {
+ flags = append(flags, "--network")
+ }
+
+ if len(k.Fn.NetworkName) > 0 {
+ flags = append(flags, "--network-name", k.Fn.NetworkName)
+ }
+
+ count := 0
+
+ if len(k.Fn.FnPath) > 0 {
+ flags = append(flags, "--fn-path", k.Fn.FnPath)
+ count++
+ }
+
+ if len(k.Fn.Image) > 0 {
+ flags = append(flags, "--image", k.Fn.Image)
+ count++
+ }
+
+ if count > 1 {
+ return nil, errors.New("only one of `fn-path` or `image` may be specified")
+ }
+
+ return flags, nil
+}
+
+// getKptLiveApplyArgs returns a list of arguments that the user specified for the `kpt live apply` command.
+func (k *KptDeployer) getKptLiveApplyArgs() []string {
+ var flags []string
+
+ if len(k.Live.Apply.PollPeriod) > 0 {
+ flags = append(flags, "--poll-period", k.Live.Apply.PollPeriod)
+ }
+
+ if len(k.Live.Apply.PrunePropagationPolicy) > 0 {
+ flags = append(flags, "--prune-propagation-policy", k.Live.Apply.PrunePropagationPolicy)
+ }
+
+ if len(k.Live.Apply.PruneTimeout) > 0 {
+ flags = append(flags, "--prune-timeout", k.Live.Apply.PruneTimeout)
+ }
+
+ if len(k.Live.Apply.ReconcileTimeout) > 0 {
+ flags = append(flags, "--reconcile-timeout", k.Live.Apply.ReconcileTimeout)
+ }
+
+ return flags
+}
+
+// getKptLiveInitArgs returns a list of arguments that the user specified for the `kpt live init` command.
+func (k *KptDeployer) getKptLiveInitArgs() []string {
+ var flags []string
+
+ if len(k.Live.InventoryID) > 0 {
+ flags = append(flags, "--inventory-id", k.Live.InventoryID)
+ }
+
+ if len(k.Live.InventoryNamespace) > 0 {
+ flags = append(flags, "--namespace", k.Live.InventoryNamespace)
+ }
+
+ return flags
+}
diff --git a/pkg/skaffold/deploy/kpt_test.go b/pkg/skaffold/deploy/kpt_test.go
index 489bbedc567..c35bae8b5b0 100644
--- a/pkg/skaffold/deploy/kpt_test.go
+++ b/pkg/skaffold/deploy/kpt_test.go
@@ -117,6 +117,78 @@ spec:
AndRunErr("kpt live apply .kpt-hydrated", errors.New("BUG")),
shouldErr: true,
},
+ {
+ description: "user specifies reconcile timeout and poll period",
+ cfg: &latest.KptDeploy{
+ Dir: ".",
+ ApplyDir: "valid_path",
+ Live: latest.KptLive{
+ Apply: latest.KptLiveApply{
+ PollPeriod: "5s",
+ ReconcileTimeout: "2m",
+ },
+ },
+ },
+ commands: testutil.
+ CmdRunOut("kpt fn source .", ``).
+ AndRunOut("kpt fn sink .pipeline", ``).
+ AndRunOut("kpt fn run .pipeline --dry-run", output).
+ AndRun("kpt live apply valid_path --poll-period 5s --reconcile-timeout 2m"),
+ },
+ {
+ description: "user specifies invalid reconcile timeout and poll period",
+ cfg: &latest.KptDeploy{
+ Dir: ".",
+ ApplyDir: "valid_path",
+ Live: latest.KptLive{
+ Apply: latest.KptLiveApply{
+ PollPeriod: "foo",
+ ReconcileTimeout: "bar",
+ },
+ },
+ },
+ commands: testutil.
+ CmdRunOut("kpt fn source .", ``).
+ AndRunOut("kpt fn sink .pipeline", ``).
+ AndRunOut("kpt fn run .pipeline --dry-run", output).
+ AndRun("kpt live apply valid_path --poll-period foo --reconcile-timeout bar"),
+ },
+ {
+ description: "user specifies prune propagation policy and prune timeout",
+ cfg: &latest.KptDeploy{
+ Dir: ".",
+ ApplyDir: "valid_path",
+ Live: latest.KptLive{
+ Apply: latest.KptLiveApply{
+ PrunePropagationPolicy: "Orphan",
+ PruneTimeout: "2m",
+ },
+ },
+ },
+ commands: testutil.
+ CmdRunOut("kpt fn source .", ``).
+ AndRunOut("kpt fn sink .pipeline", ``).
+ AndRunOut("kpt fn run .pipeline --dry-run", output).
+ AndRun("kpt live apply valid_path --prune-propagation-policy Orphan --prune-timeout 2m"),
+ },
+ {
+ description: "user specifies invalid prune propagation policy and prune timeout",
+ cfg: &latest.KptDeploy{
+ Dir: ".",
+ ApplyDir: "valid_path",
+ Live: latest.KptLive{
+ Apply: latest.KptLiveApply{
+ PrunePropagationPolicy: "foo",
+ PruneTimeout: "bar",
+ },
+ },
+ },
+ commands: testutil.
+ CmdRunOut("kpt fn source .", ``).
+ AndRunOut("kpt fn sink .pipeline", ``).
+ AndRunOut("kpt fn run .pipeline --dry-run", output).
+ AndRun("kpt live apply valid_path --prune-propagation-policy foo --prune-timeout bar"),
+ },
}
for _, test := range tests {
testutil.Run(t, test.description, func(t *testutil.T) {
@@ -277,6 +349,7 @@ func TestKpt_Cleanup(t *testing.T) {
tests := []struct {
description string
applyDir string
+ globalFlags []string
commands util.Command
shouldErr bool
}{
@@ -604,6 +677,67 @@ spec:
AndRunOutErr("kpt fn run .pipeline --dry-run", "invalid pipeline", errors.New("BUG")),
shouldErr: true,
},
+ {
+ description: "kpt fn run with --global-scope",
+ cfg: &latest.KptDeploy{
+ Dir: ".",
+ Fn: latest.KptFn{
+ Image: "gcr.io/example.com/my-fn:v1.0.0 -- foo=bar",
+ GlobalScope: true,
+ },
+ },
+ commands: testutil.
+ CmdRunOut("kpt fn source .", ``).
+ AndRunOut("kpt fn sink .pipeline", ``).
+ AndRunOut("kpt fn run .pipeline --dry-run --global-scope --image gcr.io/example.com/my-fn:v1.0.0 -- foo=bar", ``),
+ expected: "\n",
+ },
+ {
+ description: "kpt fn run with --mount arguments",
+ cfg: &latest.KptDeploy{
+ Dir: ".",
+ Fn: latest.KptFn{
+ Image: "gcr.io/example.com/my-fn:v1.0.0 -- foo=bar",
+ Mount: []string{"type=bind", "src=$(pwd)", "dst=/source"},
+ },
+ },
+ commands: testutil.
+ CmdRunOut("kpt fn source .", ``).
+ AndRunOut("kpt fn sink .pipeline", ``).
+ AndRunOut("kpt fn run .pipeline --dry-run --mount type=bind,src=$(pwd),dst=/source --image gcr.io/example.com/my-fn:v1.0.0 -- foo=bar", ``),
+ expected: "\n",
+ },
+ {
+ description: "kpt fn run with invalid --mount arguments",
+ cfg: &latest.KptDeploy{
+ Dir: ".",
+ Fn: latest.KptFn{
+ Image: "gcr.io/example.com/my-fn:v1.0.0 -- foo=bar",
+ Mount: []string{"foo", "", "bar"},
+ },
+ },
+ commands: testutil.
+ CmdRunOut("kpt fn source .", ``).
+ AndRunOut("kpt fn sink .pipeline", ``).
+ AndRunOut("kpt fn run .pipeline --dry-run --mount foo,,bar --image gcr.io/example.com/my-fn:v1.0.0 -- foo=bar", ``),
+ expected: "\n",
+ },
+ {
+ description: "kpt fn run flag with --network and --network-name arguments",
+ cfg: &latest.KptDeploy{
+ Dir: ".",
+ Fn: latest.KptFn{
+ Image: "gcr.io/example.com/my-fn:v1.0.0 -- foo=bar",
+ Network: true,
+ NetworkName: "foo",
+ },
+ },
+ commands: testutil.
+ CmdRunOut("kpt fn source .", ``).
+ AndRunOut("kpt fn sink .pipeline", ``).
+ AndRunOut("kpt fn run .pipeline --dry-run --network --network-name foo --image gcr.io/example.com/my-fn:v1.0.0 -- foo=bar", ``),
+ expected: "\n",
+ },
}
for _, test := range tests {
testutil.Run(t, test.description, func(t *testutil.T) {
@@ -639,6 +773,7 @@ func TestKpt_GetApplyDir(t *testing.T) {
tests := []struct {
description string
applyDir string
+ live latest.KptLive
expected string
commands util.Command
shouldErr bool
@@ -658,6 +793,15 @@ func TestKpt_GetApplyDir(t *testing.T) {
expected: ".kpt-hydrated",
commands: testutil.CmdRunOut("kpt live init .kpt-hydrated", ""),
},
+ {
+ description: "unspecified applyDir with specified inventory-id and namespace",
+ live: latest.KptLive{
+ InventoryID: "1a23bcde-4f56-7891-a2bc-de34fabcde5f6",
+ InventoryNamespace: "foo",
+ },
+ expected: ".kpt-hydrated",
+ commands: testutil.CmdRunOut("kpt live init .kpt-hydrated --inventory-id 1a23bcde-4f56-7891-a2bc-de34fabcde5f6 --namespace foo", ""),
+ },
{
description: "existing template resource in .kpt-hydrated",
expected: ".kpt-hydrated",
@@ -685,6 +829,7 @@ func TestKpt_GetApplyDir(t *testing.T) {
DeployType: latest.DeployType{
KptDeploy: &latest.KptDeploy{
ApplyDir: test.applyDir,
+ Live: test.live,
},
},
},
@@ -722,8 +867,8 @@ func TestKpt_KptCommandArgs(t *testing.T) {
description: "empty dir",
commands: []string{"live", "apply"},
flags: []string{"--fn-path", "kpt-func.yaml"},
- globalFlags: []string{"-h"},
- expected: strings.Split("live apply --fn-path kpt-func.yaml -h", " "),
+ globalFlags: []string{"-v", "3"},
+ expected: strings.Split("live apply --fn-path kpt-func.yaml -v 3", " "),
},
{
description: "empty commands",
diff --git a/pkg/skaffold/schema/latest/config.go b/pkg/skaffold/schema/latest/config.go
index 20a14fd5723..93551bf5c18 100644
--- a/pkg/skaffold/schema/latest/config.go
+++ b/pkg/skaffold/schema/latest/config.go
@@ -528,12 +528,12 @@ type KustomizeDeploy struct {
// KptDeploy *beta* uses the `kpt` CLI to manage and deploy manifests.
type KptDeploy struct {
- // Dir is the path to the directory to run kpt functions against.
- Dir string `yaml:"dir,omitempty"`
-
// ApplyDir is the path to the directory to deploy to the cluster.
ApplyDir string `yaml:"applyDir,omitempty"`
+ // Dir is the path to the directory to run kpt functions against.
+ Dir string `yaml:"dir,omitempty"`
+
// Fn adds additional configurations for `kpt fn`.
Fn KptFn `yaml:"fn,omitempty"`
@@ -548,13 +548,49 @@ type KptFn struct {
// Image is an image to be run as a function in lieu of running functions from a directory.
Image string `yaml:"image,omitempty"`
+
+ // NetworkName is the docker network to run the container in (default "bridge").
+ NetworkName string `yaml:"networkName,omitempty"`
+
+ // GlobalScope sets global scope for functions.
+ GlobalScope bool `yaml:"globalScope,omitempty"`
+
+ // Network enables network access for functions that declare it.
+ Network bool `yaml:"network,omitempty"`
+
+ // Mount is a list of storage options to mount to the fn image.
+ Mount []string `yaml:"mount,omitempty"`
}
-// KptLive adds additional configurations used when calling `kpt live`
-// on every command (Global), creations (Apply), or deletions (Destroy).
+// KptLive adds additional configurations used when calling `kpt live`.
type KptLive struct {
- // Apply are additional flags passed on creations (`kpt live apply`).
- Apply []string `yaml:"apply,omitempty"`
+ // Apply adds additional configurations for `kpt live apply` commands.
+ Apply KptLiveApply `yaml:"apply,omitempty"`
+
+ // InventoryID is the identifier for a group of applied resources.
+ // This configuration is used when users do not specify `KptDeploy.ApplyDir`
+ // and `.kpt-hydrated/inventory-template.yaml` does not exist.
+ InventoryID string `yaml:"inventoryID,omitempty"`
+
+ // InventoryNamespace sets the namespace scope for `kpt live init`.
+ InventoryNamespace string `yaml:"inventoryNamespace,omitempty"`
+}
+
+// KptLiveApply adds additional configurations used when calling `kpt live apply`.
+type KptLiveApply struct {
+ // PollPeriod sets for the polling period for resource statuses. Default to 2s.
+ PollPeriod string `yaml:"pollPeriod,omitempty"`
+
+ // PrunePropagationPolicy sets the propagation policy for pruning.
+ // Possible settings are Background, Foreground, Orphan.
+ // Default to "Background".
+ PrunePropagationPolicy string `yaml:"prunePropagationPolicy,omitempty"`
+
+ // PruneTimeout sets the time threshold to wait for all pruned resources to be deleted.
+ PruneTimeout string `yaml:"pruneTimeout,omitempty"`
+
+ // ReconcileTimeout sets the time threshold to wait for all resources to reach the current status.
+ ReconcileTimeout string `yaml:"reconcileTimeout,omitempty"`
}
// HelmRelease describes a helm release to be deployed.