Skip to content

Commit fd0d8d2

Browse files
authored
Kpt Deployer Deploy() Implementation/Tests (#4723)
* deployer implementation and tests * nit
1 parent f54a62b commit fd0d8d2

File tree

2 files changed

+143
-16
lines changed

2 files changed

+143
-16
lines changed

pkg/skaffold/deploy/kpt.go

+39-6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
3232
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
3333
deploy "github.com/GoogleContainerTools/skaffold/pkg/skaffold/deploy/kubectl"
34+
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/event"
3435
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext"
3536
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
3637
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
@@ -60,8 +61,40 @@ func NewKptDeployer(runCtx *runcontext.RunContext, labels map[string]string) *Kp
6061
}
6162
}
6263

64+
// Deploy hydrates the manifests using kustomizations and kpt functions as described in the render method,
65+
// outputs them to the applyDir, and runs `kpt live apply` against applyDir to create resources in the cluster.
66+
// `kpt live apply` supports automated pruning declaratively via resources in the applyDir.
6367
func (k *KptDeployer) Deploy(ctx context.Context, out io.Writer, builds []build.Artifact) ([]string, error) {
64-
return nil, nil
68+
manifests, err := k.renderManifests(ctx, out, builds)
69+
if err != nil {
70+
return nil, err
71+
}
72+
73+
if len(manifests) == 0 {
74+
return nil, nil
75+
}
76+
77+
namespaces, err := manifests.CollectNamespaces()
78+
if err != nil {
79+
event.DeployInfoEvent(fmt.Errorf("could not fetch deployed resource namespace. "+
80+
"This might cause port-forward and deploy health-check to fail: %w", err))
81+
}
82+
83+
applyDir, err := k.getApplyDir(ctx)
84+
if err != nil {
85+
return nil, fmt.Errorf("getting applyDir: %w", err)
86+
}
87+
88+
outputRenderedManifests(manifests.String(), filepath.Join(applyDir, "resources.yaml"), out)
89+
90+
cmd := exec.CommandContext(ctx, "kpt", kptCommandArgs(applyDir, []string{"live", "apply"}, k.Live.Apply, nil)...)
91+
cmd.Stdout = out
92+
cmd.Stderr = out
93+
if err := util.RunCmd(cmd); err != nil {
94+
return nil, err
95+
}
96+
97+
return namespaces, nil
6598
}
6699

67100
// Dependencies returns a list of files that the deployer depends on. This does NOT include applyDir.
@@ -91,17 +124,17 @@ func (k *KptDeployer) Dependencies() ([]string, error) {
91124
}
92125

