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

Autogenerate k8s manifests in skaffold init #3703

Merged
merged 5 commits into from
Mar 2, 2020
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
52 changes: 28 additions & 24 deletions cmd/skaffold/app/cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,18 @@ import (
const maxFileSize = 1024 * 1024 * 512

var (
composeFile string
cliArtifacts []string
cliKubernetesManifests []string
skipBuild bool
skipDeploy bool
force bool
analyze bool
enableJibInit bool
enableBuildpacksInit bool
enableNewInitFormat bool
buildpacksBuilder string
composeFile string
cliArtifacts []string
cliKubernetesManifests []string
skipBuild bool
skipDeploy bool
force bool
analyze bool
enableJibInit bool
enableBuildpacksInit bool
enableNewInitFormat bool
enableManifestGeneration bool
buildpacksBuilder string
)

// for testing
Expand Down Expand Up @@ -68,24 +69,27 @@ func NewCmdInit() *cobra.Command {
f.MarkHidden("XXenableBuildpacksInit")
f.StringVar(&buildpacksBuilder, "XXdefaultBuildpacksBuilder", "heroku/buildpacks", "")
f.MarkHidden("XXdefaultBuildpacksBuilder")
f.BoolVar(&enableManifestGeneration, "XXenableManifestGeneration", false, "")
f.MarkHidden("XXenableManifestGeneration")
}).
NoArgs(cancelWithCtrlC(context.Background(), doInit))
}

func doInit(ctx context.Context, out io.Writer) error {
return initEntrypoint(ctx, out, config.Config{
ComposeFile: composeFile,
CliArtifacts: cliArtifacts,
CliKubernetesManifests: cliKubernetesManifests,
SkipBuild: skipBuild,
SkipDeploy: skipDeploy,
Force: force,
Analyze: analyze,
EnableJibInit: enableJibInit,
EnableBuildpacksInit: enableBuildpacksInit,
EnableNewInitFormat: enableNewInitFormat || enableBuildpacksInit || enableJibInit,
BuildpacksBuilder: buildpacksBuilder,
Opts: opts,
MaxFileSize: maxFileSize,
ComposeFile: composeFile,
CliArtifacts: cliArtifacts,
CliKubernetesManifests: cliKubernetesManifests,
SkipBuild: skipBuild,
SkipDeploy: skipDeploy,
Force: force,
Analyze: analyze,
EnableJibInit: enableJibInit,
EnableBuildpacksInit: enableBuildpacksInit,
EnableNewInitFormat: enableNewInitFormat || enableBuildpacksInit || enableJibInit,
EnableManifestGeneration: enableManifestGeneration,
BuildpacksBuilder: buildpacksBuilder,
Opts: opts,
MaxFileSize: maxFileSize,
})
}
53 changes: 53 additions & 0 deletions integration/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,48 @@ func TestInitCompose(t *testing.T) {
}
}

func TestInitManifestGeneration(t *testing.T) {
if testing.Short() || RunOnGCP() {
t.Skip("skipping kind integration test")
}

tests := []struct {
name string
dir string
args []string
expectedManifestPaths []string
}{
{
name: "hello",
dir: "testdata/init/hello",
args: []string{"--XXenableManifestGeneration"},
expectedManifestPaths: []string{"deployment.yaml"},
},
// TODO(nkubala): add this back when the --force flag is fixed
nkubala marked this conversation as resolved.
Show resolved Hide resolved
// {
// name: "microservices",
// dir: "testdata/init/microservices",
// args: []string{"--XXenableManifestGeneration"},
// expectedManifestPaths: []string{"leeroy-web/deployment.yaml", "leeroy-app/deployment.yaml"},
// },
}

for _, test := range tests {
testutil.Run(t, test.name, func(t *testutil.T) {
ns, _, deleteNs := SetupNamespace(t.T)
defer deleteNs()

initArgs := append([]string{"--force"}, test.args...)
skaffold.Init(initArgs...).InDir(test.dir).WithConfig("skaffold.yaml.out").RunOrFail(t.T)

checkGeneratedManifests(t, test.dir, test.expectedManifestPaths)

// Make sure the skaffold yaml and the kubernetes manifests created by kompose are ok
skaffold.Run().InDir(test.dir).WithConfig("skaffold.yaml.out").InNs(ns.Name).RunOrFail(t.T)
})
}
}

