Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement 'skaffold render' for kubectl deployer #2943

Merged
merged 3 commits into from
Oct 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 168 additions & 0 deletions integration/render_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
Copyright 2019 The Skaffold Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package integration

import (
"bytes"
"context"
"testing"

"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/deploy"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
"github.com/GoogleContainerTools/skaffold/testutil"
)

func TestKubectlRender(t *testing.T) {
tests := []struct {
description string
builds []build.Artifact
input string
expectedOut string
}{
{
description: "normal render",
builds: []build.Artifact{
{
ImageName: "gcr.io/k8s-skaffold/skaffold",
Tag: "gcr.io/k8s-skaffold/skaffold:test",
},
},
input: `apiVersion: v1
kind: Pod
spec:
containers:
- image: gcr.io/k8s-skaffold/skaffold
name: skaffold
`,
expectedOut: `apiVersion: v1
kind: Pod
metadata:
namespace: default
spec:
containers:
- image: gcr.io/k8s-skaffold/skaffold:test
name: skaffold
`,
},
{
description: "two artifacts",
builds: []build.Artifact{
{
ImageName: "gcr.io/project/image1",
Tag: "gcr.io/project/image1:tag1",
},
{
ImageName: "gcr.io/project/image2",
Tag: "gcr.io/project/image2:tag2",
},
},
input: `apiVersion: v1
nkubala marked this conversation as resolved.
Show resolved Hide resolved
kind: Pod
spec:
containers:
- image: gcr.io/project/image1
name: image1
- image: gcr.io/project/image2
name: image2
`,
expectedOut: `apiVersion: v1
kind: Pod
metadata:
namespace: default
spec:
containers:
- image: gcr.io/project/image1:tag1
name: image1
- image: gcr.io/project/image2:tag2
name: image2
`,
},
{
description: "two artifacts, combined manifests",
builds: []build.Artifact{
{
ImageName: "gcr.io/project/image1",
Tag: "gcr.io/project/image1:tag1",
},
{
ImageName: "gcr.io/project/image2",
Tag: "gcr.io/project/image2:tag2",
},
},
input: `apiVersion: v1
kind: Pod
spec:
containers:
- image: gcr.io/project/image1
name: image1
---
apiVersion: v1
kind: Pod
spec:
containers:
- image: gcr.io/project/image2
name: image2
`,
expectedOut: `apiVersion: v1
kind: Pod
metadata:
namespace: default
spec:
containers:
- image: gcr.io/project/image1:tag1
name: image1
---
apiVersion: v1
kind: Pod
metadata:
namespace: default
spec:
containers:
- image: gcr.io/project/image2:tag2
name: image2
`,
},
}
for _, test := range tests {
testutil.Run(t, test.description, func(t *testutil.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
t.NewTempDir().
Write("deployment.yaml", test.input).
Chdir()

deployer := deploy.NewKubectlDeployer(&runcontext.RunContext{
WorkingDir: ".",
Cfg: latest.Pipeline{
Deploy: latest.DeployConfig{
DeployType: latest.DeployType{
KubectlDeploy: &latest.KubectlDeploy{
Manifests: []string{"deployment.yaml"},
},
},
},
},
})
var b bytes.Buffer
err := deployer.Render(context.Background(), &b, test.builds, "")
t.CheckErrorAndDeepEqual(false, err, test.expectedOut, b.String())
})
}
}
121 changes: 75 additions & 46 deletions pkg/skaffold/deploy/kubectl.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ limitations under the License.
package deploy

import (
"bufio"
"bytes"
"context"
"fmt"
"io"
"os"
"strings"

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

manifests, err := k.readManifests(ctx)
if err != nil {
event.DeployFailed(err)
return NewDeployErrorResult(errors.Wrap(err, "reading manifests"))
return NewDeployErrorResult(err)
}

for _, m := range k.RemoteManifests {
manifest, err := k.readRemoteManifest(ctx, m)
if err != nil {
return NewDeployErrorResult(errors.Wrap(err, "get remote manifests"))
}

manifests = append(manifests, manifest)
}

if len(k.originalImages) == 0 {
k.originalImages, err = manifests.GetImages()
if err != nil {
return NewDeployErrorResult(errors.Wrap(err, "get images from manifests"))
}
}

logrus.Debugln("manifests", manifests.String())

if len(manifests) == 0 {
event.DeployComplete()
return NewDeploySuccessResult(nil)
}

event.DeployInProgress()

namespaces, err := manifests.CollectNamespaces()
if err != nil {
event.DeployInfoEvent(errors.Wrap(err, "could not fetch deployed resource namespace. "+
"This might cause port-forward and deploy health-check to fail."))
}

manifests, err = manifests.ReplaceImages(builds, k.defaultRepo)
if err != nil {
event.DeployFailed(err)
return NewDeployErrorResult(errors.Wrap(err, "replacing images in manifests"))
}

manifests, err = manifests.SetLabels(merge(labellers...))
if err != nil {
event.DeployFailed(err)
return NewDeployErrorResult(errors.Wrap(err, "setting labels in manifests"))
}

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

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

func (k *KubectlDeployer) Render(context.Context, io.Writer, []build.Artifact, string) error {
return errors.New("not yet implemented")
func (k *KubectlDeployer) Render(ctx context.Context, out io.Writer, builds []build.Artifact, filepath string) error {
manifests, err := k.renderManifests(ctx, out, builds)

if err != nil {
return err
}

manifestOut := out
if filepath != "" {
f, err := os.Open(filepath)
nkubala marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return errors.Wrap(err, "opening file for writing manifests")
}
manifestOut = bufio.NewWriter(f)
}

fmt.Fprintln(manifestOut, manifests.String())
return nil
}

func (k *KubectlDeployer) renderManifests(ctx context.Context, out io.Writer, builds []build.Artifact) (deploy.ManifestList, error) {
if err := k.kubectl.CheckVersion(ctx); err != nil {
color.Default.Fprintln(out, "kubectl client version:", k.kubectl.Version(ctx))
color.Default.Fprintln(out, err)
}

manifests, err := k.readManifests(ctx)
if err != nil {
return nil, errors.Wrap(err, "reading manifests")
}

for _, m := range k.RemoteManifests {
manifest, err := k.readRemoteManifest(ctx, m)
if err != nil {
return nil, errors.Wrap(err, "get remote manifests")
}

manifests = append(manifests, manifest)
}

if len(k.originalImages) == 0 {
k.originalImages, err = manifests.GetImages()
if err != nil {
return nil, errors.Wrap(err, "get images from manifests")
}
}

if len(manifests) == 0 {
return nil, nil
}

manifests, err = manifests.ReplaceImages(builds, k.defaultRepo)
if err != nil {
return nil, errors.Wrap(err, "replacing images in manifests")
}

for _, transform := range manifestTransforms {
manifests, err = transform(manifests, builds, k.insecureRegistries)
if err != nil {
return nil, errors.Wrap(err, "unable to transform manifests")
}
}

return manifests, nil
}
1 change: 0 additions & 1 deletion pkg/skaffold/deploy/kubectl/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ func (c *CLI) ReadManifests(ctx context.Context, manifests []string) (ManifestLi

var manifestList ManifestList
manifestList.Append(buf)
logrus.Debugln("manifests", manifestList.String())

return manifestList, nil
}
Expand Down
Loading