diff --git a/pkg/generator/build_tmpl.go b/pkg/generator/build_tmpls.go similarity index 50% rename from pkg/generator/build_tmpl.go rename to pkg/generator/build_tmpls.go index 6d4924333c..7e80553198 100644 --- a/pkg/generator/build_tmpl.go +++ b/pkg/generator/build_tmpls.go @@ -19,3 +19,24 @@ BUILD_PATH="${REPO_PATH}/cmd/${PROJECT_NAME}" echo "building "${PROJECT_NAME}"..." GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o ${BIN_DIR}/${PROJECT_NAME} $BUILD_PATH ` + +const dockerBuildTmpl = `#!/usr/bin/env bash + +if ! which docker > /dev/null; then + echo "docker needs to be installed" + exit 1 +fi + +: ${IMAGE:?"Need to set IMAGE, e.g. gcr.io//-operator"} + +echo "building container ${IMAGE}..." +docker build -t "${IMAGE}" -f tmp/build/Dockerfile . +` + +const dockerFileTmpl = `FROM alpine:3.6 + +ADD tmp/_output/bin/{{.ProjectName}} /usr/local/bin/{{.ProjectName}} + +RUN adduser -D {{.ProjectName}} +USER {{.ProjectName}} +` diff --git a/pkg/generator/gen_build.go b/pkg/generator/gen_build.go index c58951e329..c1f8ad16a6 100644 --- a/pkg/generator/gen_build.go +++ b/pkg/generator/gen_build.go @@ -12,10 +12,10 @@ type Build struct { ProjectName string } -// renderBuildFile generates the tmp/build.sh file given a repo path ("github.com/coreos/app-operator") +// renderBuildFile generates the tmp/build/build.sh file given a repo path ("github.com/coreos/app-operator") // and projectName ("app-operator"). func renderBuildFile(w io.Writer, repo, projectName string) error { - t := template.New("tmp/build.sh") + t := template.New("tmp/build/build.sh") t, err := t.Parse(buildTmpl) if err != nil { return err @@ -27,3 +27,29 @@ func renderBuildFile(w io.Writer, repo, projectName string) error { } return t.Execute(w, m) } + +// renderDockerBuildFile generates the docker_build.sh script which builds the docker image for this operator. +func renderDockerBuildFile(w io.Writer) error { + _, err := w.Write([]byte(dockerBuildTmpl)) + return err +} + +// DockerFile contains all the customized data needed to generate tmp/build/Dockerfie +// for a new operator when pairing with dockerFileTmpl template. +type DockerFile struct { + ProjectName string +} + +// renderDockerFile generates the tmp/build/Dockerfile file given the projectName ("app-operator"). +func renderDockerFile(w io.Writer, projectName string) error { + t := template.New("tmp/build/Dockerfile") + t, err := t.Parse(dockerFileTmpl) + if err != nil { + return err + } + + df := DockerFile{ + ProjectName: projectName, + } + return t.Execute(w, df) +} diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 6aa9051ed3..c106ff98bc 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -30,6 +30,8 @@ const ( register = "register.go" types = "types.go" build = "build.sh" + dockerBuild = "docker_build.sh" + dockerfile = "Dockerfile" boilerplate = "boilerplate.go.txt" updateGenerated = "update-generated.sh" ) @@ -142,7 +144,23 @@ func renderBuildFiles(buildDir, repoPath, projectName string) error { if err := renderBuildFile(buf, repoPath, projectName); err != nil { return err } - return ioutil.WriteFile(filepath.Join(buildDir, build), buf.Bytes(), defaultExecFileMode) + if err := ioutil.WriteFile(filepath.Join(buildDir, build), buf.Bytes(), defaultExecFileMode); err != nil { + return err + } + + buf = &bytes.Buffer{} + if err := renderDockerBuildFile(buf); err != nil { + return err + } + if err := ioutil.WriteFile(filepath.Join(buildDir, dockerBuild), buf.Bytes(), defaultExecFileMode); err != nil { + return err + } + + buf = &bytes.Buffer{} + if err := renderDockerFile(buf, projectName); err != nil { + return err + } + return ioutil.WriteFile(filepath.Join(buildDir, dockerfile), buf.Bytes(), defaultFileMode) } func renderCodegenFiles(codegenDir, repoPath, apiDirName, version, projectName string) error { diff --git a/pkg/generator/generator_test.go b/pkg/generator/generator_test.go index a965a8677a..2a2c8d4f62 100644 --- a/pkg/generator/generator_test.go +++ b/pkg/generator/generator_test.go @@ -166,15 +166,42 @@ echo "building "${PROJECT_NAME}"..." GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o ${BIN_DIR}/${PROJECT_NAME} $BUILD_PATH ` +const dockerFileExp = `FROM alpine:3.6 + +ADD tmp/_output/bin/play /usr/local/bin/play + +RUN adduser -D play +USER play +` + func TestGenBuild(t *testing.T) { buf := &bytes.Buffer{} - if err := renderBuildFile(buf, "github.com/coreos/play", "play"); err != nil { + projectName := "play" + if err := renderBuildFile(buf, "github.com/coreos/play", projectName); err != nil { t.Error(err) return } if buildExp != buf.String() { t.Errorf("want %v, got %v", buildExp, buf.String()) } + + buf = &bytes.Buffer{} + if err := renderDockerBuildFile(buf); err != nil { + t.Error(err) + return + } + if dockerBuildTmpl != buf.String() { + t.Errorf("want %v, got %v", dockerBuildTmpl, buf.String()) + } + + buf = &bytes.Buffer{} + if err := renderDockerFile(buf, projectName); err != nil { + t.Error(err) + return + } + if dockerFileExp != buf.String() { + t.Errorf("want %v, got %v", dockerFileExp, buf.String()) + } } const boilerplateExp = `/*