Skip to content

Commit 16d0154

Browse files
committed
Add 'skaffold render' for kubectl deployer
1 parent 667bd76 commit 16d0154

File tree

4 files changed

+251
-53
lines changed

4 files changed

+251
-53
lines changed

integration/render_test.go

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
Copyright 2019 The Skaffold Authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package integration
18+
19+
import (
20+
"bytes"
21+
"context"
22+
"testing"
23+
24+
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
25+
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/deploy"
26+
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext"
27+
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
28+
"github.com/GoogleContainerTools/skaffold/testutil"
29+
)
30+
31+
func TestKubectlRender(t *testing.T) {
32+
tests := []struct {
33+
description string
34+
builds []build.Artifact
35+
input string
36+
expectedOut string
37+
}{
38+
{
39+
description: "normal render",
40+
builds: []build.Artifact{
41+
{
42+
ImageName: "gcr.io/k8s-skaffold/skaffold",
43+
Tag: "gcr.io/k8s-skaffold/skaffold:test",
44+
},
45+
},
46+
input: `apiVersion: v1
47+
kind: Pod
48+
spec:
49+
containers:
50+
- image: gcr.io/k8s-skaffold/skaffold
51+
name: skaffold
52+
`,
53+
expectedOut: `apiVersion: v1
54+
kind: Pod
55+
metadata:
56+
namespace: default
57+
spec:
58+
containers:
59+
- image: gcr.io/k8s-skaffold/skaffold:test
60+
name: skaffold
61+
`,
62+
},
63+
{
64+
description: "two artifacts",
65+
builds: []build.Artifact{
66+
{
67+
ImageName: "gcr.io/project/image1",
68+
Tag: "gcr.io/project/image1:tag1",
69+
},
70+
{
71+
ImageName: "gcr.io/project/image2",
72+
Tag: "gcr.io/project/image2:tag2",
73+
},
74+
},
75+
input: `apiVersion: v1
76+
kind: Pod
77+
spec:
78+
containers:
79+
- image: gcr.io/project/image1
80+
name: image1
81+
- image: gcr.io/project/image2
82+
name: image2
83+
`,
84+
expectedOut: `apiVersion: v1
85+
kind: Pod
86+
metadata:
87+
namespace: default
88+
spec:
89+
containers:
90+
- image: gcr.io/project/image1:tag1
91+
name: image1
92+
- image: gcr.io/project/image2:tag2
93+
name: image2
94+
`,
95+
},
96+
}
97+
for _, test := range tests {
98+
testutil.Run(t, test.description, func(t *testutil.T) {
99+
if testing.Short() {
100+
t.Skip("skipping integration test")
101+
}
102+
t.NewTempDir().
103+
Write("deployment.yaml", test.input).
104+
Chdir()
105+
106+
deployer := deploy.NewKubectlDeployer(&runcontext.RunContext{
107+
WorkingDir: ".",
108+
Cfg: latest.Pipeline{
109+
Deploy: latest.DeployConfig{
110+
DeployType: latest.DeployType{
111+
KubectlDeploy: &latest.KubectlDeploy{
112+
Manifests: []string{"deployment.yaml"},
113+
},
114+
},
115+
},
116+
},
117+
})
118+
var b bytes.Buffer
119+
err := deployer.Render(context.Background(), &b, test.builds, "")
120+
t.CheckErrorAndDeepEqual(false, err, test.expectedOut, b.String())
121+
})
122+
}
123+
}

pkg/skaffold/deploy/kubectl.go

+79-46
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ limitations under the License.
1717
package deploy
1818

