Skip to content

Commit 08551a7

Browse files
authored
Merge pull request #2943 from nkubala/render-kubectl
Implement 'skaffold render' for kubectl deployer
2 parents a4bdbbc + 9331930 commit 08551a7

File tree

4 files changed

+292
-53
lines changed

4 files changed

+292
-53
lines changed

integration/render_test.go

+168
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
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+
description: "two artifacts, combined manifests",
98+
builds: []build.Artifact{
99+
{
100+
ImageName: "gcr.io/project/image1",
101+
Tag: "gcr.io/project/image1:tag1",
102+
},
103+
{
104+
ImageName: "gcr.io/project/image2",
105+
Tag: "gcr.io/project/image2:tag2",
106+
},
107+
},
108+
input: `apiVersion: v1
109+
kind: Pod
110+
spec:
111+
containers:
112+
- image: gcr.io/project/image1
113+
name: image1
114+
---
115+
apiVersion: v1
116+
kind: Pod
117+
spec:
118+
containers:
119+
- image: gcr.io/project/image2
120+
name: image2
121+
`,
122+
expectedOut: `apiVersion: v1
123+
kind: Pod
124+
metadata:
125+
namespace: default
126+
spec:
127+
containers:
128+
- image: gcr.io/project/image1:tag1
129+
name: image1
130+
---
131+
apiVersion: v1
132+
kind: Pod
133+
metadata:
134+
namespace: default
135+
spec:
136+
containers:
137+
- image: gcr.io/project/image2:tag2
138+
name: image2
139+
`,
140+
},
141+
}
142+
for _, test := range tests {
143+
testutil.Run(t, test.description, func(t *testutil.T) {
144+
if testing.Short() {
145+
t.Skip("skipping integration test")
146+
}
147+
t.NewTempDir().
148+
Write("deployment.yaml", test.input).
149+
Chdir()
150+
151+
deployer := deploy.NewKubectlDeployer(&runcontext.RunContext{
152+
WorkingDir: ".",
153+
Cfg: latest.Pipeline{
154+
Deploy: latest.DeployConfig{
155+
DeployType: latest.DeployType{
156+
KubectlDeploy: &latest.KubectlDeploy{
157+
Manifests: []string{"deployment.yaml"},
158+
},
159+
},
160+
},
161+
},
162+
})
163+
var b bytes.Buffer
164+
err := deployer.Render(context.Background(), &b, test.builds, "")
165+
t.CheckErrorAndDeepEqual(false, err, test.expectedOut, b.String())
166+
})
167+
}
168+
}

pkg/skaffold/deploy/kubectl.go

+75-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,68 @@ 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+
fmt.Fprintln(manifestOut, manifests.String())
239+
return nil
240+
}
241+
242+
func (k *KubectlDeployer) renderManifests(ctx context.Context, out io.Writer, builds []build.Artifact) (deploy.ManifestList, error) {
243+
if err := k.kubectl.CheckVersion(ctx); err != nil {
244+
color.Default.Fprintln(out, "kubectl client version:", k.kubectl.Version(ctx))
245+
color.Default.Fprintln(out, err)
246+
}
247+
248+
manifests, err := k.readManifests(ctx)
249+
if err != nil {
250+
return nil, errors.Wrap(err, "reading manifests")
251+
}
252+
253+
for _, m := range k.RemoteManifests {
254+
manifest, err := k.readRemoteManifest(ctx, m)
255+
if err != nil {
256+
return nil, errors.Wrap(err, "get remote manifests")
257+
}
258+
259+
manifests = append(manifests, manifest)
260+
}
261+
262+
if len(k.originalImages) == 0 {
263+
k.originalImages, err = manifests.GetImages()
264+
if err != nil {
265+
return nil, errors.Wrap(err, "get images from manifests")
266+
}
267+
}
268+
269+
if len(manifests) == 0 {
270+
return nil, nil
271+
}
272+
273+
manifests, err = manifests.ReplaceImages(builds, k.defaultRepo)
274+
if err != nil {
275+
return nil, errors.Wrap(err, "replacing images in manifests")
276+
}
277+
278+
for _, transform := range manifestTransforms {
279+
manifests, err = transform(manifests, builds, k.insecureRegistries)
280+
if err != nil {
281+
return nil, errors.Wrap(err, "unable to transform manifests")
282+
}
283+
}
284+
285+
return manifests, nil
257286
}

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
}

0 commit comments

Comments
 (0)