93126
// Cleanup deletes what was deployed by calling `kpt live destroy`.
94-
func (k *KptDeployer) Cleanup(ctx context.Context, _ io.Writer) error {
127+
func (k *KptDeployer) Cleanup(ctx context.Context, out io.Writer) error {
95128
applyDir, err := k.getApplyDir(ctx)
96129
if err != nil {
97130
return fmt.Errorf("getting applyDir: %w", err)
98131
}
99132

100133
cmd := exec.CommandContext(ctx, "kpt", kptCommandArgs(applyDir, []string{"live", "destroy"}, nil, nil)...)
101-
out, err := util.RunCmdOut(cmd)
102-
if err != nil {
103-
// Kpt errors are written in STDOUT and surrounded by `\n`.
104-
return fmt.Errorf("kpt live destroy: %s", strings.Trim(string(out), "\n"))
134+
cmd.Stdout = out
135+
cmd.Stderr = out
136+
if err := util.RunCmd(cmd); err != nil {
137+
return err
105138
}
106139

107140
return nil

pkg/skaffold/deploy/kpt_test.go

+104-10
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,114 @@ import (
3636
)
3737

3838
func TestKpt_Deploy(t *testing.T) {
39+
output := `apiVersion: v1
40+
kind: Pod
41+
metadata:
42+
namespace: default
43+
spec:
44+
containers:
45+
- image: gcr.io/project/image1
46+
name: image1
47+
`
3948
tests := []struct {
40-
description string
41-
expected []string
42-
shouldErr bool
49+
description string
50+
builds []build.Artifact
51+
cfg *latest.KptDeploy
52+
kustomizations map[string]string
53+
commands util.Command
54+
expected []string
55+
shouldErr bool
4356
}{
4457
{
45-
description: "nil",
58+
description: "no manifest",
59+
cfg: &latest.KptDeploy{
60+
Dir: ".",
61+
},
62+
commands: testutil.
63+
CmdRunOut("kpt fn source .", ``).
64+
AndRunOut("kpt fn sink .pipeline", ``).
65+
AndRunOut("kpt fn run .pipeline --dry-run", ``),
66+
},
67+
{
68+
description: "invalid manifest",
69+
cfg: &latest.KptDeploy{
70+
Dir: ".",
71+
},
72+
commands: testutil.
73+
CmdRunOut("kpt fn source .", ``).
74+
AndRunOut("kpt fn sink .pipeline", ``).
75+
AndRunOut("kpt fn run .pipeline --dry-run", `foo`),
76+
shouldErr: true,
77+
},
78+
{
79+
description: "invalid user specified applyDir",
80+
cfg: &latest.KptDeploy{
81+
Dir: ".",
82+
ApplyDir: "invalid_path",
83+
},
84+
commands: testutil.
85+
CmdRunOut("kpt fn source .", ``).
86+
AndRunOut("kpt fn sink .pipeline", ``).
87+
AndRunOut("kpt fn run .pipeline --dry-run", output),
88+
shouldErr: true,
89+
},
90+
{
91+
description: "kustomization and specified kpt fn",
92+
cfg: &latest.KptDeploy{
93+
Dir: ".",
94+
Fn: latest.KptFn{FnPath: "kpt-func.yaml"},
95+
ApplyDir: "valid_path",
96+
},
97+
kustomizations: map[string]string{"Kustomization": `resources:
98+
- foo.yaml`},
99+
commands: testutil.
100+
CmdRunOut("kpt fn source .", ``).
101+
AndRunOut("kpt fn sink .pipeline", ``).
102+
AndRunOut("kustomize build -o .pipeline .", ``).
103+
AndRunOut("kpt fn run .pipeline --dry-run --fn-path kpt-func.yaml", output).
104+
AndRun("kpt live apply valid_path"),
105+
expected: []string{"default"},
106+
},
107+
{
108+
description: "kpt live apply fails",
109+
cfg: &latest.KptDeploy{
110+
Dir: ".",
111+
},
112+
commands: testutil.
113+
CmdRunOut("kpt fn source .", ``).
114+
AndRunOut("kpt fn sink .pipeline", ``).
115+
AndRunOut("kpt fn run .pipeline --dry-run", output).
116+
AndRunOut("kpt live init .kpt-hydrated", ``).
117+
AndRunErr("kpt live apply .kpt-hydrated", errors.New("BUG")),
118+
shouldErr: true,
46119
},
47120
}
48121
for _, test := range tests {
49122
testutil.Run(t, test.description, func(t *testutil.T) {
50-
k := NewKptDeployer(&runcontext.RunContext{}, nil)
51-
res, err := k.Deploy(context.Background(), nil, nil)
52-
t.CheckErrorAndDeepEqual(test.shouldErr, err, test.expected, res)
123+
t.Override(&util.DefaultExecCommand, test.commands)
124+
tmpDir := t.NewTempDir().Chdir()
125+
126+
tmpDir.WriteFiles(test.kustomizations)
127+
128+
k := NewKptDeployer(&runcontext.RunContext{
129+
Cfg: latest.Pipeline{
130+
Deploy: latest.DeployConfig{
131+
DeployType: latest.DeployType{
132+
KptDeploy: test.cfg,
133+
},
134+
},
135+
},
136+
}, nil)
137+
138+
if k.ApplyDir == "valid_path" {
139+
// 0755 is a permission setting where the owner can read, write, and execute.
140+
// Others can read and execute but not modify the directory.
141+
os.Mkdir(k.ApplyDir, 0755)
142+
}
143+
144+
_, err := k.Deploy(context.Background(), ioutil.Discard, test.builds)
145+
146+
t.CheckError(test.shouldErr, err)
53147
})
54148
}
55149
}
@@ -194,19 +288,19 @@ func TestKpt_Cleanup(t *testing.T) {
194288
{
195289
description: "valid user specified applyDir w/o template resource",
196290
applyDir: "valid_path",
197-
commands: testutil.CmdRunOutErr("kpt live destroy valid_path", "", errors.New("BUG")),
291+
commands: testutil.CmdRunErr("kpt live destroy valid_path", errors.New("BUG")),
198292
shouldErr: true,
199293
},
200294
{
201295
description: "valid user specified applyDir w/ template resource (emulated)",
202296
applyDir: "valid_path",
203-
commands: testutil.CmdRunOut("kpt live destroy valid_path", ""),
297+
commands: testutil.CmdRun("kpt live destroy valid_path"),
204298
},
205299
{
206300
description: "unspecified applyDir",
207301
commands: testutil.
208302
CmdRunOut("kpt live init .kpt-hydrated", "").
209-
AndRunOut("kpt live destroy .kpt-hydrated", ""),
303+
AndRun("kpt live destroy .kpt-hydrated"),
210304
},
211305
}
212306
for _, test := range tests {

0 commit comments

Comments
 (0)