1919
import (
20+
"bufio"
2021
"bytes"
2122
"context"
23+
"fmt"
2224
"io"
25+
"os"
2326
"strings"
2427

2528
"github.com/pkg/errors"
@@ -73,65 +76,29 @@ func (k *KubectlDeployer) Labels() map[string]string {
7376
// Deploy templates the provided manifests with a simple `find and replace` and
7477
// runs `kubectl apply` on those manifests
7578
func (k *KubectlDeployer) Deploy(ctx context.Context, out io.Writer, builds []build.Artifact, labellers []Labeller) *Result {
76-
if err := k.kubectl.CheckVersion(ctx); err != nil {
77-
color.Default.Fprintln(out, "kubectl client version:", k.kubectl.Version(ctx))
78-
color.Default.Fprintln(out, err)
79-
}
79+
event.DeployInProgress()
80+
manifests, err := k.renderManifests(ctx, out, builds)
8081

81-
manifests, err := k.readManifests(ctx)
8282
if err != nil {
8383
event.DeployFailed(err)
84-
return NewDeployErrorResult(errors.Wrap(err, "reading manifests"))
84+
return NewDeployErrorResult(err)
8585
}
8686

87-
for _, m := range k.RemoteManifests {
88-
manifest, err := k.readRemoteManifest(ctx, m)
89-
if err != nil {
90-
return NewDeployErrorResult(errors.Wrap(err, "get remote manifests"))
91-
}
92-
93-
manifests = append(manifests, manifest)
94-
}
95-
96-
if len(k.originalImages) == 0 {
97-
k.originalImages, err = manifests.GetImages()
98-
if err != nil {
99-
return NewDeployErrorResult(errors.Wrap(err, "get images from manifests"))
100-
}
101-
}
102-
103-
logrus.Debugln("manifests", manifests.String())
104-
10587
if len(manifests) == 0 {
88+
event.DeployComplete()
10689
return NewDeploySuccessResult(nil)
10790
}
10891

109-
event.DeployInProgress()
110-
111-
namespaces, err := manifests.CollectNamespaces()
112-
if err != nil {
113-
event.DeployInfoEvent(errors.Wrap(err, "could not fetch deployed resource namespace. "+
114-
"This might cause port-forward and deploy health-check to fail."))
115-
}
116-
117-
manifests, err = manifests.ReplaceImages(builds, k.defaultRepo)
118-
if err != nil {
119-
event.DeployFailed(err)
120-
return NewDeployErrorResult(errors.Wrap(err, "replacing images in manifests"))
121-
}
122-
12392
manifests, err = manifests.SetLabels(merge(labellers...))
12493
if err != nil {
12594
event.DeployFailed(err)
12695
return NewDeployErrorResult(errors.Wrap(err, "setting labels in manifests"))
12796
}
12897

129-
for _, transform := range manifestTransforms {
130-
manifests, err = transform(manifests, builds, k.insecureRegistries)
131-
if err != nil {
132-
event.DeployFailed(err)
133-
return NewDeployErrorResult(errors.Wrap(err, "unable to transform manifests"))
134-
}
98+
namespaces, err := manifests.CollectNamespaces()
99+
if err != nil {
100+
event.DeployInfoEvent(errors.Wrap(err, "could not fetch deployed resource namespace. "+
101+
"This might cause port-forward and deploy health-check to fail."))
135102
}
136103

137104
if err := k.kubectl.Apply(ctx, textio.NewPrefixWriter(out, " - "), manifests); err != nil {
@@ -252,6 +219,72 @@ func (k *KubectlDeployer) readRemoteManifest(ctx context.Context, name string) (
252219
return manifest.Bytes(), nil
253220
}
254221

255-
func (k *KubectlDeployer) Render(context.Context, io.Writer, []build.Artifact, string) error {
256-
return errors.New("not yet implemented")
222+
func (k *KubectlDeployer) Render(ctx context.Context, out io.Writer, builds []build.Artifact, filepath string) error {
223+
manifests, err := k.renderManifests(ctx, out, builds)
224+
225+
if err != nil {
226+
return err
227+
}
228+
229+
manifestOut := out
230+
if filepath != "" {
231+
f, err := os.Open(filepath)
232+
if err != nil {
233+
return errors.Wrap(err, "opening file for writing manifests")
234+
}
235+
manifestOut = bufio.NewWriter(f)
236+
}
237+
238+
for _, m := range manifests {
239+
if _, err := fmt.Fprintln(manifestOut, string(m)); err != nil {
240+
return errors.Wrap(err, "writing manifests")
241+
}
242+
}
243+
return nil
244+
}
245+
246+
func (k *KubectlDeployer) renderManifests(ctx context.Context, out io.Writer, builds []build.Artifact) (deploy.ManifestList, error) {
247+
if err := k.kubectl.CheckVersion(ctx); err != nil {
248+
color.Default.Fprintln(out, "kubectl client version:", k.kubectl.Version(ctx))
249+
color.Default.Fprintln(out, err)
250+
}
251+
252+
manifests, err := k.readManifests(ctx)
253+
if err != nil {
254+
return nil, errors.Wrap(err, "reading manifests")
255+
}
256+
257+
for _, m := range k.RemoteManifests {
258+
manifest, err := k.readRemoteManifest(ctx, m)
259+
if err != nil {
260+
return nil, errors.Wrap(err, "get remote manifests")
261+
}
262+
263+
manifests = append(manifests, manifest)
264+
}
265+
266+
if len(k.originalImages) == 0 {
267+
k.originalImages, err = manifests.GetImages()
268+
if err != nil {
269+
return nil, errors.Wrap(err, "get images from manifests")
270+
}
271+
}
272+
273+
if len(manifests) == 0 {
274+
return nil, nil
275+
}
276+
277+
manifests, err = manifests.ReplaceImages(builds, k.defaultRepo)
278+
if err != nil {
279+
return nil, errors.Wrap(err, "replacing images in manifests")
280+
}
281+
282+
for _, transform := range manifestTransforms {
283+
manifests, err = transform(manifests, builds, k.insecureRegistries)
284+
if err != nil {
285+
return nil, errors.Wrap(err, "unable to transform manifests")
286+
}
287+
}
288+
289+
return manifests, nil
257290
}

pkg/skaffold/deploy/kubectl/cli.go

-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ func (c *CLI) ReadManifests(ctx context.Context, manifests []string) (ManifestLi
8484

8585
var manifestList ManifestList
8686
manifestList.Append(buf)
87-
logrus.Debugln("manifests", manifestList.String())
8887

8988
return manifestList, nil
9089
}

pkg/skaffold/deploy/kubectl_test.go

+49-6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package deploy
1818

1919
import (
20+
"bytes"
2021
"context"
2122
"fmt"
2223
"io/ioutil"
@@ -461,28 +462,70 @@ func TestDependencies(t *testing.T) {
461462
func TestKubectlRender(t *testing.T) {
462463
tests := []struct {
463464
description string
464-
shouldErr bool
465+
builds []build.Artifact
466+
input string
465467
}{
466468
{
467-
description: "calling render returns error",
468-
shouldErr: true,
469+
description: "normal render",
470+
builds: []build.Artifact{
471+
{
472+
ImageName: "gcr.io/k8s-skaffold/skaffold",
473+
Tag: "gcr.io/k8s-skaffold/skaffold:test",
474+
},
475+
},
476+
input: `apiVersion: v1
477+
kind: Pod
478+
spec:
479+
containers:
480+
- image: gcr.io/k8s-skaffold/skaffold
481+
name: skaffold
482+
`,
483+
},
484+
{
485+
description: "two artifacts",
486+
builds: []build.Artifact{
487+
{
488+
ImageName: "gcr.io/project/image1",
489+
Tag: "gcr.io/project/image1:tag1",
490+
},
491+
{
492+
ImageName: "gcr.io/project/image2",
493+
Tag: "gcr.io/project/image2:tag2",
494+
},
495+
},
496+
input: `apiVersion: v1
497+
kind: Pod
498+
spec:
499+
containers:
500+
- image: gcr.io/project/image1
501+
name: image1
502+
- image: gcr.io/project/image2
503+
name: image2
504+
`,
469505
},
470506
}
471507
for _, test := range tests {
472508
testutil.Run(t, test.description, func(t *testutil.T) {
509+
t.Override(&util.DefaultExecCommand, testutil.
510+
CmdRunOut("kubectl version --client -ojson", kubectlVersion).
511+
AndRunOut("kubectl --context kubecontext create --dry-run -oyaml -f deployment.yaml", test.input))
512+
473513
deployer := NewKubectlDeployer(&runcontext.RunContext{
514+
WorkingDir: ".",
474515
Cfg: latest.Pipeline{
475516
Deploy: latest.DeployConfig{
476517
DeployType: latest.DeployType{
477518
KubectlDeploy: &latest.KubectlDeploy{
478-
Manifests: []string{},
519+
Manifests: []string{"deployment.yaml"},
479520
},
480521
},
481522
},
482523
},
524+
KubeContext: testKubeContext,
483525
})
484-
actual := deployer.Render(context.Background(), ioutil.Discard, []build.Artifact{}, "tmp/dir")
485-
t.CheckError(test.shouldErr, actual)
526+
var b bytes.Buffer
527+
err := deployer.Render(context.Background(), &b, test.builds, "")
528+
t.CheckError(false, err)
486529
})
487530
}
488531
}

0 commit comments

Comments
 (0)