From cb476fb3f4cbc2c081977643b7d386c6a526c570 Mon Sep 17 00:00:00 2001 From: fanmin shi Date: Wed, 28 Feb 2018 16:10:53 -0800 Subject: [PATCH 1/3] pkg/generator: enable code generation for deploy/operator.yaml --- pkg/generator/deploy_tmpl.go | 33 ++++++++++++++++++++++++++++ pkg/generator/gen_deploy.go | 42 ++++++++++++++++++++++++++++++++++++ pkg/generator/generator.go | 10 +++++++++ 3 files changed, 85 insertions(+) create mode 100644 pkg/generator/deploy_tmpl.go create mode 100644 pkg/generator/gen_deploy.go diff --git a/pkg/generator/deploy_tmpl.go b/pkg/generator/deploy_tmpl.go new file mode 100644 index 0000000000..deae1490c5 --- /dev/null +++ b/pkg/generator/deploy_tmpl.go @@ -0,0 +1,33 @@ +package generator + +const operatorYamlTmpl = `apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: {{.KindPlural}}.{{.GroupName}} +spec: + group: {{.GroupName}} + names: + kind: {{.Kind}} + listKind: {{.Kind}}List + plural: {{.KindPlural}} + singular: {{.KindSingular}} + scope: Namespaced + version: {{.Version}} +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: {{.ProjectName}} +spec: + replicas: 1 + template: + metadata: + labels: + name: {{.ProjectName}} + spec: + containers: + - name: {{.ProjectName}} + image: {{.Image}} + command: + - {{.ProjectName}} +` diff --git a/pkg/generator/gen_deploy.go b/pkg/generator/gen_deploy.go new file mode 100644 index 0000000000..98e1521621 --- /dev/null +++ b/pkg/generator/gen_deploy.go @@ -0,0 +1,42 @@ +package generator + +import ( + "io" + "strings" + "text/template" +) + +// OperatorYaml contains all the customized data needed to generate deploy/operator.yaml for a new operator +// when pairing with operatorYamlTmpl template. +type OperatorYaml struct { + Kind string + KindSingular string + KindPlural string + GroupName string + Version string + ProjectName string + Image string +} + +// renderOperatorYaml generates deploy/operator.yaml. +func renderOperatorYaml(w io.Writer, kind, apiVersion, projectName, image string) error { + t := template.New("deploy/operator.yaml") + t, err := t.Parse(operatorYamlTmpl) + if err != nil { + return err + } + + ks := strings.ToLower(kind) + o := OperatorYaml{ + Kind: kind, + KindSingular: ks, + // suffix KindSingular with "s" to create KindPlural. + // TODO: make this more grammatically correct for special nouns. + KindPlural: ks + "s", + GroupName: groupName(apiVersion), + Version: version(apiVersion), + ProjectName: projectName, + Image: image, + } + return t.Execute(w, o) +} diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index c95d6cb7da..f32666728c 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -37,6 +37,7 @@ const ( gopkgtoml = "Gopkg.toml" gopkglock = "Gopkg.lock" config = "config.yaml" + operatorYaml = deployDir + "/operator.yaml" ) type Generator struct { @@ -149,6 +150,15 @@ func (g *Generator) renderDeploy() error { return nil } +// RenderDeployFiles generates "deploy/operator.yaml". +func RenderDeployFiles(c *Config, image string) error { + buf := &bytes.Buffer{} + if err := renderOperatorYaml(buf, c.APIVersion, c.APIVersion, c.ProjectName, image); err != nil { + return err + } + return ioutil.WriteFile(operatorYaml, buf.Bytes(), defaultFileMode) +} + func (g *Generator) renderTmp() error { bDir := filepath.Join(g.projectName, buildDir) if err := os.MkdirAll(bDir, defaultDirFileMode); err != nil { From 365ddacd2592c4dc6a4a84e273671611d6ee7517 Mon Sep 17 00:00:00 2001 From: fanmin shi Date: Wed, 28 Feb 2018 16:11:21 -0800 Subject: [PATCH 2/3] pkg/generator: add TestGenDeploy in generator_test.go --- pkg/generator/generator_test.go | 42 +++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/pkg/generator/generator_test.go b/pkg/generator/generator_test.go index 3fd29516d4..5a78178d1e 100644 --- a/pkg/generator/generator_test.go +++ b/pkg/generator/generator_test.go @@ -289,3 +289,45 @@ func TestGenConfig(t *testing.T) { t.Errorf("want %v, got %v", configExp, buf.String()) } } + +const operatorYamlExp = `apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: appservices.app.example.com +spec: + group: app.example.com + names: + kind: AppService + listKind: AppServiceList + plural: appservices + singular: appservice + scope: Namespaced + version: v1alpha1 +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: app-operator +spec: + replicas: 1 + template: + metadata: + labels: + name: app-operator + spec: + containers: + - name: app-operator + image: quay.io/coreos/operator-sdk-dev:app-operator + command: + - app-operator +` + +func TestGenDeploy(t *testing.T) { + buf := &bytes.Buffer{} + if err := renderOperatorYaml(buf, "AppService", "app.example.com/v1alpha1", "app-operator", "quay.io/coreos/operator-sdk-dev:app-operator"); err != nil { + t.Error(err) + } + if operatorYamlExp != buf.String() { + t.Errorf("want %v, got %v", operatorYamlExp, buf.String()) + } +} From 1ca8e9983c5a1bfb64531a69ba847c683877e607 Mon Sep 17 00:00:00 2001 From: fanmin shi Date: Wed, 28 Feb 2018 16:11:52 -0800 Subject: [PATCH 3/3] commands: build now generates k8s manifest --- commands/operator-sdk/cmd/build.go | 18 +++++++++++++++++- pkg/generator/gen_deploy.go | 9 +++++++-- pkg/generator/generator.go | 2 +- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/commands/operator-sdk/cmd/build.go b/commands/operator-sdk/cmd/build.go index e72a5ebca8..7b10b8479a 100644 --- a/commands/operator-sdk/cmd/build.go +++ b/commands/operator-sdk/cmd/build.go @@ -2,10 +2,14 @@ package cmd import ( "fmt" + "io/ioutil" "os" "os/exec" + "github.com/coreos/operator-sdk/pkg/generator" + "github.com/spf13/cobra" + yaml "gopkg.in/yaml.v2" ) func NewBuildCmd() *cobra.Command { @@ -31,6 +35,7 @@ For example: const ( build = "./tmp/build/build.sh" dockerBuild = "./tmp/build/docker_build.sh" + configYaml = "./config/config.yaml" ) func buildFunc(cmd *cobra.Command, args []string) { @@ -53,5 +58,16 @@ func buildFunc(cmd *cobra.Command, args []string) { ExitWithError(ExitError, fmt.Errorf("failed to output build image %v: (%v)", image, err)) } fmt.Fprintln(os.Stdout, string(o)) - // TODO: generates Kubernetes manifests + + c := &generator.Config{} + fp, err := ioutil.ReadFile(configYaml) + if err != nil { + ExitWithError(ExitError, fmt.Errorf("failed to read config file %v: (%v)", configYaml, err)) + } + if err = yaml.Unmarshal(fp, c); err != nil { + ExitWithError(ExitError, fmt.Errorf("failed to unmarshal config file %v: (%v)", configYaml, err)) + } + if err = generator.RenderDeployFiles(c, image); err != nil { + ExitWithError(ExitError, fmt.Errorf("failed to generate deploy/operator.yaml: (%v)", err)) + } } diff --git a/pkg/generator/gen_deploy.go b/pkg/generator/gen_deploy.go index 98e1521621..6b0a5363b3 100644 --- a/pkg/generator/gen_deploy.go +++ b/pkg/generator/gen_deploy.go @@ -1,11 +1,16 @@ package generator import ( + "fmt" "io" "strings" "text/template" ) +const ( + operatorTmplName = "deploy/operator.yaml" +) + // OperatorYaml contains all the customized data needed to generate deploy/operator.yaml for a new operator // when pairing with operatorYamlTmpl template. type OperatorYaml struct { @@ -20,10 +25,10 @@ type OperatorYaml struct { // renderOperatorYaml generates deploy/operator.yaml. func renderOperatorYaml(w io.Writer, kind, apiVersion, projectName, image string) error { - t := template.New("deploy/operator.yaml") + t := template.New(operatorTmplName) t, err := t.Parse(operatorYamlTmpl) if err != nil { - return err + return fmt.Errorf("failed to parse operator yaml template: %v", err) } ks := strings.ToLower(kind) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index f32666728c..a52da0e421 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -153,7 +153,7 @@ func (g *Generator) renderDeploy() error { // RenderDeployFiles generates "deploy/operator.yaml". func RenderDeployFiles(c *Config, image string) error { buf := &bytes.Buffer{} - if err := renderOperatorYaml(buf, c.APIVersion, c.APIVersion, c.ProjectName, image); err != nil { + if err := renderOperatorYaml(buf, c.Kind, c.APIVersion, c.ProjectName, image); err != nil { return err } return ioutil.WriteFile(operatorYaml, buf.Bytes(), defaultFileMode)