func checkGeneratedConfig(t *testutil.T, dir string) {
expectedOutput, err := ioutil.ReadFile(filepath.Join(dir, "skaffold.yaml"))
t.CheckNoError(err)
Expand All @@ -65,3 +107,14 @@ func checkGeneratedConfig(t *testutil.T, dir string) {
t.CheckNoError(err)
t.CheckDeepEqual(string(expectedOutput), string(output))
}

func checkGeneratedManifests(t *testutil.T, dir string, manifestPaths []string) {
for _, path := range manifestPaths {
expectedOutput, err := ioutil.ReadFile(filepath.Join(dir, path+".expected"))
t.CheckNoError(err)

output, err := ioutil.ReadFile(filepath.Join(dir, path))
t.CheckNoError(err)
t.CheckDeepEqual(string(expectedOutput), string(output))
}
}
3 changes: 2 additions & 1 deletion integration/testdata/init/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
skaffold.yaml.out
**/deployment.yaml
**/skaffold.yaml.out
7 changes: 7 additions & 0 deletions integration/testdata/init/hello/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM golang:1.12.9-alpine3.10 as builder
COPY hello.go .
RUN go build -o /app hello.go

FROM alpine:3.10
CMD ["./app"]
COPY --from=builder /app .
30 changes: 30 additions & 0 deletions integration/testdata/init/hello/deployment.yaml.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
apiVersion: v1
kind: Service
metadata:
name: dockerfile-image
nkubala marked this conversation as resolved.
Show resolved Hide resolved
labels:
app: dockerfile-image
spec:
clusterIP: None
selector:
app: dockerfile-image
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dockerfile-image
labels:
app: dockerfile-image
spec:
replicas: 1
selector:
matchLabels:
app: dockerfile-image
template:
metadata:
labels:
app: dockerfile-image
spec:
containers:
- name: dockerfile-image
image: dockerfile-image
14 changes: 14 additions & 0 deletions integration/testdata/init/hello/hello.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import (
"fmt"
"time"
)

func main() {
for {
fmt.Println("Hello world!")

time.Sleep(time.Second * 1)
}
}
7 changes: 7 additions & 0 deletions integration/testdata/init/microservices/leeroy-app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM golang:1.12.9-alpine3.10 as builder
COPY app.go .
RUN go build -o /app .

FROM alpine:3.10
CMD ["./app"]
COPY --from=builder /app .
17 changes: 17 additions & 0 deletions integration/testdata/init/microservices/leeroy-app/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

import (
"fmt"
"log"
"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "leeroooooy app!!\n")
}

func main() {
log.Print("leeroy app server ready")
http.HandleFunc("/", handler)
http.ListenAndServe(":50051", nil)
}
7 changes: 7 additions & 0 deletions integration/testdata/init/microservices/leeroy-web/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM golang:1.12.9-alpine3.10 as builder
COPY web.go .
RUN go build -o /web .

FROM alpine:3.10
CMD ["./web"]
COPY --from=builder /web .
25 changes: 25 additions & 0 deletions integration/testdata/init/microservices/leeroy-web/web.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

import (
"io"
"net/http"

"log"
)

func handler(w http.ResponseWriter, r *http.Request) {
resp, err := http.Get("http://leeroy-app:50051")
if err != nil {
panic(err)
}
defer resp.Body.Close()
if _, err := io.Copy(w, resp.Body); err != nil {
panic(err)
}
}

func main() {
log.Print("leeroy web server ready")
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
20 changes: 16 additions & 4 deletions pkg/skaffold/initializer/build/builders.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,23 @@ type BuilderImagePair struct {
ImageName string
}

// GeneratedBuilderImagePair pairs a discovered builder with a
// generated image name, and the path to the manifest that should be generated
type GeneratedBuilderImagePair struct {
BuilderImagePair
ManifestPath string
}

type Initializer interface {
// ProcessImages is the entrypoint call, and handles the pairing of all builders
// contained in the initializer with the provided images from the deploy initializer
ProcessImages([]string) error
// BuildConfig returns the processed build config to be written to the skaffold.yaml
BuildConfig() latest.BuildConfig
BuilderImagePairs() []BuilderImagePair
// PrintAnalysis writes the project analysis to the provided out stream
PrintAnalysis(io.Writer) error
// GenerateManifests generates image names and manifests for all unresolved pairs
GenerateManifests() (map[GeneratedBuilderImagePair][]byte, error)
}

type emptyBuildInitializer struct {
Expand All @@ -73,12 +85,12 @@ func (e *emptyBuildInitializer) BuildConfig() latest.BuildConfig {
return latest.BuildConfig{}
}

func (e *emptyBuildInitializer) BuilderImagePairs() []BuilderImagePair {
func (e *emptyBuildInitializer) PrintAnalysis(io.Writer) error {
return nil
}

func (e *emptyBuildInitializer) PrintAnalysis(io.Writer) error {
return nil
func (e *emptyBuildInitializer) GenerateManifests() (map[GeneratedBuilderImagePair][]byte, error) {
return nil, nil
}

func NewInitializer(builders []InitBuilder, c config.Config) Initializer {
Expand Down
49 changes: 39 additions & 10 deletions pkg/skaffold/initializer/build/builders_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,26 @@ package build
import (
"testing"

"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/prompt"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/warnings"
"github.com/google/go-cmp/cmp"

"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/buildpacks"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/jib"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/prompt"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/warnings"
"github.com/GoogleContainerTools/skaffold/testutil"
)

func TestResolveBuilderImages(t *testing.T) {
tests := []struct {
description string
buildConfigs []InitBuilder
images []string
force bool
shouldMakeChoice bool
shouldErr bool
expectedPairs []BuilderImagePair
description string
buildConfigs []InitBuilder
images []string
force bool
shouldMakeChoice bool
shouldErr bool
expectedPairs []BuilderImagePair
expectedGeneratedPairs []GeneratedBuilderImagePair
}{
{
description: "nothing to choose from",
Expand Down Expand Up @@ -72,6 +74,15 @@ func TestResolveBuilderImages(t *testing.T) {
ImageName: "image2",
},
},
expectedGeneratedPairs: []GeneratedBuilderImagePair{
{
BuilderImagePair: BuilderImagePair{
Builder: jib.ArtifactConfig{BuilderName: "Jib Maven Plugin", File: "pom.xml", Project: "project"},
ImageName: "pom.xml-image",
},
ManifestPath: "deployment.yaml",
},
},
},
{
description: "successful force",
Expand All @@ -94,6 +105,23 @@ func TestResolveBuilderImages(t *testing.T) {
force: true,
shouldErr: true,
},
{
description: "one unresolved image",
buildConfigs: []InitBuilder{docker.ArtifactConfig{File: "foo"}},
images: []string{},
expectedGeneratedPairs: []GeneratedBuilderImagePair{
{
BuilderImagePair: BuilderImagePair{
Builder: docker.ArtifactConfig{File: "foo"},
ImageName: "foo-image",
},
ManifestPath: "deployment.yaml",
},
},
shouldMakeChoice: false,
force: false,
shouldErr: false,
},
}
for _, test := range tests {
testutil.Run(t, test.description, func(t *testutil.T) {
Expand All @@ -111,7 +139,8 @@ func TestResolveBuilderImages(t *testing.T) {
unresolvedImages: test.images,
}
err := initializer.resolveBuilderImages()
t.CheckErrorAndDeepEqual(test.shouldErr, err, test.expectedPairs, initializer.BuilderImagePairs())
t.CheckErrorAndDeepEqual(test.shouldErr, err, test.expectedPairs, initializer.builderImagePairs, cmp.AllowUnexported())
t.CheckDeepEqual(test.expectedGeneratedPairs, initializer.generatedBuilderImagePairs, cmp.AllowUnexported())
})
}
}
Expand Down
8 changes: 4 additions & 4 deletions pkg/skaffold/initializer/build/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ func (c *cliBuildInitializer) BuildConfig() latest.BuildConfig {
}
}

func (c *cliBuildInitializer) BuilderImagePairs() []BuilderImagePair {
return c.builderImagePairs
}

func (c *cliBuildInitializer) PrintAnalysis(out io.Writer) error {
return printAnalysis(out, c.enableNewFormat, c.skipBuild, c.builderImagePairs, c.builders, nil)
}

func (c *cliBuildInitializer) GenerateManifests() (map[GeneratedBuilderImagePair][]byte, error) {
return nil, nil
}

func (c *cliBuildInitializer) processCliArtifacts() error {
pairs, err := processCliArtifacts(c.cliArtifacts)
if err != nil {
Expand Down
Loading