From 20d59a60b5e41665bdab5f21b70abf44c99a8a31 Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Thu, 7 Jun 2018 14:51:07 -0700 Subject: [PATCH 01/21] Make template data struct, directory generator, and generic file writer --- pkg/generator/generator.go | 94 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index df41ae34c2..2b90f5880c 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -17,10 +17,12 @@ package generator import ( "bytes" "fmt" + "io" "io/ioutil" "os" "path/filepath" "strings" + "text/template" ) const ( @@ -397,6 +399,98 @@ func renderStubFiles(stubDir, repoPath, kind, apiDirName, version string) error return writeFileAndPrint(filepath.Join(stubDir, handler), buf.Bytes(), defaultFileMode) } +type tmplData struct { + VersoinNumber string + + OperatorSDKImport string + StubImport string + K8sutilImport string + SDKVersionImport string + + APIVersion string + Kind string + + RepoPath string + APIDirName string + Version string + + ProjectName string + GroupName string + + KindSingular string + KindPlural string + + Image string + Name string +} + +func (g *Generator) generateDirStructure() error { + if err := os.MkdirAll(g.projectName, defaultDirFileMode); err != nil { + return err + } + + cpDir := filepath.Join(g.projectName, cmdDir, g.projectName) + if err := os.MkdirAll(cpDir, defaultDirFileMode); err != nil { + return err + } + + cp := filepath.Join(g.projectName, configDir) + if err := os.MkdirAll(cp, defaultDirFileMode); err != nil { + return err + } + + dp := filepath.Join(g.projectName, deployDir) + if err := os.MkdirAll(dp, defaultDirFileMode); err != nil { + return err + } + + repoPath, err := os.Getwd() + if err != nil { + return err + } + olmDir := filepath.Join(repoPath, olmCatalogDir) + if err := os.MkdirAll(olmDir, defaultDirFileMode); err != nil { + return err + } + + bDir := filepath.Join(g.projectName, buildDir) + if err := os.MkdirAll(bDir, defaultDirFileMode); err != nil { + return err + } + cDir := filepath.Join(g.projectName, codegenDir) + if err := os.MkdirAll(cDir, defaultDirFileMode); err != nil { + return err + } + + if err := os.MkdirAll(filepath.Join(g.projectName, versionDir), defaultDirFileMode); err != nil { + return err + } + + v := version(g.apiVersion) + adn := apiDirName(g.apiVersion) + apiDir := filepath.Join(g.projectName, apisDir, adn, v) + if err := os.MkdirAll(apiDir, defaultDirFileMode); err != nil { + return err + } + sDir := filepath.Join(g.projectName, stubDir) + if err := os.MkdirAll(sDir, defaultDirFileMode); err != nil { + return err + } + + return nil +} + +func renderGenericFile(w io.Writer, fileLoc string, fileTmpl string, info tmplData) error { + t := template.New(fileLoc) + + t, err := t.Parse(fileTmpl) + if err != nil { + return err + } + + return t.Execute(w, info) +} + // version extracts the VERSION from the given apiVersion ($GROUP_NAME/$VERSION). func version(apiVersion string) string { return strings.Split(apiVersion, "/")[1] From 3d8865a538eb0c9354f651aa61a66d57095640d5 Mon Sep 17 00:00:00 2001 From: Etienne Coutaud Date: Fri, 1 Jun 2018 11:02:24 +0200 Subject: [PATCH 02/21] commands/up: Add OPERATOR_NAME env var when run locally --- Gopkg.lock | 2 +- Gopkg.toml | 4 +++ pkg/generator/gen_deploy_test.go | 49 ++++++++++++++++++++++++++++++++ pkg/generator/gen_main_test.go | 9 ++++++ pkg/generator/generator.go | 2 ++ pkg/generator/templates.go | 14 +++++++-- 6 files changed, 76 insertions(+), 4 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index f8180644e3..787bc5ab10 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -404,6 +404,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "d5cc928bcf8f796babddedb13b1516b8d6fbc2f48d68546b712af753671673e2" + inputs-digest = "f310ffe8b6a0cff2978d4f2e11c7f32dcb008225c1c9193e9f7da20f34935189" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 5a72d67e2e..492b98e2b4 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -6,6 +6,10 @@ name = "github.com/spf13/cobra" version = "0.0.2" +[[override]] + name = "github.com/prometheus/client_golang" + version = "0.8.0" + [[override]] name = "k8s.io/api" version = "kubernetes-1.9.3" diff --git a/pkg/generator/gen_deploy_test.go b/pkg/generator/gen_deploy_test.go index d9586f54d8..3e92e231b4 100644 --- a/pkg/generator/gen_deploy_test.go +++ b/pkg/generator/gen_deploy_test.go @@ -24,6 +24,8 @@ const operatorYamlExp = `apiVersion: apps/v1 kind: Deployment metadata: name: app-operator + labels: + name: app-operator spec: replicas: 1 selector: @@ -37,6 +39,9 @@ spec: containers: - name: app-operator image: quay.io/example-inc/app-operator:0.0.1 + ports: + - containerPort: 9090 + name: metrics command: - app-operator imagePullPolicy: Always @@ -95,6 +100,34 @@ roleRef: apiGroup: rbac.authorization.k8s.io ` +const serviceYamlExp = `apiVersion: v1 +kind: Service +metadata: + name: app-operator + labels: + name: app-operator +spec: + selector: + name: app-operator + ports: + - protocol: TCP + targetPort: metrics + port: 9090 + name: metrics` + +const serviceMonitorYamlExp = `apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: app-operator + labels: + name: app-operator +spec: + selector: + matchLabels: + name: app-operator + endpoints: + - port: metrics` + func TestGenDeploy(t *testing.T) { buf := &bytes.Buffer{} if err := renderCRDYaml(buf, appKind, appAPIVersion); err != nil { @@ -119,4 +152,20 @@ func TestGenDeploy(t *testing.T) { if rbacYamlExp != buf.String() { t.Errorf(errorMessage, rbacYamlExp, buf.String()) } + + buf = &bytes.Buffer{} + if err := renderServiceYaml(buf, appProjectName); err != nil { + t.Error(err) + } + if serviceYamlExp != buf.String() { + t.Errorf("want %v, got %v", serviceYamlExp, buf.String()) + } + + buf = &bytes.Buffer{} + if err := renderServiceMonitorYaml(buf, appProjectName); err != nil { + t.Error(err) + } + if serviceMonitorYamlExp != buf.String() { + t.Errorf("want %v, got %v", serviceMonitorYamlExp, buf.String()) + } } diff --git a/pkg/generator/gen_main_test.go b/pkg/generator/gen_main_test.go index 41b1ca995f..55650bd9ed 100644 --- a/pkg/generator/gen_main_test.go +++ b/pkg/generator/gen_main_test.go @@ -24,24 +24,33 @@ const mainExp = `package main import ( "context" "runtime" + "net/http" stub "github.com/example-inc/app-operator/pkg/stub" sdk "github.com/operator-framework/operator-sdk/pkg/sdk" k8sutil "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" sdkVersion "github.com/operator-framework/operator-sdk/version" + "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/sirupsen/logrus" ) +// Prometheus metrics port +const promPort = ":9090" + func printVersion() { logrus.Infof("Go Version: %s", runtime.Version()) logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) + logrus.Infof("operator prometheus port :%s", promPort) } func main() { printVersion() + http.Handle("/metrics", promhttp.Handler()) + logrus.Fatalf("%s", http.ListenAndServe(promPort, nil)) + resource := "app.example.com/v1alpha1" kind := "AppService" namespace, err := k8sutil.GetWatchNamespace() diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index df41ae34c2..7b3ff097e9 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -55,6 +55,8 @@ const ( gopkglock = "Gopkg.lock" config = "config.yaml" operatorYaml = deployDir + "/operator.yaml" + serviceYaml = "service.yaml" + serviceMonitorYaml = "serviceMonitor.yaml" rbacYaml = "rbac.yaml" crYaml = "cr.yaml" catalogPackageYaml = "package.yaml" diff --git a/pkg/generator/templates.go b/pkg/generator/templates.go index cdfe30a380..8a4dbfd256 100644 --- a/pkg/generator/templates.go +++ b/pkg/generator/templates.go @@ -136,20 +136,28 @@ import ( stub "{{.StubImport}}" sdk "{{.OperatorSDKImport}}" k8sutil "{{.K8sutilImport}}" - sdkVersion "{{.SDKVersionImport}}" - + sdkVersion "{{.SDKVersionImport}}" + + "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/sirupsen/logrus" ) +// Prometheus metrics port +const promPort = ":9090" + func printVersion() { logrus.Infof("Go Version: %s", runtime.Version()) logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) - logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) + logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) + logrus.Infof("operator prometheus port :%s", promPort) } func main() { printVersion() + http.Handle("/metrics", promhttp.Handler()) + logrus.Fatalf("%s", http.ListenAndServe(promPort, nil)) + resource := "{{.APIVersion}}" kind := "{{.Kind}}" namespace, err := k8sutil.GetWatchNamespace() From f862a624d92fc46a3549890d3ef93a1a7bc6f22e Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Fri, 8 Jun 2018 09:19:33 -0700 Subject: [PATCH 03/21] generic render function working for versioning --- pkg/generator/generator.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 2b90f5880c..519c7db804 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -303,9 +303,10 @@ func (g *Generator) renderVersion() error { return err } - if err := renderVersionFile(buf, "0.0.1"); err != nil { + if err := renderGenericFile(buf, "version/version.go", versionTmpl, tmplData{VersionNumber: "0.0.1"}); err != nil { return err } + return writeFileAndPrint(filepath.Join(g.projectName, versionDir, versionfile), buf.Bytes(), defaultFileMode) } @@ -400,7 +401,7 @@ func renderStubFiles(stubDir, repoPath, kind, apiDirName, version string) error } type tmplData struct { - VersoinNumber string + VersionNumber string OperatorSDKImport string StubImport string From e1a7a5e8b7b8a47e04ee51f6569b403be87f68fb Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Fri, 8 Jun 2018 11:23:00 -0700 Subject: [PATCH 04/21] Removed redundant render functions and files --- pkg/generator/gen_api_doc.go | 42 ------ pkg/generator/gen_api_register.go | 51 ------- pkg/generator/gen_api_register_test.go | 68 ---------- pkg/generator/gen_api_types.go | 42 ------ pkg/generator/gen_api_types_test.go | 62 --------- pkg/generator/gen_build.go | 69 ---------- pkg/generator/gen_build_test.go | 77 ----------- pkg/generator/gen_codegen.go | 62 --------- pkg/generator/gen_codegen_test.go | 65 --------- pkg/generator/gen_deploy.go | 121 ----------------- pkg/generator/gen_deploy_test.go | 122 ----------------- pkg/generator/gen_handler.go | 50 ------- pkg/generator/gen_handler_test.go | 101 -------------- pkg/generator/gen_main.go | 60 --------- pkg/generator/gen_main_test.go | 69 ---------- pkg/generator/gen_olm_catalog.go | 121 ----------------- pkg/generator/gen_version.go | 40 ------ pkg/generator/gen_version_test.go | 39 ------ pkg/generator/generator.go | 176 ++++++++++++++++++------- 19 files changed, 128 insertions(+), 1309 deletions(-) delete mode 100644 pkg/generator/gen_api_doc.go delete mode 100644 pkg/generator/gen_api_register.go delete mode 100644 pkg/generator/gen_api_register_test.go delete mode 100644 pkg/generator/gen_api_types.go delete mode 100644 pkg/generator/gen_api_types_test.go delete mode 100644 pkg/generator/gen_build.go delete mode 100644 pkg/generator/gen_build_test.go delete mode 100644 pkg/generator/gen_codegen.go delete mode 100644 pkg/generator/gen_codegen_test.go delete mode 100644 pkg/generator/gen_deploy.go delete mode 100644 pkg/generator/gen_deploy_test.go delete mode 100644 pkg/generator/gen_handler.go delete mode 100644 pkg/generator/gen_handler_test.go delete mode 100644 pkg/generator/gen_main.go delete mode 100644 pkg/generator/gen_main_test.go delete mode 100644 pkg/generator/gen_olm_catalog.go delete mode 100644 pkg/generator/gen_version.go delete mode 100644 pkg/generator/gen_version_test.go diff --git a/pkg/generator/gen_api_doc.go b/pkg/generator/gen_api_doc.go deleted file mode 100644 index bfb9f3f476..0000000000 --- a/pkg/generator/gen_api_doc.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "io" - "text/template" -) - -// Doc contains all the customized data needed to generate apis///doc.go for a new operator -// when pairing with apisDocTmpl template. -type Doc struct { - GroupName string - Version string -} - -// renderAPIDocFile generates the apis///doc.go file. -func renderAPIDocFile(w io.Writer, groupName, version string) error { - t := template.New("apis///doc.go") - t, err := t.Parse(apiDocTmpl) - if err != nil { - return err - } - - d := Doc{ - GroupName: groupName, - Version: version, - } - return t.Execute(w, d) -} diff --git a/pkg/generator/gen_api_register.go b/pkg/generator/gen_api_register.go deleted file mode 100644 index b5e2d756f2..0000000000 --- a/pkg/generator/gen_api_register.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "io" - "strings" - "text/template" -) - -const pluralSuffix = "s" - -// Register contains all the customized data needed to generate apis///register.go -// for a new operator when pairing with apisDocTmpl template. -type Register struct { - GroupName string - Version string - Kind string - KindPlural string -} - -// renderAPIRegisterFile generates the apis///register.go file. -func renderAPIRegisterFile(w io.Writer, kind, groupName, version string) error { - t := template.New("apis///register.go") - t, err := t.Parse(apiRegisterTmpl) - if err != nil { - return err - } - - d := Register{ - GroupName: groupName, - Version: version, - Kind: kind, - // TODO: adding "s" to make a word plural is too native - // and is wrong for many special nouns. Make this better. - KindPlural: strings.ToLower(kind) + pluralSuffix, - } - return t.Execute(w, d) -} diff --git a/pkg/generator/gen_api_register_test.go b/pkg/generator/gen_api_register_test.go deleted file mode 100644 index 443c2831d6..0000000000 --- a/pkg/generator/gen_api_register_test.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "bytes" - "testing" -) - -const registerExp = `package v1alpha1 - -import ( - sdkK8sutil "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -const ( - version = "v1alpha1" - groupName = "app.example.com" -) - -var ( - SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) - AddToScheme = SchemeBuilder.AddToScheme - // SchemeGroupVersion is the group version used to register these objects. - SchemeGroupVersion = schema.GroupVersion{Group: groupName, Version: version} -) - -func init() { - sdkK8sutil.AddToSDKScheme(AddToScheme) -} - -// addKnownTypes adds the set of types defined in this package to the supplied scheme. -func addKnownTypes(scheme *runtime.Scheme) error { - scheme.AddKnownTypes(SchemeGroupVersion, - &AppService{}, - &AppServiceList{}, - ) - metav1.AddToGroupVersion(scheme, SchemeGroupVersion) - return nil -} -` - -func TestGenRegister(t *testing.T) { - buf := &bytes.Buffer{} - if err := renderAPIRegisterFile(buf, appKind, appGroupName, appVersion); err != nil { - t.Error(err) - return - } - if registerExp != buf.String() { - t.Errorf(errorMessage, registerExp, buf.String()) - } -} diff --git a/pkg/generator/gen_api_types.go b/pkg/generator/gen_api_types.go deleted file mode 100644 index 46b39aa666..0000000000 --- a/pkg/generator/gen_api_types.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "io" - "text/template" -) - -// Types contains all the customized data needed to generate apis///types.go -// for a new operator when pairing with apisTypesTmpl template. -type Types struct { - Version string - Kind string -} - -// renderAPITypesFile generates the apis///types.go file. -func renderAPITypesFile(w io.Writer, kind, version string) error { - t := template.New("apis///types.go") - t, err := t.Parse(apiTypesTmpl) - if err != nil { - return err - } - - types := Types{ - Version: version, - Kind: kind, - } - return t.Execute(w, types) -} diff --git a/pkg/generator/gen_api_types_test.go b/pkg/generator/gen_api_types_test.go deleted file mode 100644 index b49062446a..0000000000 --- a/pkg/generator/gen_api_types_test.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "bytes" - "testing" -) - -const typesExp = `package app.example.com/v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -type AppServiceList struct { - metav1.TypeMeta ` + "`" + `json:",inline"` + "`\n" + - ` metav1.ListMeta ` + "`" + `json:"metadata"` + "`\n" + - ` Items []AppService ` + "`" + `json:"items"` + "`" + ` -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -type AppService struct { - metav1.TypeMeta ` + "`" + `json:",inline"` + "`\n" + - ` metav1.ObjectMeta ` + "`" + `json:"metadata"` + "`\n" + - ` Spec AppServiceSpec ` + "`" + `json:"spec"` + "`\n" + - ` Status AppServiceStatus ` + "`" + `json:"status,omitempty"` + "`" + ` -} - -type AppServiceSpec struct { - // Fill me -} -type AppServiceStatus struct { - // Fill me -} -` - -func TestGenTypes(t *testing.T) { - buf := &bytes.Buffer{} - if err := renderAPITypesFile(buf, appKind, appAPIVersion); err != nil { - t.Error(err) - return - } - if typesExp != buf.String() { - t.Errorf(errorMessage, typesExp, buf.String()) - } -} diff --git a/pkg/generator/gen_build.go b/pkg/generator/gen_build.go deleted file mode 100644 index 88122461d3..0000000000 --- a/pkg/generator/gen_build.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "io" - "text/template" -) - -// Build contains all the customized data needed to generate tmp/build.sh -// for a new operator when pairing with buildTmpl template. -type Build struct { - RepoPath string - ProjectName string -} - -// 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/build.sh") - t, err := t.Parse(buildTmpl) - if err != nil { - return err - } - - m := Build{ - RepoPath: repo, - ProjectName: projectName, - } - 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/gen_build_test.go b/pkg/generator/gen_build_test.go deleted file mode 100644 index 7b28f49bca..0000000000 --- a/pkg/generator/gen_build_test.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "bytes" - "testing" -) - -const buildExp = `#!/usr/bin/env bash - -set -o errexit -set -o nounset -set -o pipefail - -if ! which go > /dev/null; then - echo "golang needs to be installed" - exit 1 -fi - -BIN_DIR="$(pwd)/tmp/_output/bin" -mkdir -p ${BIN_DIR} -PROJECT_NAME="app-operator" -REPO_PATH="github.com/example-inc/app-operator" -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 dockerFileExp = `FROM alpine:3.6 - -RUN adduser -D app-operator -USER app-operator - -ADD tmp/_output/bin/app-operator /usr/local/bin/app-operator -` - -func TestGenBuild(t *testing.T) { - buf := &bytes.Buffer{} - if err := renderBuildFile(buf, appRepoPath, appProjectName); err != nil { - t.Error(err) - return - } - if buildExp != buf.String() { - t.Errorf(errorMessage, buildExp, buf.String()) - } - - buf = &bytes.Buffer{} - if err := renderDockerBuildFile(buf); err != nil { - t.Error(err) - return - } - if dockerBuildTmpl != buf.String() { - t.Errorf(errorMessage, dockerBuildTmpl, buf.String()) - } - - buf = &bytes.Buffer{} - if err := renderDockerFile(buf, appProjectName); err != nil { - t.Error(err) - return - } - if dockerFileExp != buf.String() { - t.Errorf(errorMessage, dockerFileExp, buf.String()) - } -} diff --git a/pkg/generator/gen_codegen.go b/pkg/generator/gen_codegen.go deleted file mode 100644 index f163c5cee4..0000000000 --- a/pkg/generator/gen_codegen.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "io" - "text/template" -) - -// Boilerplate contains all the customized data needed to generate codegen/boilerplate.go.txt -// for a new operator when pairing with boilerplateTmpl template. -type Boilerplate struct { - ProjectName string -} - -// UpdateGenerated contains all the customized data needed to generate codegen/update-generated.sh -// for a new operator when pairing with updateGeneratedTmpl template. -type UpdateGenerated struct { - RepoPath string - APIDirName string - Version string -} - -func renderBoilerplateFile(w io.Writer, projectName string) error { - t := template.New("codegen/boilerplate.go.txt") - t, err := t.Parse(boilerplateTmpl) - if err != nil { - return err - } - - b := Boilerplate{ - ProjectName: projectName, - } - return t.Execute(w, b) -} - -func renderUpdateGeneratedFile(w io.Writer, repo, apiDirName, version string) error { - t := template.New("codegen/update-generated.sh") - t, err := t.Parse(updateGeneratedTmpl) - if err != nil { - return err - } - - b := UpdateGenerated{ - RepoPath: repo, - APIDirName: apiDirName, - Version: version, - } - return t.Execute(w, b) -} diff --git a/pkg/generator/gen_codegen_test.go b/pkg/generator/gen_codegen_test.go deleted file mode 100644 index f43b89df3e..0000000000 --- a/pkg/generator/gen_codegen_test.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "bytes" - "testing" -) - -const boilerplateExp = ` -` - -const updateGeneratedExp = `#!/usr/bin/env bash - -set -o errexit -set -o nounset -set -o pipefail - -DOCKER_REPO_ROOT="/go/src/github.com/example-inc/app-operator" -IMAGE=${IMAGE:-"gcr.io/coreos-k8s-scale-testing/codegen:1.9.3"} - -docker run --rm \ - -v "$PWD":"$DOCKER_REPO_ROOT":Z \ - -w "$DOCKER_REPO_ROOT" \ - "$IMAGE" \ - "/go/src/k8s.io/code-generator/generate-groups.sh" \ - "deepcopy" \ - "github.com/example-inc/app-operator/pkg/generated" \ - "github.com/example-inc/app-operator/pkg/apis" \ - "app:v1alpha1" \ - --go-header-file "./tmp/codegen/boilerplate.go.txt" \ - $@ -` - -func TestCodeGen(t *testing.T) { - buf := &bytes.Buffer{} - if err := renderBoilerplateFile(buf, appProjectName); err != nil { - t.Error(err) - return - } - if boilerplateExp != buf.String() { - t.Errorf(errorMessage, boilerplateExp, buf.String()) - } - - buf = &bytes.Buffer{} - if err := renderUpdateGeneratedFile(buf, appRepoPath, appApiDirName, appVersion); err != nil { - t.Error(err) - return - } - if updateGeneratedExp != buf.String() { - t.Errorf(errorMessage, updateGeneratedExp, buf.String()) - } -} diff --git a/pkg/generator/gen_deploy.go b/pkg/generator/gen_deploy.go deleted file mode 100644 index 9bf7e1c734..0000000000 --- a/pkg/generator/gen_deploy.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "fmt" - "io" - "strings" - "text/template" -) - -const ( - crdTmplName = "deploy/crd.yaml" - operatorTmplName = "deploy/operator.yaml" - rbacTmplName = "deploy/rbac.yaml" - crTmplName = "deploy/cr.yaml" -) - -// CRDYaml contains data needed to generate deploy/crd.yaml -type CRDYaml struct { - Kind string - KindSingular string - KindPlural string - GroupName string - Version string -} - -// renderCRDYaml generates deploy/crd.yaml -func renderCRDYaml(w io.Writer, kind, apiVersion string) error { - t := template.New(crdTmplName) - t, err := t.Parse(crdYamlTmpl) - if err != nil { - return fmt.Errorf("failed to parse crd yaml template: %v", err) - } - - ks := strings.ToLower(kind) - o := CRDYaml{ - Kind: kind, - KindSingular: ks, - KindPlural: toPlural(ks), - GroupName: groupName(apiVersion), - Version: version(apiVersion), - } - return t.Execute(w, o) -} - -// OperatorYaml contains data needed to generate deploy/operator.yaml -type OperatorYaml struct { - ProjectName string - Image string -} - -// renderOperatorYaml generates deploy/operator.yaml. -func renderOperatorYaml(w io.Writer, projectName, image string) error { - t := template.New(operatorTmplName) - t, err := t.Parse(operatorYamlTmpl) - if err != nil { - return fmt.Errorf("failed to parse operator yaml template: %v", err) - } - - o := OperatorYaml{ - ProjectName: projectName, - Image: image, - } - return t.Execute(w, o) -} - -// RBACYaml contains all the customized data needed to generate deploy/rbac.yaml for a new operator -// when pairing with rbacYamlTmpl template. -type RBACYaml struct { - ProjectName string - GroupName string -} - -// renderRBACYaml generates deploy/rbac.yaml. -func renderRBACYaml(w io.Writer, projectName, groupName string) error { - t := template.New(rbacTmplName) - t, err := t.Parse(rbacYamlTmpl) - if err != nil { - return fmt.Errorf("failed to parse rbac yaml template: %v", err) - } - - r := RBACYaml{ - ProjectName: projectName, - GroupName: groupName, - } - return t.Execute(w, r) -} - -// CRYaml contains all the customized data needed to generate deploy/cr.yaml. -type CRYaml struct { - APIVersion string - Kind string - Name string -} - -func renderCustomResourceYaml(w io.Writer, apiVersion, kind string) error { - t := template.New(crTmplName) - t, err := t.Parse(crYamlTmpl) - if err != nil { - return fmt.Errorf("failed to parse cr yaml template: %v", err) - } - - r := CRYaml{ - APIVersion: apiVersion, - Kind: kind, - } - return t.Execute(w, r) -} diff --git a/pkg/generator/gen_deploy_test.go b/pkg/generator/gen_deploy_test.go deleted file mode 100644 index d9586f54d8..0000000000 --- a/pkg/generator/gen_deploy_test.go +++ /dev/null @@ -1,122 +0,0 @@ -package generator - -import ( - "bytes" - "testing" -) - -const crdYamlExp = `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 -` - -const operatorYamlExp = `apiVersion: apps/v1 -kind: Deployment -metadata: - name: app-operator -spec: - replicas: 1 - selector: - matchLabels: - name: app-operator - template: - metadata: - labels: - name: app-operator - spec: - containers: - - name: app-operator - image: quay.io/example-inc/app-operator:0.0.1 - command: - - app-operator - imagePullPolicy: Always - env: - - name: WATCH_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace -` - -const rbacYamlExp = `kind: Role -apiVersion: rbac.authorization.k8s.io/v1beta1 -metadata: - name: app-operator -rules: -- apiGroups: - - app.example.com - resources: - - "*" - verbs: - - "*" -- apiGroups: - - "" - resources: - - pods - - services - - endpoints - - persistentvolumeclaims - - events - - configmaps - - secrets - verbs: - - "*" -- apiGroups: - - apps - resources: - - deployments - - daemonsets - - replicasets - - statefulsets - verbs: - - "*" - ---- - -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1beta1 -metadata: - name: default-account-app-operator -subjects: -- kind: ServiceAccount - name: default -roleRef: - kind: Role - name: app-operator - apiGroup: rbac.authorization.k8s.io -` - -func TestGenDeploy(t *testing.T) { - buf := &bytes.Buffer{} - if err := renderCRDYaml(buf, appKind, appAPIVersion); err != nil { - t.Error(err) - } - if crdYamlExp != buf.String() { - t.Errorf(errorMessage, crdYamlExp, buf.String()) - } - - buf = &bytes.Buffer{} - if err := renderOperatorYaml(buf, appProjectName, appImage); err != nil { - t.Error(err) - } - if operatorYamlExp != buf.String() { - t.Errorf(errorMessage, operatorYamlExp, buf.String()) - } - - buf = &bytes.Buffer{} - if err := renderRBACYaml(buf, appProjectName, appGroupName); err != nil { - t.Error(err) - } - if rbacYamlExp != buf.String() { - t.Errorf(errorMessage, rbacYamlExp, buf.String()) - } -} diff --git a/pkg/generator/gen_handler.go b/pkg/generator/gen_handler.go deleted file mode 100644 index cac2739fdc..0000000000 --- a/pkg/generator/gen_handler.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "io" - "text/template" -) - -// Handler contains all the customized data needed to generate stub/handler.go for a new operator -// when pairing with handlerTmpl template. -type Handler struct { - // imports - OperatorSDKImport string - - RepoPath string - Kind string - APIDirName string - Version string -} - -// renderHandlerFile generates the stub/handler.go file. -func renderHandlerFile(w io.Writer, repoPath, kind, apiDirName, version string) error { - t := template.New("stub/handler.go") - t, err := t.Parse(handlerTmpl) - if err != nil { - return err - } - - h := Handler{ - OperatorSDKImport: sdkImport, - RepoPath: repoPath, - Kind: kind, - APIDirName: apiDirName, - Version: version, - } - return t.Execute(w, h) -} diff --git a/pkg/generator/gen_handler_test.go b/pkg/generator/gen_handler_test.go deleted file mode 100644 index 1b31ea3b5d..0000000000 --- a/pkg/generator/gen_handler_test.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "bytes" - "testing" -) - -const handlerExp = `package stub - -import ( - "context" - - "github.com/example-inc/app-operator/pkg/apis/app/v1alpha1" - - "github.com/operator-framework/operator-sdk/pkg/sdk" - "github.com/sirupsen/logrus" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -func NewHandler() sdk.Handler { - return &Handler{} -} - -type Handler struct { - // Fill me -} - -func (h *Handler) Handle(ctx context.Context, event sdk.Event) error { - switch o := event.Object.(type) { - case *v1alpha1.AppService: - err := sdk.Create(newbusyBoxPod(o)) - if err != nil && !errors.IsAlreadyExists(err) { - logrus.Errorf("Failed to create busybox pod : %v", err) - return err - } - } - return nil -} - -// newbusyBoxPod demonstrates how to create a busybox pod -func newbusyBoxPod(cr *v1alpha1.AppService) *corev1.Pod { - labels := map[string]string{ - "app": "busy-box", - } - return &corev1.Pod{ - TypeMeta: metav1.TypeMeta{ - Kind: "Pod", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "busy-box", - Namespace: cr.Namespace, - OwnerReferences: []metav1.OwnerReference{ - *metav1.NewControllerRef(cr, schema.GroupVersionKind{ - Group: v1alpha1.SchemeGroupVersion.Group, - Version: v1alpha1.SchemeGroupVersion.Version, - Kind: "AppService", - }), - }, - Labels: labels, - }, - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - { - Name: "busybox", - Image: "busybox", - Command: []string{"sleep", "3600"}, - }, - }, - }, - } -} -` - -func TestGenHandler(t *testing.T) { - buf := &bytes.Buffer{} - if err := renderHandlerFile(buf, appRepoPath, appKind, appApiDirName, appVersion); err != nil { - t.Error(err) - return - } - if handlerExp != buf.String() { - t.Errorf(errorMessage, handlerExp, buf.String()) - } -} diff --git a/pkg/generator/gen_main.go b/pkg/generator/gen_main.go deleted file mode 100644 index 5f56a1d653..0000000000 --- a/pkg/generator/gen_main.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "io" - "path/filepath" - "text/template" -) - -const ( - // sdkImport is the operator-sdk import path. - sdkImport = "github.com/operator-framework/operator-sdk/pkg/sdk" - k8sutilImport = "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" - versionImport = "github.com/operator-framework/operator-sdk/version" -) - -// Main contains all the customized data needed to generate cmd//main.go for a new operator -// when pairing with mainTmpl template. -type Main struct { - // imports - OperatorSDKImport string - StubImport string - K8sutilImport string - SDKVersionImport string - - APIVersion string - Kind string -} - -// renderMainFile generates the cmd//main.go file. -func renderMainFile(w io.Writer, repo, apiVersion, kind string) error { - t := template.New("cmd//main.go") - t, err := t.Parse(mainTmpl) - if err != nil { - return err - } - - m := Main{ - OperatorSDKImport: sdkImport, - StubImport: filepath.Join(repo, stubDir), - K8sutilImport: k8sutilImport, - SDKVersionImport: versionImport, - APIVersion: apiVersion, - Kind: kind, - } - return t.Execute(w, m) -} diff --git a/pkg/generator/gen_main_test.go b/pkg/generator/gen_main_test.go deleted file mode 100644 index 41b1ca995f..0000000000 --- a/pkg/generator/gen_main_test.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "bytes" - "testing" -) - -const mainExp = `package main - -import ( - "context" - "runtime" - - stub "github.com/example-inc/app-operator/pkg/stub" - sdk "github.com/operator-framework/operator-sdk/pkg/sdk" - k8sutil "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" - sdkVersion "github.com/operator-framework/operator-sdk/version" - - "github.com/sirupsen/logrus" -) - -func printVersion() { - logrus.Infof("Go Version: %s", runtime.Version()) - logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) - logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) -} - -func main() { - printVersion() - - resource := "app.example.com/v1alpha1" - kind := "AppService" - namespace, err := k8sutil.GetWatchNamespace() - if err != nil { - logrus.Fatalf("Failed to get watch namespace: %v", err) - } - resyncPeriod := 5 - logrus.Infof("Watching %s, %s, %s, %d", resource, kind, namespace, resyncPeriod) - sdk.Watch(resource, kind, namespace, resyncPeriod) - sdk.Handle(stub.NewHandler()) - sdk.Run(context.TODO()) -} -` - -func TestGenMain(t *testing.T) { - buf := &bytes.Buffer{} - if err := renderMainFile(buf, appRepoPath, appAPIVersion, appKind); err != nil { - t.Error(err) - return - } - - if mainExp != buf.String() { - t.Errorf(errorMessage, mainExp, buf.String()) - } -} diff --git a/pkg/generator/gen_olm_catalog.go b/pkg/generator/gen_olm_catalog.go deleted file mode 100644 index a21a08e28a..0000000000 --- a/pkg/generator/gen_olm_catalog.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "fmt" - "io" - "strings" - "text/template" -) - -const ( - // Sample catalog resource values - // TODO: Make this configurable - packageChannel = "alpha" - catalogCRDTmplName = "deploy/olm-catalog/crd.yaml" -) - -// CatalogPackageConfig contains the data needed to generate deploy/olm-catalog/package.yaml -type CatalogPackageConfig struct { - PackageName string - ChannelName string - CurrentCSV string -} - -// renderCatalogPackage generates deploy/olm-catalog/package.yaml -func renderCatalogPackage(w io.Writer, config *Config, catalogVersion string) error { - t := template.New(catalogPackageYaml) - t, err := t.Parse(catalogPackageTmpl) - if err != nil { - return fmt.Errorf("failed to parse catalog package template: %v", err) - } - - name := strings.ToLower(config.Kind) - cpConfig := CatalogPackageConfig{ - PackageName: name, - ChannelName: packageChannel, - CurrentCSV: getCSVName(name, catalogVersion), - } - return t.Execute(w, cpConfig) -} - -// CRDConfig contains the data needed to generate deploy/olm-catalog/crd.yaml -type CRDConfig struct { - Kind string - KindSingular string - KindPlural string - GroupName string - Version string -} - -// renderCatalogCRD generates deploy/olm-catalog/crd.yaml -func renderCatalogCRD(w io.Writer, config *Config) error { - t := template.New(catalogCRDTmplName) - t, err := t.Parse(crdTmpl) - if err != nil { - return fmt.Errorf("failed to parse catalog CRD template: %v", err) - } - - kindSingular := strings.ToLower(config.Kind) - crdConfig := CRDConfig{ - Kind: config.Kind, - KindSingular: kindSingular, - KindPlural: toPlural(kindSingular), - GroupName: groupName(config.APIVersion), - Version: version(config.APIVersion), - } - return t.Execute(w, crdConfig) -} - -// CSVConfig contains the data needed to generate deploy/olm-catalog/csv.yaml -type CSVConfig struct { - Kind string - KindSingular string - KindPlural string - GroupName string - CRDVersion string - ProjectName string - CSVName string - Image string - CatalogVersion string -} - -// renderCatalogCSV generates deploy/olm-catalog/csv.yaml -func renderCatalogCSV(w io.Writer, config *Config, image, catalogVersion string) error { - t := template.New(catalogCSVYaml) - t, err := t.Parse(catalogCSVTmpl) - if err != nil { - return fmt.Errorf("failed to parse catalog CSV template: %v", err) - } - - kindSingular := strings.ToLower(config.Kind) - csvConfig := CSVConfig{ - Kind: config.Kind, - KindSingular: kindSingular, - KindPlural: kindSingular + "s", - GroupName: groupName(config.APIVersion), - CRDVersion: version(config.APIVersion), - CSVName: getCSVName(kindSingular, catalogVersion), - Image: image, - CatalogVersion: catalogVersion, - ProjectName: config.ProjectName, - } - return t.Execute(w, csvConfig) -} - -func getCSVName(name, version string) string { - return name + ".v" + version -} diff --git a/pkg/generator/gen_version.go b/pkg/generator/gen_version.go deleted file mode 100644 index 4d3cede937..0000000000 --- a/pkg/generator/gen_version.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "io" - "text/template" -) - -// Version contains the verison number string and gitsha string -type Version struct { - // imports - VersionNumber string -} - -// renderVersionFile generates the version/version.go file. -func renderVersionFile(w io.Writer, versionNumber string) error { - t := template.New("version/version.go") - t, err := t.Parse(versionTmpl) - if err != nil { - return err - } - - v := Version{ - VersionNumber: versionNumber, - } - return t.Execute(w, v) -} diff --git a/pkg/generator/gen_version_test.go b/pkg/generator/gen_version_test.go deleted file mode 100644 index 5c2ef198f0..0000000000 --- a/pkg/generator/gen_version_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "bytes" - "testing" -) - -const versionExp = `package version - -var ( - Version = "0.9.2+git" -) -` - -func TestGenVersion(t *testing.T) { - buf := &bytes.Buffer{} - if err := renderVersionFile(buf, "0.9.2+git"); err != nil { - t.Error(err) - return - } - if versionExp != buf.String() { - t.Errorf("Wants: %v", versionExp) - t.Errorf(" Got: %v", buf.String()) - } -} diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 519c7db804..382d4c6ec9 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -64,6 +64,18 @@ const ( crdYaml = "crd.yaml" gitignore = ".gitignore" versionfile = "version.go" + + // sdkImport is the operator-sdk import path. + sdkImport = "github.com/operator-framework/operator-sdk/pkg/sdk" + k8sutilImport = "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" + versionImport = "github.com/operator-framework/operator-sdk/version" + packageChannel = "alpha" + catalogCRDTmplName = "deploy/olm-catalog/crd.yaml" + crdTmplName = "deploy/crd.yaml" + operatorTmplName = "deploy/operator.yaml" + rbacTmplName = "deploy/rbac.yaml" + crTmplName = "deploy/cr.yaml" + // pluralSuffix = "s" ) type Generator struct { @@ -99,6 +111,10 @@ func NewGenerator(apiVersion, kind, projectName, repoPath string) *Generator { // │ | └── codegen // │ └── version func (g *Generator) Render() error { + if err := g.generateDirStructure(); err != nil { + return err + } + if err := g.renderProject(); err != nil { return err } @@ -125,9 +141,6 @@ func (g *Generator) Render() error { } func (g *Generator) renderProject() error { - if err := os.MkdirAll(g.projectName, defaultDirFileMode); err != nil { - return err - } return renderProjectGitignore(g.projectName) } @@ -159,25 +172,28 @@ func (g *Generator) renderGoDep() error { func (g *Generator) renderCmd() error { cpDir := filepath.Join(g.projectName, cmdDir, g.projectName) - if err := os.MkdirAll(cpDir, defaultDirFileMode); err != nil { - return err - } return renderCmdFiles(cpDir, g.repoPath, g.apiVersion, g.kind) } func renderCmdFiles(cmdProjectDir, repoPath, apiVersion, kind string) error { buf := &bytes.Buffer{} - if err := renderMainFile(buf, repoPath, apiVersion, kind); err != nil { + + if err := renderGenericFile(buf, "cmd//main.go", mainTmpl, tmplData{ + OperatorSDKImport: sdkImport, + StubImport: filepath.Join(repoPath, stubDir), + K8sutilImport: k8sutilImport, + SDKVersionImport: versionImport, + APIVersion: apiVersion, + Kind: kind, + }); err != nil { return err } + return writeFileAndPrint(filepath.Join(cmdProjectDir, main), buf.Bytes(), defaultFileMode) } func (g *Generator) renderConfig() error { cp := filepath.Join(g.projectName, configDir) - if err := os.MkdirAll(cp, defaultDirFileMode); err != nil { - return err - } return renderConfigFiles(cp, g.apiVersion, g.kind, g.projectName) } @@ -191,23 +207,28 @@ func renderConfigFiles(configDir, apiVersion, kind, projectName string) error { func (g *Generator) renderDeploy() error { dp := filepath.Join(g.projectName, deployDir) - if err := os.MkdirAll(dp, defaultDirFileMode); err != nil { - return err - } return renderDeployFiles(dp, g.projectName, g.apiVersion, g.kind) } func renderRBAC(deployDir, projectName, groupName string) error { buf := &bytes.Buffer{} - if err := renderRBACYaml(buf, projectName, groupName); err != nil { + + if err := renderGenericFile(buf, rbacTmplName, rbacYamlTmpl, tmplData{ + ProjectName: projectName, + GroupName: groupName, + }); err != nil { return err } + return writeFileAndPrint(filepath.Join(deployDir, rbacYaml), buf.Bytes(), defaultFileMode) } func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { buf := &bytes.Buffer{} - if err := renderRBACYaml(buf, projectName, groupName(apiVersion)); err != nil { + if err := renderGenericFile(buf, rbacTmplName, rbacYamlTmpl, tmplData{ + ProjectName: projectName, + GroupName: groupName(apiVersion), + }); err != nil { return err } if err := writeFileAndPrint(filepath.Join(deployDir, rbacYaml), buf.Bytes(), defaultFileMode); err != nil { @@ -215,7 +236,13 @@ func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { } buf = &bytes.Buffer{} - if err := renderCRDYaml(buf, kind, apiVersion); err != nil { + if err := renderGenericFile(buf, crdTmplName, crdYamlTmpl, tmplData{ + Kind: kind, + KindSingular: strings.ToLower(kind), + KindPlural: toPlural(strings.ToLower(kind)), + GroupName: groupName(apiVersion), + Version: version(apiVersion), + }); err != nil { return err } if err := writeFileAndPrint(filepath.Join(deployDir, crdYaml), buf.Bytes(), defaultFileMode); err != nil { @@ -223,7 +250,10 @@ func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { } buf = &bytes.Buffer{} - if err := renderCustomResourceYaml(buf, apiVersion, kind); err != nil { + if err := renderGenericFile(buf, crTmplName, crYamlTmpl, tmplData{ + APIVersion: apiVersion, + Kind: kind, + }); err != nil { return err } return writeFileAndPrint(filepath.Join(deployDir, crYaml), buf.Bytes(), defaultFileMode) @@ -232,7 +262,10 @@ func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { // RenderOperatorYaml generates "deploy/operator.yaml" func RenderOperatorYaml(c *Config, image string) error { buf := &bytes.Buffer{} - if err := renderOperatorYaml(buf, c.ProjectName, image); err != nil { + if err := renderGenericFile(buf, operatorTmplName, operatorYamlTmpl, tmplData{ + ProjectName: c.ProjectName, + Image: image, + }); err != nil { return err } return ioutil.WriteFile(operatorYaml, buf.Bytes(), defaultFileMode) @@ -247,13 +280,14 @@ func RenderOlmCatalog(c *Config, image, version string) error { return err } olmDir := filepath.Join(repoPath, olmCatalogDir) - if err := os.MkdirAll(olmDir, defaultDirFileMode); err != nil { - return err - } // deploy/olm-catalog/package.yaml buf := &bytes.Buffer{} - if err := renderCatalogPackage(buf, c, version); err != nil { + if err := renderGenericFile(buf, catalogPackageYaml, catalogPackageTmpl, tmplData{ + PackageName: strings.ToLower(c.Kind), + ChannelName: packageChannel, + CurrentCSV: getCSVName(strings.ToLower(c.Kind), version), + }); err != nil { return err } path := filepath.Join(olmDir, catalogPackageYaml) @@ -263,7 +297,13 @@ func RenderOlmCatalog(c *Config, image, version string) error { // deploy/olm-catalog/crd.yaml buf = &bytes.Buffer{} - if err := renderCatalogCRD(buf, c); err != nil { + if err := renderGenericFile(buf, catalogCRDTmplName, crdTmpl, tmplData{ + Kind: c.Kind, + KindSingular: strings.ToLower(c.Kind), + KindPlural: toPlural(strings.ToLower(c.Kind)), + GroupName: groupName(c.APIVersion), + Version: version, + }); err != nil { return err } path = filepath.Join(olmDir, crdYaml) @@ -273,36 +313,40 @@ func RenderOlmCatalog(c *Config, image, version string) error { // deploy/olm-catalog/csv.yaml buf = &bytes.Buffer{} - if err := renderCatalogCSV(buf, c, image, version); err != nil { + if err := renderGenericFile(buf, catalogCSVYaml, catalogCSVTmpl, tmplData{ + Kind: c.Kind, + KindSingular: strings.ToLower(c.Kind), + KindPlural: toPlural(strings.ToLower(c.Kind)), + GroupName: groupName(c.APIVersion), + CRDVersion: version, + CSVName: getCSVName(strings.ToLower(c.Kind), version), + Image: image, + CatalogVersion: version, + ProjectName: c.ProjectName, + }); err != nil { return err } path = filepath.Join(olmDir, catalogCSVYaml) return ioutil.WriteFile(path, buf.Bytes(), defaultFileMode) } +func getCSVName(name, version string) string { + return name + ".v" + version +} + func (g *Generator) renderTmp() error { bDir := filepath.Join(g.projectName, buildDir) - if err := os.MkdirAll(bDir, defaultDirFileMode); err != nil { - return err - } if err := renderBuildFiles(bDir, g.repoPath, g.projectName); err != nil { return err } cDir := filepath.Join(g.projectName, codegenDir) - if err := os.MkdirAll(cDir, defaultDirFileMode); err != nil { - return err - } return renderCodegenFiles(cDir, g.repoPath, apiDirName(g.apiVersion), version(g.apiVersion), g.projectName) } func (g *Generator) renderVersion() error { buf := &bytes.Buffer{} - if err := os.MkdirAll(filepath.Join(g.projectName, versionDir), defaultDirFileMode); err != nil { - return err - } - if err := renderGenericFile(buf, "version/version.go", versionTmpl, tmplData{VersionNumber: "0.0.1"}); err != nil { return err } @@ -312,7 +356,11 @@ func (g *Generator) renderVersion() error { func renderBuildFiles(buildDir, repoPath, projectName string) error { buf := &bytes.Buffer{} - if err := renderBuildFile(buf, repoPath, projectName); err != nil { + + if err := renderGenericFile(buf, "tmp/build/build.sh", buildTmpl, tmplData{ + ProjectName: projectName, + RepoPath: repoPath, + }); err != nil { return err } if err := writeFileAndPrint(filepath.Join(buildDir, build), buf.Bytes(), defaultExecFileMode); err != nil { @@ -328,15 +376,24 @@ func renderBuildFiles(buildDir, repoPath, projectName string) error { } buf = &bytes.Buffer{} - if err := renderDockerFile(buf, projectName); err != nil { + if err := renderGenericFile(buf, "tmp/build/Dockerfile", dockerFileTmpl, tmplData{ + ProjectName: projectName, + }); err != nil { return err } return writeFileAndPrint(filepath.Join(buildDir, dockerfile), buf.Bytes(), defaultFileMode) } +func renderDockerBuildFile(w io.Writer) error { + _, err := w.Write([]byte(dockerBuildTmpl)) + return err +} + func renderCodegenFiles(codegenDir, repoPath, apiDirName, version, projectName string) error { buf := &bytes.Buffer{} - if err := renderBoilerplateFile(buf, projectName); err != nil { + if err := renderGenericFile(buf, "codegen/boilerplate.go.txt", boilerplateTmpl, tmplData{ + ProjectName: projectName, + }); err != nil { return err } if err := writeFileAndPrint(filepath.Join(codegenDir, boilerplate), buf.Bytes(), defaultFileMode); err != nil { @@ -344,7 +401,11 @@ func renderCodegenFiles(codegenDir, repoPath, apiDirName, version, projectName s } buf = &bytes.Buffer{} - if err := renderUpdateGeneratedFile(buf, repoPath, apiDirName, version); err != nil { + if err := renderGenericFile(buf, "codegen/update-generated.sh", updateGeneratedTmpl, tmplData{ + RepoPath: repoPath, + APIDirName: apiDirName, + Version: version, + }); err != nil { return err } return writeFileAndPrint(filepath.Join(codegenDir, updateGenerated), buf.Bytes(), defaultExecFileMode) @@ -354,23 +415,20 @@ func (g *Generator) renderPkg() error { v := version(g.apiVersion) adn := apiDirName(g.apiVersion) apiDir := filepath.Join(g.projectName, apisDir, adn, v) - if err := os.MkdirAll(apiDir, defaultDirFileMode); err != nil { - return err - } if err := renderAPIFiles(apiDir, groupName(g.apiVersion), v, g.kind); err != nil { return err } sDir := filepath.Join(g.projectName, stubDir) - if err := os.MkdirAll(sDir, defaultDirFileMode); err != nil { - return err - } return renderStubFiles(sDir, g.repoPath, g.kind, adn, v) } func renderAPIFiles(apiDir, groupName, version, kind string) error { buf := &bytes.Buffer{} - if err := renderAPIDocFile(buf, groupName, version); err != nil { + if err := renderGenericFile(buf, "apis///doc.go", apiDocTmpl, tmplData{ + GroupName: groupName, + Version: version, + }); err != nil { return err } if err := writeFileAndPrint(filepath.Join(apiDir, doc), buf.Bytes(), defaultFileMode); err != nil { @@ -378,7 +436,12 @@ func renderAPIFiles(apiDir, groupName, version, kind string) error { } buf = &bytes.Buffer{} - if err := renderAPIRegisterFile(buf, kind, groupName, version); err != nil { + if err := renderGenericFile(buf, "apis///register.go", apiRegisterTmpl, tmplData{ + Kind: kind, + KindPlural: toPlural(strings.ToLower(kind)), + GroupName: groupName, + Version: version, + }); err != nil { return err } if err := writeFileAndPrint(filepath.Join(apiDir, register), buf.Bytes(), defaultFileMode); err != nil { @@ -386,7 +449,10 @@ func renderAPIFiles(apiDir, groupName, version, kind string) error { } buf = &bytes.Buffer{} - if err := renderAPITypesFile(buf, kind, version); err != nil { + if err := renderGenericFile(buf, "apis///types.go", apiTypesTmpl, tmplData{ + Kind: kind, + Version: version, + }); err != nil { return err } return writeFileAndPrint(filepath.Join(apiDir, types), buf.Bytes(), defaultFileMode) @@ -394,7 +460,13 @@ func renderAPIFiles(apiDir, groupName, version, kind string) error { func renderStubFiles(stubDir, repoPath, kind, apiDirName, version string) error { buf := &bytes.Buffer{} - if err := renderHandlerFile(buf, repoPath, kind, apiDirName, version); err != nil { + if err := renderGenericFile(buf, "stub/handler.go", handlerTmpl, tmplData{ + OperatorSDKImport: sdkImport, + RepoPath: repoPath, + Kind: kind, + APIDirName: apiDirName, + Version: version, + }); err != nil { return err } return writeFileAndPrint(filepath.Join(stubDir, handler), buf.Bytes(), defaultFileMode) @@ -423,6 +495,14 @@ type tmplData struct { Image string Name string + + PackageName string + ChannelName string + CurrentCSV string + + CRDVersion string + CSVName string + CatalogVersion string } func (g *Generator) generateDirStructure() error { From cea3b572d0c5e9fa531c2074cf2ebdbbe3ab4de0 Mon Sep 17 00:00:00 2001 From: Etienne Coutaud Date: Fri, 1 Jun 2018 11:03:56 +0200 Subject: [PATCH 05/21] pkg/util: Init service object + GetOperatorName env var and test --- pkg/generator/gen_deploy.go | 16 +++++-- pkg/generator/gen_deploy_test.go | 48 ++------------------ pkg/generator/gen_main.go | 8 +++- pkg/generator/gen_main_test.go | 71 +++++++++++++++++------------- pkg/generator/generator.go | 2 - pkg/generator/templates.go | 75 ++++++++++++++++++++------------ pkg/util/k8sutil/constants.go | 7 +++ pkg/util/k8sutil/k8sutil.go | 58 ++++++++++++++++++++++++ pkg/util/k8sutil/k8sutil_test.go | 61 ++++++++++++++++++++++++++ 9 files changed, 235 insertions(+), 111 deletions(-) create mode 100644 pkg/util/k8sutil/k8sutil_test.go diff --git a/pkg/generator/gen_deploy.go b/pkg/generator/gen_deploy.go index 9bf7e1c734..131147c1eb 100644 --- a/pkg/generator/gen_deploy.go +++ b/pkg/generator/gen_deploy.go @@ -19,6 +19,8 @@ import ( "io" "strings" "text/template" + + "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" ) const ( @@ -58,8 +60,11 @@ func renderCRDYaml(w io.Writer, kind, apiVersion string) error { // OperatorYaml contains data needed to generate deploy/operator.yaml type OperatorYaml struct { - ProjectName string - Image string + ProjectName string + Image string + NameEnv string + NamespaceEnv string + MetricsPort int } // renderOperatorYaml generates deploy/operator.yaml. @@ -71,8 +76,11 @@ func renderOperatorYaml(w io.Writer, projectName, image string) error { } o := OperatorYaml{ - ProjectName: projectName, - Image: image, + ProjectName: projectName, + Image: image, + NameEnv: k8sutil.OperatorNameEnvVar, + NamespaceEnv: k8sutil.WatchNamespaceEnvVar, + MetricsPort: k8sutil.PrometheusMetricsPort, } return t.Execute(w, o) } diff --git a/pkg/generator/gen_deploy_test.go b/pkg/generator/gen_deploy_test.go index 3e92e231b4..b2f5df2186 100644 --- a/pkg/generator/gen_deploy_test.go +++ b/pkg/generator/gen_deploy_test.go @@ -40,7 +40,7 @@ spec: - name: app-operator image: quay.io/example-inc/app-operator:0.0.1 ports: - - containerPort: 9090 + - containerPort: 60000 name: metrics command: - app-operator @@ -50,6 +50,8 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace + - name: OPERATOR_NAME + value: "app-operator" ` const rbacYamlExp = `kind: Role @@ -100,34 +102,6 @@ roleRef: apiGroup: rbac.authorization.k8s.io ` -const serviceYamlExp = `apiVersion: v1 -kind: Service -metadata: - name: app-operator - labels: - name: app-operator -spec: - selector: - name: app-operator - ports: - - protocol: TCP - targetPort: metrics - port: 9090 - name: metrics` - -const serviceMonitorYamlExp = `apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: app-operator - labels: - name: app-operator -spec: - selector: - matchLabels: - name: app-operator - endpoints: - - port: metrics` - func TestGenDeploy(t *testing.T) { buf := &bytes.Buffer{} if err := renderCRDYaml(buf, appKind, appAPIVersion); err != nil { @@ -152,20 +126,4 @@ func TestGenDeploy(t *testing.T) { if rbacYamlExp != buf.String() { t.Errorf(errorMessage, rbacYamlExp, buf.String()) } - - buf = &bytes.Buffer{} - if err := renderServiceYaml(buf, appProjectName); err != nil { - t.Error(err) - } - if serviceYamlExp != buf.String() { - t.Errorf("want %v, got %v", serviceYamlExp, buf.String()) - } - - buf = &bytes.Buffer{} - if err := renderServiceMonitorYaml(buf, appProjectName); err != nil { - t.Error(err) - } - if serviceMonitorYamlExp != buf.String() { - t.Errorf("want %v, got %v", serviceMonitorYamlExp, buf.String()) - } } diff --git a/pkg/generator/gen_main.go b/pkg/generator/gen_main.go index 5f56a1d653..455e85d3d1 100644 --- a/pkg/generator/gen_main.go +++ b/pkg/generator/gen_main.go @@ -18,6 +18,8 @@ import ( "io" "path/filepath" "text/template" + + "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" ) const ( @@ -36,8 +38,9 @@ type Main struct { K8sutilImport string SDKVersionImport string - APIVersion string - Kind string + APIVersion string + Kind string + MetricsPort string } // renderMainFile generates the cmd//main.go file. @@ -55,6 +58,7 @@ func renderMainFile(w io.Writer, repo, apiVersion, kind string) error { SDKVersionImport: versionImport, APIVersion: apiVersion, Kind: kind, + MetricsPort: k8sutil.GetPrometheusMetricsPort(), } return t.Execute(w, m) } diff --git a/pkg/generator/gen_main_test.go b/pkg/generator/gen_main_test.go index 55650bd9ed..501714e4ec 100644 --- a/pkg/generator/gen_main_test.go +++ b/pkg/generator/gen_main_test.go @@ -22,46 +22,57 @@ import ( const mainExp = `package main import ( - "context" - "runtime" - "net/http" + "context" + "runtime" + "net/http" - stub "github.com/example-inc/app-operator/pkg/stub" - sdk "github.com/operator-framework/operator-sdk/pkg/sdk" - k8sutil "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" - sdkVersion "github.com/operator-framework/operator-sdk/version" + stub "github.com/example-inc/app-operator/pkg/stub" + sdk "github.com/operator-framework/operator-sdk/pkg/sdk" + k8sutil "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" + sdkVersion "github.com/operator-framework/operator-sdk/version" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/sirupsen/logrus" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/sirupsen/logrus" ) -// Prometheus metrics port -const promPort = ":9090" - func printVersion() { - logrus.Infof("Go Version: %s", runtime.Version()) - logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) - logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) - logrus.Infof("operator prometheus port :%s", promPort) + logrus.Infof("Go Version: %s", runtime.Version()) + logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) + logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) + logrus.Infof("operator prometheus port %s", ":60000") +} + +func initOperatorService() { + service, err := k8sutil.InitOperatorService() + if err != nil { + logrus.Fatalf("Failed to init operator service: %v", err) + } + err = sdk.Create(service) + if err != nil { + logrus.Infof("Failed to create operator service: %v", err) + return + } + logrus.Infof("Service %s have been created", service.Name) } func main() { - printVersion() + printVersion() + initOperatorService() - http.Handle("/metrics", promhttp.Handler()) - logrus.Fatalf("%s", http.ListenAndServe(promPort, nil)) + http.Handle("/metrics", promhttp.Handler()) + go http.ListenAndServe(":60000", nil) - resource := "app.example.com/v1alpha1" - kind := "AppService" - namespace, err := k8sutil.GetWatchNamespace() - if err != nil { - logrus.Fatalf("Failed to get watch namespace: %v", err) - } - resyncPeriod := 5 - logrus.Infof("Watching %s, %s, %s, %d", resource, kind, namespace, resyncPeriod) - sdk.Watch(resource, kind, namespace, resyncPeriod) - sdk.Handle(stub.NewHandler()) - sdk.Run(context.TODO()) + resource := "app.example.com/v1alpha1" + kind := "AppService" + namespace, err := k8sutil.GetWatchNamespace() + if err != nil { + logrus.Fatalf("Failed to get watch namespace: %v", err) + } + resyncPeriod := 5 + logrus.Infof("Watching %s, %s, %s, %d", resource, kind, namespace, resyncPeriod) + sdk.Watch(resource, kind, namespace, resyncPeriod) + sdk.Handle(stub.NewHandler()) + sdk.Run(context.TODO()) } ` diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 7b3ff097e9..df41ae34c2 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -55,8 +55,6 @@ const ( gopkglock = "Gopkg.lock" config = "config.yaml" operatorYaml = deployDir + "/operator.yaml" - serviceYaml = "service.yaml" - serviceMonitorYaml = "serviceMonitor.yaml" rbacYaml = "rbac.yaml" crYaml = "cr.yaml" catalogPackageYaml = "package.yaml" diff --git a/pkg/generator/templates.go b/pkg/generator/templates.go index 8a4dbfd256..1ac4fe643e 100644 --- a/pkg/generator/templates.go +++ b/pkg/generator/templates.go @@ -130,45 +130,57 @@ spec: const mainTmpl = `package main import ( - "context" - "runtime" + "context" + "runtime" + "net/http" - stub "{{.StubImport}}" - sdk "{{.OperatorSDKImport}}" - k8sutil "{{.K8sutilImport}}" + stub "{{.StubImport}}" + sdk "{{.OperatorSDKImport}}" + k8sutil "{{.K8sutilImport}}" sdkVersion "{{.SDKVersionImport}}" - + "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus" ) -// Prometheus metrics port -const promPort = ":9090" - func printVersion() { - logrus.Infof("Go Version: %s", runtime.Version()) - logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) + logrus.Infof("Go Version: %s", runtime.Version()) + logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) - logrus.Infof("operator prometheus port :%s", promPort) + logrus.Infof("operator prometheus port %s", "{{.MetricsPort}}") +} + +func initOperatorService() { + service, err := k8sutil.InitOperatorService() + if err != nil { + logrus.Fatalf("Failed to init operator service: %v", err) + } + err = sdk.Create(service) + if err != nil { + logrus.Infof("Failed to create operator service: %v", err) + return + } + logrus.Infof("Service %s have been created", service.Name) } func main() { - printVersion() + printVersion() + initOperatorService() http.Handle("/metrics", promhttp.Handler()) - logrus.Fatalf("%s", http.ListenAndServe(promPort, nil)) - - resource := "{{.APIVersion}}" - kind := "{{.Kind}}" - namespace, err := k8sutil.GetWatchNamespace() - if err != nil { - logrus.Fatalf("Failed to get watch namespace: %v", err) - } - resyncPeriod := 5 - logrus.Infof("Watching %s, %s, %s, %d", resource, kind, namespace, resyncPeriod) - sdk.Watch(resource, kind, namespace, resyncPeriod) - sdk.Handle(stub.NewHandler()) - sdk.Run(context.TODO()) + go http.ListenAndServe("{{.MetricsPort}}", nil) + + resource := "{{.APIVersion}}" + kind := "{{.Kind}}" + namespace, err := k8sutil.GetWatchNamespace() + if err != nil { + logrus.Fatalf("Failed to get watch namespace: %v", err) + } + resyncPeriod := 5 + logrus.Infof("Watching %s, %s, %s, %d", resource, kind, namespace, resyncPeriod) + sdk.Watch(resource, kind, namespace, resyncPeriod) + sdk.Handle(stub.NewHandler()) + sdk.Run(context.TODO()) } ` @@ -524,6 +536,8 @@ const operatorYamlTmpl = `apiVersion: apps/v1 kind: Deployment metadata: name: {{.ProjectName}} + labels: + name: {{.ProjectName}} spec: replicas: 1 selector: @@ -537,14 +551,19 @@ spec: containers: - name: {{.ProjectName}} image: {{.Image}} + ports: + - containerPort: {{.MetricsPort}} + name: metrics command: - {{.ProjectName}} imagePullPolicy: Always env: - - name: WATCH_NAMESPACE + - name: {{.NamespaceEnv}} valueFrom: fieldRef: fieldPath: metadata.namespace + - name: {{.NameEnv}} + value: "{{.ProjectName}}" ` const rbacYamlTmpl = `kind: Role diff --git a/pkg/util/k8sutil/constants.go b/pkg/util/k8sutil/constants.go index fd67036cca..bc56cc77bf 100644 --- a/pkg/util/k8sutil/constants.go +++ b/pkg/util/k8sutil/constants.go @@ -8,4 +8,11 @@ const ( // WatchNamespaceEnvVar is the constant for env variable WATCH_NAMESPACE // which is the namespace that the pod is currently running in. WatchNamespaceEnvVar = "WATCH_NAMESPACE" + + // OperatorName is the constant for env variable OPERATOR_NAME + // wich is the name of the current operator + OperatorNameEnvVar = "OPERATOR_NAME" + + // PrometheusMetricsPort defines the port which expose prometheus metrics + PrometheusMetricsPort = 60000 ) diff --git a/pkg/util/k8sutil/k8sutil.go b/pkg/util/k8sutil/k8sutil.go index f317f67bb5..02a584a56d 100644 --- a/pkg/util/k8sutil/k8sutil.go +++ b/pkg/util/k8sutil/k8sutil.go @@ -18,13 +18,16 @@ import ( "encoding/json" "fmt" "os" + "strconv" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" + intstr "k8s.io/apimachinery/pkg/util/intstr" cgoscheme "k8s.io/client-go/kubernetes/scheme" ) @@ -147,3 +150,58 @@ func GetWatchNamespace() (string, error) { } return ns, nil } + +// GetOperatorName return the operator name +func GetOperatorName() (string, error) { + operatorName, found := os.LookupEnv(OperatorNameEnvVar) + if !found { + return "", fmt.Errorf("%s must be set", OperatorNameEnvVar) + } + if len(operatorName) == 0 { + return "", fmt.Errorf("%s must not be empty", OperatorNameEnvVar) + } + return operatorName, nil +} + +// InitOperatorService return the static service which expose operator metrics +func InitOperatorService() (*v1.Service, error) { + operatorName, err := GetOperatorName() + if err != nil { + return nil, err + } + namespace, err := GetWatchNamespace() + if err != nil { + return nil, err + } + service := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: operatorName, + Namespace: namespace, + Labels: map[string]string{"name": operatorName}, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Port: PrometheusMetricsPort, + Protocol: v1.ProtocolTCP, + TargetPort: intstr.IntOrString{ + Type: intstr.String, + StrVal: "metrics", + }, + Name: "metrics", + }, + }, + Selector: map[string]string{"name": operatorName}, + }, + } + return service, nil +} + +// GetPrometheusMetricsPort convert constant to string +func GetPrometheusMetricsPort() string { + return ":" + strconv.Itoa(PrometheusMetricsPort) +} diff --git a/pkg/util/k8sutil/k8sutil_test.go b/pkg/util/k8sutil/k8sutil_test.go new file mode 100644 index 0000000000..0e5c257874 --- /dev/null +++ b/pkg/util/k8sutil/k8sutil_test.go @@ -0,0 +1,61 @@ +package k8sutil + +import ( + "fmt" + "os" + "reflect" + "testing" +) + +func TestGetOperatorName(t *testing.T) { + type Output struct { + operatorName string + err error + } + + type Scenario struct { + name string + envVarKey string + envVarValue string + expectedOutput Output + } + + tests := []Scenario{ + Scenario{ + name: "Simple case", + envVarKey: OperatorNameEnvVar, + envVarValue: "myoperator", + expectedOutput: Output{ + operatorName: "myoperator", + err: nil, + }, + }, + Scenario{ + name: "Unset env var", + envVarKey: "", + envVarValue: "", + expectedOutput: Output{ + operatorName: "", + err: fmt.Errorf("%s must be set", OperatorNameEnvVar), + }, + }, + Scenario{ + name: "Empty env var", + envVarKey: OperatorNameEnvVar, + envVarValue: "", + expectedOutput: Output{ + operatorName: "", + err: fmt.Errorf("%s must not be empty", OperatorNameEnvVar), + }, + }, + } + + for _, test := range tests { + _ = os.Setenv(test.envVarKey, test.envVarValue) + operatorName, err := GetOperatorName() + if !(operatorName == test.expectedOutput.operatorName && reflect.DeepEqual(err, test.expectedOutput.err)) { + t.Errorf("test %s failed, expected ouput: %s,%v; got: %s,%v", test.name, test.expectedOutput.operatorName, test.expectedOutput.err, operatorName, err) + } + _ = os.Unsetenv(test.envVarKey) + } +} From e3857198f7522254640b007afb32577bad836b41 Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Mon, 11 Jun 2018 10:10:16 -0700 Subject: [PATCH 06/21] Fix olm dir generation --- pkg/generator/generator.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 382d4c6ec9..3946a3a15b 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -525,12 +525,8 @@ func (g *Generator) generateDirStructure() error { return err } - repoPath, err := os.Getwd() - if err != nil { - return err - } - olmDir := filepath.Join(repoPath, olmCatalogDir) - if err := os.MkdirAll(olmDir, defaultDirFileMode); err != nil { + op := filepath.Join(g.projectName, olmCatalogDir) + if err := os.MkdirAll(op, defaultDirFileMode); err != nil { return err } From a7e2d93eff6e4e3fae08a995ca83388439c09338 Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Mon, 11 Jun 2018 11:16:40 -0700 Subject: [PATCH 07/21] Added basic test for generic file render func --- pkg/generator/generator_test.go | 39 +++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 pkg/generator/generator_test.go diff --git a/pkg/generator/generator_test.go b/pkg/generator/generator_test.go new file mode 100644 index 0000000000..6ceab64de1 --- /dev/null +++ b/pkg/generator/generator_test.go @@ -0,0 +1,39 @@ +// Copyright 2018 The Operator-SDK 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 generator + +import ( + "bytes" + "testing" +) + +const versionExp = `package version + +var ( + Version = "0.9.2+git" +) +` + +func TestGenVersion(t *testing.T) { + buf := &bytes.Buffer{} + if err := renderGenericFile(buf, "version/version.go", versionTmpl, tmplData{VersionNumber: "0.9.2+git"}); err != nil { + t.Error(err) + return + } + if versionExp != buf.String() { + t.Errorf("Wants: %v", versionExp) + t.Errorf(" Got: %v", buf.String()) + } +} From a24cef13d7045b1e08d43de9f7638f490f7fb575 Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Mon, 11 Jun 2018 11:48:58 -0700 Subject: [PATCH 08/21] Rename file rendering function and add comments --- pkg/generator/generator.go | 40 +++++++++++++++++---------------- pkg/generator/generator_test.go | 2 +- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 3946a3a15b..91e5f885c6 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -178,7 +178,7 @@ func (g *Generator) renderCmd() error { func renderCmdFiles(cmdProjectDir, repoPath, apiVersion, kind string) error { buf := &bytes.Buffer{} - if err := renderGenericFile(buf, "cmd//main.go", mainTmpl, tmplData{ + if err := renderFile(buf, "cmd//main.go", mainTmpl, tmplData{ OperatorSDKImport: sdkImport, StubImport: filepath.Join(repoPath, stubDir), K8sutilImport: k8sutilImport, @@ -213,7 +213,7 @@ func (g *Generator) renderDeploy() error { func renderRBAC(deployDir, projectName, groupName string) error { buf := &bytes.Buffer{} - if err := renderGenericFile(buf, rbacTmplName, rbacYamlTmpl, tmplData{ + if err := renderFile(buf, rbacTmplName, rbacYamlTmpl, tmplData{ ProjectName: projectName, GroupName: groupName, }); err != nil { @@ -225,7 +225,7 @@ func renderRBAC(deployDir, projectName, groupName string) error { func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { buf := &bytes.Buffer{} - if err := renderGenericFile(buf, rbacTmplName, rbacYamlTmpl, tmplData{ + if err := renderFile(buf, rbacTmplName, rbacYamlTmpl, tmplData{ ProjectName: projectName, GroupName: groupName(apiVersion), }); err != nil { @@ -236,7 +236,7 @@ func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { } buf = &bytes.Buffer{} - if err := renderGenericFile(buf, crdTmplName, crdYamlTmpl, tmplData{ + if err := renderFile(buf, crdTmplName, crdYamlTmpl, tmplData{ Kind: kind, KindSingular: strings.ToLower(kind), KindPlural: toPlural(strings.ToLower(kind)), @@ -250,7 +250,7 @@ func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { } buf = &bytes.Buffer{} - if err := renderGenericFile(buf, crTmplName, crYamlTmpl, tmplData{ + if err := renderFile(buf, crTmplName, crYamlTmpl, tmplData{ APIVersion: apiVersion, Kind: kind, }); err != nil { @@ -262,7 +262,7 @@ func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { // RenderOperatorYaml generates "deploy/operator.yaml" func RenderOperatorYaml(c *Config, image string) error { buf := &bytes.Buffer{} - if err := renderGenericFile(buf, operatorTmplName, operatorYamlTmpl, tmplData{ + if err := renderFile(buf, operatorTmplName, operatorYamlTmpl, tmplData{ ProjectName: c.ProjectName, Image: image, }); err != nil { @@ -283,7 +283,7 @@ func RenderOlmCatalog(c *Config, image, version string) error { // deploy/olm-catalog/package.yaml buf := &bytes.Buffer{} - if err := renderGenericFile(buf, catalogPackageYaml, catalogPackageTmpl, tmplData{ + if err := renderFile(buf, catalogPackageYaml, catalogPackageTmpl, tmplData{ PackageName: strings.ToLower(c.Kind), ChannelName: packageChannel, CurrentCSV: getCSVName(strings.ToLower(c.Kind), version), @@ -297,7 +297,7 @@ func RenderOlmCatalog(c *Config, image, version string) error { // deploy/olm-catalog/crd.yaml buf = &bytes.Buffer{} - if err := renderGenericFile(buf, catalogCRDTmplName, crdTmpl, tmplData{ + if err := renderFile(buf, catalogCRDTmplName, crdTmpl, tmplData{ Kind: c.Kind, KindSingular: strings.ToLower(c.Kind), KindPlural: toPlural(strings.ToLower(c.Kind)), @@ -313,7 +313,7 @@ func RenderOlmCatalog(c *Config, image, version string) error { // deploy/olm-catalog/csv.yaml buf = &bytes.Buffer{} - if err := renderGenericFile(buf, catalogCSVYaml, catalogCSVTmpl, tmplData{ + if err := renderFile(buf, catalogCSVYaml, catalogCSVTmpl, tmplData{ Kind: c.Kind, KindSingular: strings.ToLower(c.Kind), KindPlural: toPlural(strings.ToLower(c.Kind)), @@ -347,7 +347,7 @@ func (g *Generator) renderTmp() error { func (g *Generator) renderVersion() error { buf := &bytes.Buffer{} - if err := renderGenericFile(buf, "version/version.go", versionTmpl, tmplData{VersionNumber: "0.0.1"}); err != nil { + if err := renderFile(buf, "version/version.go", versionTmpl, tmplData{VersionNumber: "0.0.1"}); err != nil { return err } @@ -357,7 +357,7 @@ func (g *Generator) renderVersion() error { func renderBuildFiles(buildDir, repoPath, projectName string) error { buf := &bytes.Buffer{} - if err := renderGenericFile(buf, "tmp/build/build.sh", buildTmpl, tmplData{ + if err := renderFile(buf, "tmp/build/build.sh", buildTmpl, tmplData{ ProjectName: projectName, RepoPath: repoPath, }); err != nil { @@ -376,7 +376,7 @@ func renderBuildFiles(buildDir, repoPath, projectName string) error { } buf = &bytes.Buffer{} - if err := renderGenericFile(buf, "tmp/build/Dockerfile", dockerFileTmpl, tmplData{ + if err := renderFile(buf, "tmp/build/Dockerfile", dockerFileTmpl, tmplData{ ProjectName: projectName, }); err != nil { return err @@ -391,7 +391,7 @@ func renderDockerBuildFile(w io.Writer) error { func renderCodegenFiles(codegenDir, repoPath, apiDirName, version, projectName string) error { buf := &bytes.Buffer{} - if err := renderGenericFile(buf, "codegen/boilerplate.go.txt", boilerplateTmpl, tmplData{ + if err := renderFile(buf, "codegen/boilerplate.go.txt", boilerplateTmpl, tmplData{ ProjectName: projectName, }); err != nil { return err @@ -401,7 +401,7 @@ func renderCodegenFiles(codegenDir, repoPath, apiDirName, version, projectName s } buf = &bytes.Buffer{} - if err := renderGenericFile(buf, "codegen/update-generated.sh", updateGeneratedTmpl, tmplData{ + if err := renderFile(buf, "codegen/update-generated.sh", updateGeneratedTmpl, tmplData{ RepoPath: repoPath, APIDirName: apiDirName, Version: version, @@ -425,7 +425,7 @@ func (g *Generator) renderPkg() error { func renderAPIFiles(apiDir, groupName, version, kind string) error { buf := &bytes.Buffer{} - if err := renderGenericFile(buf, "apis///doc.go", apiDocTmpl, tmplData{ + if err := renderFile(buf, "apis///doc.go", apiDocTmpl, tmplData{ GroupName: groupName, Version: version, }); err != nil { @@ -436,7 +436,7 @@ func renderAPIFiles(apiDir, groupName, version, kind string) error { } buf = &bytes.Buffer{} - if err := renderGenericFile(buf, "apis///register.go", apiRegisterTmpl, tmplData{ + if err := renderFile(buf, "apis///register.go", apiRegisterTmpl, tmplData{ Kind: kind, KindPlural: toPlural(strings.ToLower(kind)), GroupName: groupName, @@ -449,7 +449,7 @@ func renderAPIFiles(apiDir, groupName, version, kind string) error { } buf = &bytes.Buffer{} - if err := renderGenericFile(buf, "apis///types.go", apiTypesTmpl, tmplData{ + if err := renderFile(buf, "apis///types.go", apiTypesTmpl, tmplData{ Kind: kind, Version: version, }); err != nil { @@ -460,7 +460,7 @@ func renderAPIFiles(apiDir, groupName, version, kind string) error { func renderStubFiles(stubDir, repoPath, kind, apiDirName, version string) error { buf := &bytes.Buffer{} - if err := renderGenericFile(buf, "stub/handler.go", handlerTmpl, tmplData{ + if err := renderFile(buf, "stub/handler.go", handlerTmpl, tmplData{ OperatorSDKImport: sdkImport, RepoPath: repoPath, Kind: kind, @@ -505,6 +505,7 @@ type tmplData struct { CatalogVersion string } +//Creates all the necesary directories for the generated files func (g *Generator) generateDirStructure() error { if err := os.MkdirAll(g.projectName, defaultDirFileMode); err != nil { return err @@ -557,7 +558,8 @@ func (g *Generator) generateDirStructure() error { return nil } -func renderGenericFile(w io.Writer, fileLoc string, fileTmpl string, info tmplData) error { +//Renders a file given a template, and fills in template fields according to values passed in the tmplData struct +func renderFile(w io.Writer, fileLoc string, fileTmpl string, info tmplData) error { t := template.New(fileLoc) t, err := t.Parse(fileTmpl) diff --git a/pkg/generator/generator_test.go b/pkg/generator/generator_test.go index 6ceab64de1..3d18d68e98 100644 --- a/pkg/generator/generator_test.go +++ b/pkg/generator/generator_test.go @@ -28,7 +28,7 @@ var ( func TestGenVersion(t *testing.T) { buf := &bytes.Buffer{} - if err := renderGenericFile(buf, "version/version.go", versionTmpl, tmplData{VersionNumber: "0.9.2+git"}); err != nil { + if err := renderFile(buf, "version/version.go", versionTmpl, tmplData{VersionNumber: "0.9.2+git"}); err != nil { t.Error(err) return } From aad5419e5ad9335e077db56a791ec0188aed1e38 Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Mon, 11 Jun 2018 13:00:18 -0700 Subject: [PATCH 09/21] Add comments for file writer func --- pkg/generator/generator.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 91e5f885c6..241920a642 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -589,6 +589,7 @@ func apiDirName(apiVersion string) string { return strings.Split(groupName(apiVersion), ".")[0] } +// Writes file to a given path and data buffer, as well as prints out a message confirming creation of a file func writeFileAndPrint(filePath string, data []byte, fileMode os.FileMode) error { if err := ioutil.WriteFile(filePath, data, fileMode); err != nil { return err From e57b5b729c7ab7dcda4a0d7fd84a4718266d582c Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Mon, 11 Jun 2018 13:31:46 -0700 Subject: [PATCH 10/21] Added kind plural suffix to const strings --- pkg/generator/generator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 241920a642..7b318c8e65 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -75,7 +75,7 @@ const ( operatorTmplName = "deploy/operator.yaml" rbacTmplName = "deploy/rbac.yaml" crTmplName = "deploy/cr.yaml" - // pluralSuffix = "s" + pluralSuffix = "s" ) type Generator struct { From 60900407653269791a82f4bd6fb7b145a2c9fba8 Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Tue, 12 Jun 2018 12:53:39 -0700 Subject: [PATCH 11/21] Add singular/plural comments --- pkg/generator/generator.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 7b318c8e65..f5e70431a2 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -490,8 +490,10 @@ type tmplData struct { ProjectName string GroupName string + // plural name to be used in the URL: /apis/// KindSingular string - KindPlural string + // singular name to be used as an alias on the CLI and for display + KindPlural string Image string Name string From 2522bcc5b9a38f987db49e658b5917be5f1024cd Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Tue, 12 Jun 2018 14:43:29 -0700 Subject: [PATCH 12/21] Typo in comments --- pkg/generator/generator.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index f5e70431a2..860f1c518d 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -490,9 +490,9 @@ type tmplData struct { ProjectName string GroupName string - // plural name to be used in the URL: /apis/// - KindSingular string // singular name to be used as an alias on the CLI and for display + KindSingular string + // plural name to be used in the URL: /apis/// KindPlural string Image string From 56a685119d5c09daaf5980b2f84d12d2aedbb32f Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Wed, 13 Jun 2018 09:28:59 -0700 Subject: [PATCH 13/21] Declare template data struct before passing into render func --- pkg/generator/generator.go | 94 ++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 35 deletions(-) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 860f1c518d..8f6aa78660 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -178,14 +178,16 @@ func (g *Generator) renderCmd() error { func renderCmdFiles(cmdProjectDir, repoPath, apiVersion, kind string) error { buf := &bytes.Buffer{} - if err := renderFile(buf, "cmd//main.go", mainTmpl, tmplData{ + td := tmplData{ OperatorSDKImport: sdkImport, StubImport: filepath.Join(repoPath, stubDir), K8sutilImport: k8sutilImport, SDKVersionImport: versionImport, APIVersion: apiVersion, Kind: kind, - }); err != nil { + } + + if err := renderFile(buf, "cmd//main.go", mainTmpl, td); err != nil { return err } @@ -213,10 +215,12 @@ func (g *Generator) renderDeploy() error { func renderRBAC(deployDir, projectName, groupName string) error { buf := &bytes.Buffer{} - if err := renderFile(buf, rbacTmplName, rbacYamlTmpl, tmplData{ + td := tmplData{ ProjectName: projectName, GroupName: groupName, - }); err != nil { + } + + if err := renderFile(buf, rbacTmplName, rbacYamlTmpl, td); err != nil { return err } @@ -225,10 +229,11 @@ func renderRBAC(deployDir, projectName, groupName string) error { func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { buf := &bytes.Buffer{} - if err := renderFile(buf, rbacTmplName, rbacYamlTmpl, tmplData{ + rbacTd := tmplData{ ProjectName: projectName, GroupName: groupName(apiVersion), - }); err != nil { + } + if err := renderFile(buf, rbacTmplName, rbacYamlTmpl, rbacTd); err != nil { return err } if err := writeFileAndPrint(filepath.Join(deployDir, rbacYaml), buf.Bytes(), defaultFileMode); err != nil { @@ -236,13 +241,14 @@ func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { } buf = &bytes.Buffer{} - if err := renderFile(buf, crdTmplName, crdYamlTmpl, tmplData{ + crdTd := tmplData{ Kind: kind, KindSingular: strings.ToLower(kind), KindPlural: toPlural(strings.ToLower(kind)), GroupName: groupName(apiVersion), Version: version(apiVersion), - }); err != nil { + } + if err := renderFile(buf, crdTmplName, crdYamlTmpl, crdTd); err != nil { return err } if err := writeFileAndPrint(filepath.Join(deployDir, crdYaml), buf.Bytes(), defaultFileMode); err != nil { @@ -250,10 +256,11 @@ func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { } buf = &bytes.Buffer{} - if err := renderFile(buf, crTmplName, crYamlTmpl, tmplData{ + crTd := tmplData{ APIVersion: apiVersion, Kind: kind, - }); err != nil { + } + if err := renderFile(buf, crTmplName, crYamlTmpl, crTd); err != nil { return err } return writeFileAndPrint(filepath.Join(deployDir, crYaml), buf.Bytes(), defaultFileMode) @@ -262,10 +269,11 @@ func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { // RenderOperatorYaml generates "deploy/operator.yaml" func RenderOperatorYaml(c *Config, image string) error { buf := &bytes.Buffer{} - if err := renderFile(buf, operatorTmplName, operatorYamlTmpl, tmplData{ + td := tmplData{ ProjectName: c.ProjectName, Image: image, - }); err != nil { + } + if err := renderFile(buf, operatorTmplName, operatorYamlTmpl, td); err != nil { return err } return ioutil.WriteFile(operatorYaml, buf.Bytes(), defaultFileMode) @@ -283,11 +291,12 @@ func RenderOlmCatalog(c *Config, image, version string) error { // deploy/olm-catalog/package.yaml buf := &bytes.Buffer{} - if err := renderFile(buf, catalogPackageYaml, catalogPackageTmpl, tmplData{ + cpTd := tmplData{ PackageName: strings.ToLower(c.Kind), ChannelName: packageChannel, CurrentCSV: getCSVName(strings.ToLower(c.Kind), version), - }); err != nil { + } + if err := renderFile(buf, catalogPackageYaml, catalogPackageTmpl, cpTd); err != nil { return err } path := filepath.Join(olmDir, catalogPackageYaml) @@ -297,13 +306,14 @@ func RenderOlmCatalog(c *Config, image, version string) error { // deploy/olm-catalog/crd.yaml buf = &bytes.Buffer{} - if err := renderFile(buf, catalogCRDTmplName, crdTmpl, tmplData{ + ccrdTd := tmplData{ Kind: c.Kind, KindSingular: strings.ToLower(c.Kind), KindPlural: toPlural(strings.ToLower(c.Kind)), GroupName: groupName(c.APIVersion), Version: version, - }); err != nil { + } + if err := renderFile(buf, catalogCRDTmplName, crdTmpl, ccrdTd); err != nil { return err } path = filepath.Join(olmDir, crdYaml) @@ -313,7 +323,7 @@ func RenderOlmCatalog(c *Config, image, version string) error { // deploy/olm-catalog/csv.yaml buf = &bytes.Buffer{} - if err := renderFile(buf, catalogCSVYaml, catalogCSVTmpl, tmplData{ + ccsvTd := tmplData{ Kind: c.Kind, KindSingular: strings.ToLower(c.Kind), KindPlural: toPlural(strings.ToLower(c.Kind)), @@ -323,7 +333,8 @@ func RenderOlmCatalog(c *Config, image, version string) error { Image: image, CatalogVersion: version, ProjectName: c.ProjectName, - }); err != nil { + } + if err := renderFile(buf, catalogCSVYaml, catalogCSVTmpl, ccsvTd); err != nil { return err } path = filepath.Join(olmDir, catalogCSVYaml) @@ -347,7 +358,11 @@ func (g *Generator) renderTmp() error { func (g *Generator) renderVersion() error { buf := &bytes.Buffer{} - if err := renderFile(buf, "version/version.go", versionTmpl, tmplData{VersionNumber: "0.0.1"}); err != nil { + td := tmplData{ + VersionNumber: "0.0.1", + } + + if err := renderFile(buf, "version/version.go", versionTmpl, td); err != nil { return err } @@ -357,10 +372,12 @@ func (g *Generator) renderVersion() error { func renderBuildFiles(buildDir, repoPath, projectName string) error { buf := &bytes.Buffer{} - if err := renderFile(buf, "tmp/build/build.sh", buildTmpl, tmplData{ + bTd := tmplData{ ProjectName: projectName, RepoPath: repoPath, - }); err != nil { + } + + if err := renderFile(buf, "tmp/build/build.sh", buildTmpl, bTd); err != nil { return err } if err := writeFileAndPrint(filepath.Join(buildDir, build), buf.Bytes(), defaultExecFileMode); err != nil { @@ -376,9 +393,10 @@ func renderBuildFiles(buildDir, repoPath, projectName string) error { } buf = &bytes.Buffer{} - if err := renderFile(buf, "tmp/build/Dockerfile", dockerFileTmpl, tmplData{ + dTd := tmplData{ ProjectName: projectName, - }); err != nil { + } + if err := renderFile(buf, "tmp/build/Dockerfile", dockerFileTmpl, dTd); err != nil { return err } return writeFileAndPrint(filepath.Join(buildDir, dockerfile), buf.Bytes(), defaultFileMode) @@ -391,9 +409,10 @@ func renderDockerBuildFile(w io.Writer) error { func renderCodegenFiles(codegenDir, repoPath, apiDirName, version, projectName string) error { buf := &bytes.Buffer{} - if err := renderFile(buf, "codegen/boilerplate.go.txt", boilerplateTmpl, tmplData{ + bTd := tmplData{ ProjectName: projectName, - }); err != nil { + } + if err := renderFile(buf, "codegen/boilerplate.go.txt", boilerplateTmpl, bTd); err != nil { return err } if err := writeFileAndPrint(filepath.Join(codegenDir, boilerplate), buf.Bytes(), defaultFileMode); err != nil { @@ -401,11 +420,12 @@ func renderCodegenFiles(codegenDir, repoPath, apiDirName, version, projectName s } buf = &bytes.Buffer{} - if err := renderFile(buf, "codegen/update-generated.sh", updateGeneratedTmpl, tmplData{ + ugTd := tmplData{ RepoPath: repoPath, APIDirName: apiDirName, Version: version, - }); err != nil { + } + if err := renderFile(buf, "codegen/update-generated.sh", updateGeneratedTmpl, ugTd); err != nil { return err } return writeFileAndPrint(filepath.Join(codegenDir, updateGenerated), buf.Bytes(), defaultExecFileMode) @@ -425,10 +445,11 @@ func (g *Generator) renderPkg() error { func renderAPIFiles(apiDir, groupName, version, kind string) error { buf := &bytes.Buffer{} - if err := renderFile(buf, "apis///doc.go", apiDocTmpl, tmplData{ + adTd := tmplData{ GroupName: groupName, Version: version, - }); err != nil { + } + if err := renderFile(buf, "apis///doc.go", apiDocTmpl, adTd); err != nil { return err } if err := writeFileAndPrint(filepath.Join(apiDir, doc), buf.Bytes(), defaultFileMode); err != nil { @@ -436,12 +457,13 @@ func renderAPIFiles(apiDir, groupName, version, kind string) error { } buf = &bytes.Buffer{} - if err := renderFile(buf, "apis///register.go", apiRegisterTmpl, tmplData{ + arTd := tmplData{ Kind: kind, KindPlural: toPlural(strings.ToLower(kind)), GroupName: groupName, Version: version, - }); err != nil { + } + if err := renderFile(buf, "apis///register.go", apiRegisterTmpl, arTd); err != nil { return err } if err := writeFileAndPrint(filepath.Join(apiDir, register), buf.Bytes(), defaultFileMode); err != nil { @@ -449,10 +471,11 @@ func renderAPIFiles(apiDir, groupName, version, kind string) error { } buf = &bytes.Buffer{} - if err := renderFile(buf, "apis///types.go", apiTypesTmpl, tmplData{ + atTd := tmplData{ Kind: kind, Version: version, - }); err != nil { + } + if err := renderFile(buf, "apis///types.go", apiTypesTmpl, atTd); err != nil { return err } return writeFileAndPrint(filepath.Join(apiDir, types), buf.Bytes(), defaultFileMode) @@ -460,13 +483,14 @@ func renderAPIFiles(apiDir, groupName, version, kind string) error { func renderStubFiles(stubDir, repoPath, kind, apiDirName, version string) error { buf := &bytes.Buffer{} - if err := renderFile(buf, "stub/handler.go", handlerTmpl, tmplData{ + td := tmplData{ OperatorSDKImport: sdkImport, RepoPath: repoPath, Kind: kind, APIDirName: apiDirName, Version: version, - }); err != nil { + } + if err := renderFile(buf, "stub/handler.go", handlerTmpl, td); err != nil { return err } return writeFileAndPrint(filepath.Join(stubDir, handler), buf.Bytes(), defaultFileMode) From 6edde1600d0467fcd0b2ec9481c4efb07eb5cb9f Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Wed, 13 Jun 2018 13:26:40 -0700 Subject: [PATCH 14/21] Comment spacing --- pkg/generator/generator.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 8f6aa78660..cf69334bf5 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -531,7 +531,7 @@ type tmplData struct { CatalogVersion string } -//Creates all the necesary directories for the generated files +// Creates all the necesary directories for the generated files func (g *Generator) generateDirStructure() error { if err := os.MkdirAll(g.projectName, defaultDirFileMode); err != nil { return err @@ -584,7 +584,7 @@ func (g *Generator) generateDirStructure() error { return nil } -//Renders a file given a template, and fills in template fields according to values passed in the tmplData struct +// Renders a file given a template, and fills in template fields according to values passed in the tmplData struct func renderFile(w io.Writer, fileLoc string, fileTmpl string, info tmplData) error { t := template.New(fileLoc) From 7d880e0bd9b10e9f88ae76f67d41bdd4c6e9d402 Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Wed, 13 Jun 2018 13:38:19 -0700 Subject: [PATCH 15/21] Clean up directory generation --- pkg/generator/generator.go | 63 ++++++++++---------------------------- 1 file changed, 17 insertions(+), 46 deletions(-) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index cf69334bf5..d84364992d 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -533,52 +533,23 @@ type tmplData struct { // Creates all the necesary directories for the generated files func (g *Generator) generateDirStructure() error { - if err := os.MkdirAll(g.projectName, defaultDirFileMode); err != nil { - return err - } - - cpDir := filepath.Join(g.projectName, cmdDir, g.projectName) - if err := os.MkdirAll(cpDir, defaultDirFileMode); err != nil { - return err - } - - cp := filepath.Join(g.projectName, configDir) - if err := os.MkdirAll(cp, defaultDirFileMode); err != nil { - return err - } - - dp := filepath.Join(g.projectName, deployDir) - if err := os.MkdirAll(dp, defaultDirFileMode); err != nil { - return err - } - - op := filepath.Join(g.projectName, olmCatalogDir) - if err := os.MkdirAll(op, defaultDirFileMode); err != nil { - return err - } - - bDir := filepath.Join(g.projectName, buildDir) - if err := os.MkdirAll(bDir, defaultDirFileMode); err != nil { - return err - } - cDir := filepath.Join(g.projectName, codegenDir) - if err := os.MkdirAll(cDir, defaultDirFileMode); err != nil { - return err - } - - if err := os.MkdirAll(filepath.Join(g.projectName, versionDir), defaultDirFileMode); err != nil { - return err - } - - v := version(g.apiVersion) - adn := apiDirName(g.apiVersion) - apiDir := filepath.Join(g.projectName, apisDir, adn, v) - if err := os.MkdirAll(apiDir, defaultDirFileMode); err != nil { - return err - } - sDir := filepath.Join(g.projectName, stubDir) - if err := os.MkdirAll(sDir, defaultDirFileMode); err != nil { - return err + dirsToCreate := []string{ + g.projectName, + filepath.Join(g.projectName, cmdDir, g.projectName), + filepath.Join(g.projectName, configDir), + filepath.Join(g.projectName, deployDir), + filepath.Join(g.projectName, olmCatalogDir), + filepath.Join(g.projectName, buildDir), + filepath.Join(g.projectName, codegenDir), + filepath.Join(g.projectName, versionDir), + filepath.Join(g.projectName, apisDir, apiDirName(g.apiVersion), version(g.apiVersion)), + filepath.Join(g.projectName, stubDir), + } + + for _, dir := range dirsToCreate { + if err := os.MkdirAll(dir, defaultDirFileMode); err != nil { + return err + } } return nil From 50d2d4e0bf98e11126040ff029b01ae4b4c64a0d Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Wed, 13 Jun 2018 13:45:12 -0700 Subject: [PATCH 16/21] Combined file write and render func --- pkg/generator/generator.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index d84364992d..3a8e88985f 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -594,3 +594,18 @@ func writeFileAndPrint(filePath string, data []byte, fileMode os.FileMode) error fmt.Printf("Create %v \n", filePath) return nil } + +// Combines steps of creating buffer, writing to buffer, and writing buffer to file in one call +func renderWriteFile(filePath string, fileLoc string, fileTmpl string, info tmplData) error { + buf := &bytes.Buffer{} + + if err := renderFile(buf, fileLoc, fileTmpl, info); err != nil { + return err + } + + if err := writeFileAndPrint(filePath, buf.Bytes(), defaultFileMode); err != nil { + return err + } + + return nil +} From ee20d2104db9bd07457c45643efae8d648e6ea7f Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Wed, 13 Jun 2018 14:03:08 -0700 Subject: [PATCH 17/21] Use new function in place of buf, render, write --- pkg/generator/generator.go | 114 +++++++------------------------------ 1 file changed, 19 insertions(+), 95 deletions(-) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 3a8e88985f..a75486a86a 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -176,8 +176,6 @@ func (g *Generator) renderCmd() error { } func renderCmdFiles(cmdProjectDir, repoPath, apiVersion, kind string) error { - buf := &bytes.Buffer{} - td := tmplData{ OperatorSDKImport: sdkImport, StubImport: filepath.Join(repoPath, stubDir), @@ -187,11 +185,7 @@ func renderCmdFiles(cmdProjectDir, repoPath, apiVersion, kind string) error { Kind: kind, } - if err := renderFile(buf, "cmd//main.go", mainTmpl, td); err != nil { - return err - } - - return writeFileAndPrint(filepath.Join(cmdProjectDir, main), buf.Bytes(), defaultFileMode) + return renderWriteFile(filepath.Join(cmdProjectDir, main), "cmd//main.go", mainTmpl, td) } func (g *Generator) renderConfig() error { @@ -213,34 +207,23 @@ func (g *Generator) renderDeploy() error { } func renderRBAC(deployDir, projectName, groupName string) error { - buf := &bytes.Buffer{} - td := tmplData{ ProjectName: projectName, GroupName: groupName, } - if err := renderFile(buf, rbacTmplName, rbacYamlTmpl, td); err != nil { - return err - } - - return writeFileAndPrint(filepath.Join(deployDir, rbacYaml), buf.Bytes(), defaultFileMode) + return renderWriteFile(filepath.Join(deployDir, rbacYaml), rbacTmplName, rbacYamlTmpl, td) } func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { - buf := &bytes.Buffer{} rbacTd := tmplData{ ProjectName: projectName, GroupName: groupName(apiVersion), } - if err := renderFile(buf, rbacTmplName, rbacYamlTmpl, rbacTd); err != nil { - return err - } - if err := writeFileAndPrint(filepath.Join(deployDir, rbacYaml), buf.Bytes(), defaultFileMode); err != nil { + if err := renderWriteFile(filepath.Join(deployDir, rbacYaml), rbacTmplName, rbacYamlTmpl, rbacTd); err != nil { return err } - buf = &bytes.Buffer{} crdTd := tmplData{ Kind: kind, KindSingular: strings.ToLower(kind), @@ -248,35 +231,24 @@ func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { GroupName: groupName(apiVersion), Version: version(apiVersion), } - if err := renderFile(buf, crdTmplName, crdYamlTmpl, crdTd); err != nil { - return err - } - if err := writeFileAndPrint(filepath.Join(deployDir, crdYaml), buf.Bytes(), defaultFileMode); err != nil { + if err := renderWriteFile(filepath.Join(deployDir, crdYaml), crdTmplName, crdYamlTmpl, crdTd); err != nil { return err } - buf = &bytes.Buffer{} crTd := tmplData{ APIVersion: apiVersion, Kind: kind, } - if err := renderFile(buf, crTmplName, crYamlTmpl, crTd); err != nil { - return err - } - return writeFileAndPrint(filepath.Join(deployDir, crYaml), buf.Bytes(), defaultFileMode) + return renderWriteFile(filepath.Join(deployDir, crYaml), crTmplName, crYamlTmpl, crTd) } // RenderOperatorYaml generates "deploy/operator.yaml" func RenderOperatorYaml(c *Config, image string) error { - buf := &bytes.Buffer{} td := tmplData{ ProjectName: c.ProjectName, Image: image, } - if err := renderFile(buf, operatorTmplName, operatorYamlTmpl, td); err != nil { - return err - } - return ioutil.WriteFile(operatorYaml, buf.Bytes(), defaultFileMode) + return renderWriteFile(operatorYaml, operatorTmplName, operatorYamlTmpl, td) } // RenderOlmCatalog generates catalog manifests "deploy/olm-catalog/*" @@ -290,22 +262,17 @@ func RenderOlmCatalog(c *Config, image, version string) error { olmDir := filepath.Join(repoPath, olmCatalogDir) // deploy/olm-catalog/package.yaml - buf := &bytes.Buffer{} cpTd := tmplData{ PackageName: strings.ToLower(c.Kind), ChannelName: packageChannel, CurrentCSV: getCSVName(strings.ToLower(c.Kind), version), } - if err := renderFile(buf, catalogPackageYaml, catalogPackageTmpl, cpTd); err != nil { - return err - } path := filepath.Join(olmDir, catalogPackageYaml) - if err := ioutil.WriteFile(path, buf.Bytes(), defaultFileMode); err != nil { + if err := renderWriteFile(path, catalogPackageYaml, catalogPackageTmpl, cpTd); err != nil { return err } // deploy/olm-catalog/crd.yaml - buf = &bytes.Buffer{} ccrdTd := tmplData{ Kind: c.Kind, KindSingular: strings.ToLower(c.Kind), @@ -313,16 +280,12 @@ func RenderOlmCatalog(c *Config, image, version string) error { GroupName: groupName(c.APIVersion), Version: version, } - if err := renderFile(buf, catalogCRDTmplName, crdTmpl, ccrdTd); err != nil { - return err - } path = filepath.Join(olmDir, crdYaml) - if err := ioutil.WriteFile(path, buf.Bytes(), defaultFileMode); err != nil { + if err := renderWriteFile(path, catalogCRDTmplName, crdTmpl, ccrdTd); err != nil { return err } // deploy/olm-catalog/csv.yaml - buf = &bytes.Buffer{} ccsvTd := tmplData{ Kind: c.Kind, KindSingular: strings.ToLower(c.Kind), @@ -334,11 +297,8 @@ func RenderOlmCatalog(c *Config, image, version string) error { CatalogVersion: version, ProjectName: c.ProjectName, } - if err := renderFile(buf, catalogCSVYaml, catalogCSVTmpl, ccsvTd); err != nil { - return err - } path = filepath.Join(olmDir, catalogCSVYaml) - return ioutil.WriteFile(path, buf.Bytes(), defaultFileMode) + return renderWriteFile(path, catalogCSVYaml, catalogCSVTmpl, ccsvTd) } func getCSVName(name, version string) string { @@ -356,35 +316,24 @@ func (g *Generator) renderTmp() error { } func (g *Generator) renderVersion() error { - buf := &bytes.Buffer{} - td := tmplData{ VersionNumber: "0.0.1", } - if err := renderFile(buf, "version/version.go", versionTmpl, td); err != nil { - return err - } - - return writeFileAndPrint(filepath.Join(g.projectName, versionDir, versionfile), buf.Bytes(), defaultFileMode) + return renderWriteFile(filepath.Join(g.projectName, versionDir, versionfile), "version/version.go", versionTmpl, td) } func renderBuildFiles(buildDir, repoPath, projectName string) error { - buf := &bytes.Buffer{} - bTd := tmplData{ ProjectName: projectName, RepoPath: repoPath, } - if err := renderFile(buf, "tmp/build/build.sh", buildTmpl, bTd); err != nil { - return err - } - if err := writeFileAndPrint(filepath.Join(buildDir, build), buf.Bytes(), defaultExecFileMode); err != nil { + if err := renderWriteFile(filepath.Join(buildDir, build), "tmp/build/build.sh", buildTmpl, bTd); err != nil { return err } - buf = &bytes.Buffer{} + buf := &bytes.Buffer{} if err := renderDockerBuildFile(buf); err != nil { return err } @@ -392,14 +341,13 @@ func renderBuildFiles(buildDir, repoPath, projectName string) error { return err } - buf = &bytes.Buffer{} dTd := tmplData{ ProjectName: projectName, } if err := renderFile(buf, "tmp/build/Dockerfile", dockerFileTmpl, dTd); err != nil { return err } - return writeFileAndPrint(filepath.Join(buildDir, dockerfile), buf.Bytes(), defaultFileMode) + return renderWriteFile(filepath.Join(buildDir, dockerfile), "tmp/build/Dockerfile", dockerFileTmpl, dTd) } func renderDockerBuildFile(w io.Writer) error { @@ -408,27 +356,19 @@ func renderDockerBuildFile(w io.Writer) error { } func renderCodegenFiles(codegenDir, repoPath, apiDirName, version, projectName string) error { - buf := &bytes.Buffer{} bTd := tmplData{ ProjectName: projectName, } - if err := renderFile(buf, "codegen/boilerplate.go.txt", boilerplateTmpl, bTd); err != nil { - return err - } - if err := writeFileAndPrint(filepath.Join(codegenDir, boilerplate), buf.Bytes(), defaultFileMode); err != nil { + if err := renderWriteFile(filepath.Join(codegenDir, boilerplate), "codegen/boilerplate.go.txt", boilerplateTmpl, bTd); err != nil { return err } - buf = &bytes.Buffer{} ugTd := tmplData{ RepoPath: repoPath, APIDirName: apiDirName, Version: version, } - if err := renderFile(buf, "codegen/update-generated.sh", updateGeneratedTmpl, ugTd); err != nil { - return err - } - return writeFileAndPrint(filepath.Join(codegenDir, updateGenerated), buf.Bytes(), defaultExecFileMode) + return renderWriteFile(filepath.Join(codegenDir, updateGenerated), "codegen/update-generated.sh", updateGeneratedTmpl, ugTd) } func (g *Generator) renderPkg() error { @@ -444,45 +384,32 @@ func (g *Generator) renderPkg() error { } func renderAPIFiles(apiDir, groupName, version, kind string) error { - buf := &bytes.Buffer{} adTd := tmplData{ GroupName: groupName, Version: version, } - if err := renderFile(buf, "apis///doc.go", apiDocTmpl, adTd); err != nil { - return err - } - if err := writeFileAndPrint(filepath.Join(apiDir, doc), buf.Bytes(), defaultFileMode); err != nil { + if err := renderWriteFile(filepath.Join(apiDir, doc), "apis///doc.go", apiDocTmpl, adTd); err != nil { return err } - buf = &bytes.Buffer{} arTd := tmplData{ Kind: kind, KindPlural: toPlural(strings.ToLower(kind)), GroupName: groupName, Version: version, } - if err := renderFile(buf, "apis///register.go", apiRegisterTmpl, arTd); err != nil { - return err - } - if err := writeFileAndPrint(filepath.Join(apiDir, register), buf.Bytes(), defaultFileMode); err != nil { + if err := renderWriteFile(filepath.Join(apiDir, register), "apis///register.go", apiRegisterTmpl, arTd); err != nil { return err } - buf = &bytes.Buffer{} atTd := tmplData{ Kind: kind, Version: version, } - if err := renderFile(buf, "apis///types.go", apiTypesTmpl, atTd); err != nil { - return err - } - return writeFileAndPrint(filepath.Join(apiDir, types), buf.Bytes(), defaultFileMode) + return renderWriteFile(filepath.Join(apiDir, types), "apis///types.go", apiTypesTmpl, atTd) } func renderStubFiles(stubDir, repoPath, kind, apiDirName, version string) error { - buf := &bytes.Buffer{} td := tmplData{ OperatorSDKImport: sdkImport, RepoPath: repoPath, @@ -490,10 +417,7 @@ func renderStubFiles(stubDir, repoPath, kind, apiDirName, version string) error APIDirName: apiDirName, Version: version, } - if err := renderFile(buf, "stub/handler.go", handlerTmpl, td); err != nil { - return err - } - return writeFileAndPrint(filepath.Join(stubDir, handler), buf.Bytes(), defaultFileMode) + return renderWriteFile(filepath.Join(stubDir, handler), "stub/handler.go", handlerTmpl, td) } type tmplData struct { From 518b633f8366534645beaed0fc22bdc4c8aed3e1 Mon Sep 17 00:00:00 2001 From: Ish Shah Date: Thu, 14 Jun 2018 12:56:08 -0700 Subject: [PATCH 18/21] Fix executable file generation --- pkg/generator/generator.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index a75486a86a..4bd9aaa63e 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -324,16 +324,20 @@ func (g *Generator) renderVersion() error { } func renderBuildFiles(buildDir, repoPath, projectName string) error { + buf := &bytes.Buffer{} bTd := tmplData{ ProjectName: projectName, RepoPath: repoPath, } - if err := renderWriteFile(filepath.Join(buildDir, build), "tmp/build/build.sh", buildTmpl, bTd); err != nil { + if err := renderFile(buf, "tmp/build/build.sh", buildTmpl, bTd); err != nil { + return err + } + if err := writeFileAndPrint(filepath.Join(buildDir, build), buf.Bytes(), defaultExecFileMode); err != nil { return err } - buf := &bytes.Buffer{} + buf = &bytes.Buffer{} if err := renderDockerBuildFile(buf); err != nil { return err } @@ -363,12 +367,16 @@ func renderCodegenFiles(codegenDir, repoPath, apiDirName, version, projectName s return err } + buf := &bytes.Buffer{} ugTd := tmplData{ RepoPath: repoPath, APIDirName: apiDirName, Version: version, } - return renderWriteFile(filepath.Join(codegenDir, updateGenerated), "codegen/update-generated.sh", updateGeneratedTmpl, ugTd) + if err := renderFile(buf, "codegen/update-generated.sh", updateGeneratedTmpl, ugTd); err != nil { + return err + } + return writeFileAndPrint(filepath.Join(codegenDir, updateGenerated), buf.Bytes(), defaultExecFileMode) } func (g *Generator) renderPkg() error { From f7b70b88ff8db3c48d21bdf86af2e9dccbf28987 Mon Sep 17 00:00:00 2001 From: Etienne Coutaud Date: Fri, 1 Jun 2018 11:02:24 +0200 Subject: [PATCH 19/21] commands/up: Add OPERATOR_NAME env var when run locally --- Gopkg.lock | 2 +- Gopkg.toml | 4 + pkg/generator/gen_deploy_test.go | 171 +++++++++++++++++++++++++++++++ pkg/generator/gen_main_test.go | 78 ++++++++++++++ pkg/generator/generator.go | 2 + pkg/generator/templates.go | 14 ++- 6 files changed, 267 insertions(+), 4 deletions(-) create mode 100644 pkg/generator/gen_deploy_test.go create mode 100644 pkg/generator/gen_main_test.go diff --git a/Gopkg.lock b/Gopkg.lock index f8180644e3..787bc5ab10 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -404,6 +404,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "d5cc928bcf8f796babddedb13b1516b8d6fbc2f48d68546b712af753671673e2" + inputs-digest = "f310ffe8b6a0cff2978d4f2e11c7f32dcb008225c1c9193e9f7da20f34935189" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 5a72d67e2e..492b98e2b4 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -6,6 +6,10 @@ name = "github.com/spf13/cobra" version = "0.0.2" +[[override]] + name = "github.com/prometheus/client_golang" + version = "0.8.0" + [[override]] name = "k8s.io/api" version = "kubernetes-1.9.3" diff --git a/pkg/generator/gen_deploy_test.go b/pkg/generator/gen_deploy_test.go new file mode 100644 index 0000000000..3e92e231b4 --- /dev/null +++ b/pkg/generator/gen_deploy_test.go @@ -0,0 +1,171 @@ +package generator + +import ( + "bytes" + "testing" +) + +const crdYamlExp = `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 +` + +const operatorYamlExp = `apiVersion: apps/v1 +kind: Deployment +metadata: + name: app-operator + labels: + name: app-operator +spec: + replicas: 1 + selector: + matchLabels: + name: app-operator + template: + metadata: + labels: + name: app-operator + spec: + containers: + - name: app-operator + image: quay.io/example-inc/app-operator:0.0.1 + ports: + - containerPort: 9090 + name: metrics + command: + - app-operator + imagePullPolicy: Always + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace +` + +const rbacYamlExp = `kind: Role +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: app-operator +rules: +- apiGroups: + - app.example.com + resources: + - "*" + verbs: + - "*" +- apiGroups: + - "" + resources: + - pods + - services + - endpoints + - persistentvolumeclaims + - events + - configmaps + - secrets + verbs: + - "*" +- apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - "*" + +--- + +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: default-account-app-operator +subjects: +- kind: ServiceAccount + name: default +roleRef: + kind: Role + name: app-operator + apiGroup: rbac.authorization.k8s.io +` + +const serviceYamlExp = `apiVersion: v1 +kind: Service +metadata: + name: app-operator + labels: + name: app-operator +spec: + selector: + name: app-operator + ports: + - protocol: TCP + targetPort: metrics + port: 9090 + name: metrics` + +const serviceMonitorYamlExp = `apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: app-operator + labels: + name: app-operator +spec: + selector: + matchLabels: + name: app-operator + endpoints: + - port: metrics` + +func TestGenDeploy(t *testing.T) { + buf := &bytes.Buffer{} + if err := renderCRDYaml(buf, appKind, appAPIVersion); err != nil { + t.Error(err) + } + if crdYamlExp != buf.String() { + t.Errorf(errorMessage, crdYamlExp, buf.String()) + } + + buf = &bytes.Buffer{} + if err := renderOperatorYaml(buf, appProjectName, appImage); err != nil { + t.Error(err) + } + if operatorYamlExp != buf.String() { + t.Errorf(errorMessage, operatorYamlExp, buf.String()) + } + + buf = &bytes.Buffer{} + if err := renderRBACYaml(buf, appProjectName, appGroupName); err != nil { + t.Error(err) + } + if rbacYamlExp != buf.String() { + t.Errorf(errorMessage, rbacYamlExp, buf.String()) + } + + buf = &bytes.Buffer{} + if err := renderServiceYaml(buf, appProjectName); err != nil { + t.Error(err) + } + if serviceYamlExp != buf.String() { + t.Errorf("want %v, got %v", serviceYamlExp, buf.String()) + } + + buf = &bytes.Buffer{} + if err := renderServiceMonitorYaml(buf, appProjectName); err != nil { + t.Error(err) + } + if serviceMonitorYamlExp != buf.String() { + t.Errorf("want %v, got %v", serviceMonitorYamlExp, buf.String()) + } +} diff --git a/pkg/generator/gen_main_test.go b/pkg/generator/gen_main_test.go new file mode 100644 index 0000000000..55650bd9ed --- /dev/null +++ b/pkg/generator/gen_main_test.go @@ -0,0 +1,78 @@ +// Copyright 2018 The Operator-SDK 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 generator + +import ( + "bytes" + "testing" +) + +const mainExp = `package main + +import ( + "context" + "runtime" + "net/http" + + stub "github.com/example-inc/app-operator/pkg/stub" + sdk "github.com/operator-framework/operator-sdk/pkg/sdk" + k8sutil "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" + sdkVersion "github.com/operator-framework/operator-sdk/version" + + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/sirupsen/logrus" +) + +// Prometheus metrics port +const promPort = ":9090" + +func printVersion() { + logrus.Infof("Go Version: %s", runtime.Version()) + logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) + logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) + logrus.Infof("operator prometheus port :%s", promPort) +} + +func main() { + printVersion() + + http.Handle("/metrics", promhttp.Handler()) + logrus.Fatalf("%s", http.ListenAndServe(promPort, nil)) + + resource := "app.example.com/v1alpha1" + kind := "AppService" + namespace, err := k8sutil.GetWatchNamespace() + if err != nil { + logrus.Fatalf("Failed to get watch namespace: %v", err) + } + resyncPeriod := 5 + logrus.Infof("Watching %s, %s, %s, %d", resource, kind, namespace, resyncPeriod) + sdk.Watch(resource, kind, namespace, resyncPeriod) + sdk.Handle(stub.NewHandler()) + sdk.Run(context.TODO()) +} +` + +func TestGenMain(t *testing.T) { + buf := &bytes.Buffer{} + if err := renderMainFile(buf, appRepoPath, appAPIVersion, appKind); err != nil { + t.Error(err) + return + } + + if mainExp != buf.String() { + t.Errorf(errorMessage, mainExp, buf.String()) + } +} diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 4bd9aaa63e..d601a76c9d 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -57,6 +57,8 @@ const ( gopkglock = "Gopkg.lock" config = "config.yaml" operatorYaml = deployDir + "/operator.yaml" + serviceYaml = "service.yaml" + serviceMonitorYaml = "serviceMonitor.yaml" rbacYaml = "rbac.yaml" crYaml = "cr.yaml" catalogPackageYaml = "package.yaml" diff --git a/pkg/generator/templates.go b/pkg/generator/templates.go index cdfe30a380..8a4dbfd256 100644 --- a/pkg/generator/templates.go +++ b/pkg/generator/templates.go @@ -136,20 +136,28 @@ import ( stub "{{.StubImport}}" sdk "{{.OperatorSDKImport}}" k8sutil "{{.K8sutilImport}}" - sdkVersion "{{.SDKVersionImport}}" - + sdkVersion "{{.SDKVersionImport}}" + + "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/sirupsen/logrus" ) +// Prometheus metrics port +const promPort = ":9090" + func printVersion() { logrus.Infof("Go Version: %s", runtime.Version()) logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) - logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) + logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) + logrus.Infof("operator prometheus port :%s", promPort) } func main() { printVersion() + http.Handle("/metrics", promhttp.Handler()) + logrus.Fatalf("%s", http.ListenAndServe(promPort, nil)) + resource := "{{.APIVersion}}" kind := "{{.Kind}}" namespace, err := k8sutil.GetWatchNamespace() From 6e7ff06909e7a406da574565e8e37953ce3fb432 Mon Sep 17 00:00:00 2001 From: Etienne Coutaud Date: Fri, 1 Jun 2018 11:03:56 +0200 Subject: [PATCH 20/21] pkg/util: Init service object + GetOperatorName env var and test --- pkg/generator/gen_deploy.go | 129 +++++++++++++++++++++++++++++++ pkg/generator/gen_deploy_test.go | 48 +----------- pkg/generator/gen_main.go | 64 +++++++++++++++ pkg/generator/gen_main_test.go | 71 ++++++++++------- pkg/generator/generator.go | 2 - pkg/generator/templates.go | 75 +++++++++++------- pkg/util/k8sutil/constants.go | 7 ++ pkg/util/k8sutil/k8sutil.go | 58 ++++++++++++++ pkg/util/k8sutil/k8sutil_test.go | 61 +++++++++++++++ 9 files changed, 410 insertions(+), 105 deletions(-) create mode 100644 pkg/generator/gen_deploy.go create mode 100644 pkg/generator/gen_main.go create mode 100644 pkg/util/k8sutil/k8sutil_test.go diff --git a/pkg/generator/gen_deploy.go b/pkg/generator/gen_deploy.go new file mode 100644 index 0000000000..131147c1eb --- /dev/null +++ b/pkg/generator/gen_deploy.go @@ -0,0 +1,129 @@ +// Copyright 2018 The Operator-SDK 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 generator + +import ( + "fmt" + "io" + "strings" + "text/template" + + "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" +) + +const ( + crdTmplName = "deploy/crd.yaml" + operatorTmplName = "deploy/operator.yaml" + rbacTmplName = "deploy/rbac.yaml" + crTmplName = "deploy/cr.yaml" +) + +// CRDYaml contains data needed to generate deploy/crd.yaml +type CRDYaml struct { + Kind string + KindSingular string + KindPlural string + GroupName string + Version string +} + +// renderCRDYaml generates deploy/crd.yaml +func renderCRDYaml(w io.Writer, kind, apiVersion string) error { + t := template.New(crdTmplName) + t, err := t.Parse(crdYamlTmpl) + if err != nil { + return fmt.Errorf("failed to parse crd yaml template: %v", err) + } + + ks := strings.ToLower(kind) + o := CRDYaml{ + Kind: kind, + KindSingular: ks, + KindPlural: toPlural(ks), + GroupName: groupName(apiVersion), + Version: version(apiVersion), + } + return t.Execute(w, o) +} + +// OperatorYaml contains data needed to generate deploy/operator.yaml +type OperatorYaml struct { + ProjectName string + Image string + NameEnv string + NamespaceEnv string + MetricsPort int +} + +// renderOperatorYaml generates deploy/operator.yaml. +func renderOperatorYaml(w io.Writer, projectName, image string) error { + t := template.New(operatorTmplName) + t, err := t.Parse(operatorYamlTmpl) + if err != nil { + return fmt.Errorf("failed to parse operator yaml template: %v", err) + } + + o := OperatorYaml{ + ProjectName: projectName, + Image: image, + NameEnv: k8sutil.OperatorNameEnvVar, + NamespaceEnv: k8sutil.WatchNamespaceEnvVar, + MetricsPort: k8sutil.PrometheusMetricsPort, + } + return t.Execute(w, o) +} + +// RBACYaml contains all the customized data needed to generate deploy/rbac.yaml for a new operator +// when pairing with rbacYamlTmpl template. +type RBACYaml struct { + ProjectName string + GroupName string +} + +// renderRBACYaml generates deploy/rbac.yaml. +func renderRBACYaml(w io.Writer, projectName, groupName string) error { + t := template.New(rbacTmplName) + t, err := t.Parse(rbacYamlTmpl) + if err != nil { + return fmt.Errorf("failed to parse rbac yaml template: %v", err) + } + + r := RBACYaml{ + ProjectName: projectName, + GroupName: groupName, + } + return t.Execute(w, r) +} + +// CRYaml contains all the customized data needed to generate deploy/cr.yaml. +type CRYaml struct { + APIVersion string + Kind string + Name string +} + +func renderCustomResourceYaml(w io.Writer, apiVersion, kind string) error { + t := template.New(crTmplName) + t, err := t.Parse(crYamlTmpl) + if err != nil { + return fmt.Errorf("failed to parse cr yaml template: %v", err) + } + + r := CRYaml{ + APIVersion: apiVersion, + Kind: kind, + } + return t.Execute(w, r) +} diff --git a/pkg/generator/gen_deploy_test.go b/pkg/generator/gen_deploy_test.go index 3e92e231b4..b2f5df2186 100644 --- a/pkg/generator/gen_deploy_test.go +++ b/pkg/generator/gen_deploy_test.go @@ -40,7 +40,7 @@ spec: - name: app-operator image: quay.io/example-inc/app-operator:0.0.1 ports: - - containerPort: 9090 + - containerPort: 60000 name: metrics command: - app-operator @@ -50,6 +50,8 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace + - name: OPERATOR_NAME + value: "app-operator" ` const rbacYamlExp = `kind: Role @@ -100,34 +102,6 @@ roleRef: apiGroup: rbac.authorization.k8s.io ` -const serviceYamlExp = `apiVersion: v1 -kind: Service -metadata: - name: app-operator - labels: - name: app-operator -spec: - selector: - name: app-operator - ports: - - protocol: TCP - targetPort: metrics - port: 9090 - name: metrics` - -const serviceMonitorYamlExp = `apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: app-operator - labels: - name: app-operator -spec: - selector: - matchLabels: - name: app-operator - endpoints: - - port: metrics` - func TestGenDeploy(t *testing.T) { buf := &bytes.Buffer{} if err := renderCRDYaml(buf, appKind, appAPIVersion); err != nil { @@ -152,20 +126,4 @@ func TestGenDeploy(t *testing.T) { if rbacYamlExp != buf.String() { t.Errorf(errorMessage, rbacYamlExp, buf.String()) } - - buf = &bytes.Buffer{} - if err := renderServiceYaml(buf, appProjectName); err != nil { - t.Error(err) - } - if serviceYamlExp != buf.String() { - t.Errorf("want %v, got %v", serviceYamlExp, buf.String()) - } - - buf = &bytes.Buffer{} - if err := renderServiceMonitorYaml(buf, appProjectName); err != nil { - t.Error(err) - } - if serviceMonitorYamlExp != buf.String() { - t.Errorf("want %v, got %v", serviceMonitorYamlExp, buf.String()) - } } diff --git a/pkg/generator/gen_main.go b/pkg/generator/gen_main.go new file mode 100644 index 0000000000..455e85d3d1 --- /dev/null +++ b/pkg/generator/gen_main.go @@ -0,0 +1,64 @@ +// Copyright 2018 The Operator-SDK 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 generator + +import ( + "io" + "path/filepath" + "text/template" + + "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" +) + +const ( + // sdkImport is the operator-sdk import path. + sdkImport = "github.com/operator-framework/operator-sdk/pkg/sdk" + k8sutilImport = "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" + versionImport = "github.com/operator-framework/operator-sdk/version" +) + +// Main contains all the customized data needed to generate cmd//main.go for a new operator +// when pairing with mainTmpl template. +type Main struct { + // imports + OperatorSDKImport string + StubImport string + K8sutilImport string + SDKVersionImport string + + APIVersion string + Kind string + MetricsPort string +} + +// renderMainFile generates the cmd//main.go file. +func renderMainFile(w io.Writer, repo, apiVersion, kind string) error { + t := template.New("cmd//main.go") + t, err := t.Parse(mainTmpl) + if err != nil { + return err + } + + m := Main{ + OperatorSDKImport: sdkImport, + StubImport: filepath.Join(repo, stubDir), + K8sutilImport: k8sutilImport, + SDKVersionImport: versionImport, + APIVersion: apiVersion, + Kind: kind, + MetricsPort: k8sutil.GetPrometheusMetricsPort(), + } + return t.Execute(w, m) +} diff --git a/pkg/generator/gen_main_test.go b/pkg/generator/gen_main_test.go index 55650bd9ed..501714e4ec 100644 --- a/pkg/generator/gen_main_test.go +++ b/pkg/generator/gen_main_test.go @@ -22,46 +22,57 @@ import ( const mainExp = `package main import ( - "context" - "runtime" - "net/http" + "context" + "runtime" + "net/http" - stub "github.com/example-inc/app-operator/pkg/stub" - sdk "github.com/operator-framework/operator-sdk/pkg/sdk" - k8sutil "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" - sdkVersion "github.com/operator-framework/operator-sdk/version" + stub "github.com/example-inc/app-operator/pkg/stub" + sdk "github.com/operator-framework/operator-sdk/pkg/sdk" + k8sutil "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" + sdkVersion "github.com/operator-framework/operator-sdk/version" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/sirupsen/logrus" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/sirupsen/logrus" ) -// Prometheus metrics port -const promPort = ":9090" - func printVersion() { - logrus.Infof("Go Version: %s", runtime.Version()) - logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) - logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) - logrus.Infof("operator prometheus port :%s", promPort) + logrus.Infof("Go Version: %s", runtime.Version()) + logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) + logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) + logrus.Infof("operator prometheus port %s", ":60000") +} + +func initOperatorService() { + service, err := k8sutil.InitOperatorService() + if err != nil { + logrus.Fatalf("Failed to init operator service: %v", err) + } + err = sdk.Create(service) + if err != nil { + logrus.Infof("Failed to create operator service: %v", err) + return + } + logrus.Infof("Service %s have been created", service.Name) } func main() { - printVersion() + printVersion() + initOperatorService() - http.Handle("/metrics", promhttp.Handler()) - logrus.Fatalf("%s", http.ListenAndServe(promPort, nil)) + http.Handle("/metrics", promhttp.Handler()) + go http.ListenAndServe(":60000", nil) - resource := "app.example.com/v1alpha1" - kind := "AppService" - namespace, err := k8sutil.GetWatchNamespace() - if err != nil { - logrus.Fatalf("Failed to get watch namespace: %v", err) - } - resyncPeriod := 5 - logrus.Infof("Watching %s, %s, %s, %d", resource, kind, namespace, resyncPeriod) - sdk.Watch(resource, kind, namespace, resyncPeriod) - sdk.Handle(stub.NewHandler()) - sdk.Run(context.TODO()) + resource := "app.example.com/v1alpha1" + kind := "AppService" + namespace, err := k8sutil.GetWatchNamespace() + if err != nil { + logrus.Fatalf("Failed to get watch namespace: %v", err) + } + resyncPeriod := 5 + logrus.Infof("Watching %s, %s, %s, %d", resource, kind, namespace, resyncPeriod) + sdk.Watch(resource, kind, namespace, resyncPeriod) + sdk.Handle(stub.NewHandler()) + sdk.Run(context.TODO()) } ` diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index d601a76c9d..4bd9aaa63e 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -57,8 +57,6 @@ const ( gopkglock = "Gopkg.lock" config = "config.yaml" operatorYaml = deployDir + "/operator.yaml" - serviceYaml = "service.yaml" - serviceMonitorYaml = "serviceMonitor.yaml" rbacYaml = "rbac.yaml" crYaml = "cr.yaml" catalogPackageYaml = "package.yaml" diff --git a/pkg/generator/templates.go b/pkg/generator/templates.go index 8a4dbfd256..1ac4fe643e 100644 --- a/pkg/generator/templates.go +++ b/pkg/generator/templates.go @@ -130,45 +130,57 @@ spec: const mainTmpl = `package main import ( - "context" - "runtime" + "context" + "runtime" + "net/http" - stub "{{.StubImport}}" - sdk "{{.OperatorSDKImport}}" - k8sutil "{{.K8sutilImport}}" + stub "{{.StubImport}}" + sdk "{{.OperatorSDKImport}}" + k8sutil "{{.K8sutilImport}}" sdkVersion "{{.SDKVersionImport}}" - + "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus" ) -// Prometheus metrics port -const promPort = ":9090" - func printVersion() { - logrus.Infof("Go Version: %s", runtime.Version()) - logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) + logrus.Infof("Go Version: %s", runtime.Version()) + logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) - logrus.Infof("operator prometheus port :%s", promPort) + logrus.Infof("operator prometheus port %s", "{{.MetricsPort}}") +} + +func initOperatorService() { + service, err := k8sutil.InitOperatorService() + if err != nil { + logrus.Fatalf("Failed to init operator service: %v", err) + } + err = sdk.Create(service) + if err != nil { + logrus.Infof("Failed to create operator service: %v", err) + return + } + logrus.Infof("Service %s have been created", service.Name) } func main() { - printVersion() + printVersion() + initOperatorService() http.Handle("/metrics", promhttp.Handler()) - logrus.Fatalf("%s", http.ListenAndServe(promPort, nil)) - - resource := "{{.APIVersion}}" - kind := "{{.Kind}}" - namespace, err := k8sutil.GetWatchNamespace() - if err != nil { - logrus.Fatalf("Failed to get watch namespace: %v", err) - } - resyncPeriod := 5 - logrus.Infof("Watching %s, %s, %s, %d", resource, kind, namespace, resyncPeriod) - sdk.Watch(resource, kind, namespace, resyncPeriod) - sdk.Handle(stub.NewHandler()) - sdk.Run(context.TODO()) + go http.ListenAndServe("{{.MetricsPort}}", nil) + + resource := "{{.APIVersion}}" + kind := "{{.Kind}}" + namespace, err := k8sutil.GetWatchNamespace() + if err != nil { + logrus.Fatalf("Failed to get watch namespace: %v", err) + } + resyncPeriod := 5 + logrus.Infof("Watching %s, %s, %s, %d", resource, kind, namespace, resyncPeriod) + sdk.Watch(resource, kind, namespace, resyncPeriod) + sdk.Handle(stub.NewHandler()) + sdk.Run(context.TODO()) } ` @@ -524,6 +536,8 @@ const operatorYamlTmpl = `apiVersion: apps/v1 kind: Deployment metadata: name: {{.ProjectName}} + labels: + name: {{.ProjectName}} spec: replicas: 1 selector: @@ -537,14 +551,19 @@ spec: containers: - name: {{.ProjectName}} image: {{.Image}} + ports: + - containerPort: {{.MetricsPort}} + name: metrics command: - {{.ProjectName}} imagePullPolicy: Always env: - - name: WATCH_NAMESPACE + - name: {{.NamespaceEnv}} valueFrom: fieldRef: fieldPath: metadata.namespace + - name: {{.NameEnv}} + value: "{{.ProjectName}}" ` const rbacYamlTmpl = `kind: Role diff --git a/pkg/util/k8sutil/constants.go b/pkg/util/k8sutil/constants.go index fd67036cca..bc56cc77bf 100644 --- a/pkg/util/k8sutil/constants.go +++ b/pkg/util/k8sutil/constants.go @@ -8,4 +8,11 @@ const ( // WatchNamespaceEnvVar is the constant for env variable WATCH_NAMESPACE // which is the namespace that the pod is currently running in. WatchNamespaceEnvVar = "WATCH_NAMESPACE" + + // OperatorName is the constant for env variable OPERATOR_NAME + // wich is the name of the current operator + OperatorNameEnvVar = "OPERATOR_NAME" + + // PrometheusMetricsPort defines the port which expose prometheus metrics + PrometheusMetricsPort = 60000 ) diff --git a/pkg/util/k8sutil/k8sutil.go b/pkg/util/k8sutil/k8sutil.go index f317f67bb5..02a584a56d 100644 --- a/pkg/util/k8sutil/k8sutil.go +++ b/pkg/util/k8sutil/k8sutil.go @@ -18,13 +18,16 @@ import ( "encoding/json" "fmt" "os" + "strconv" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" + intstr "k8s.io/apimachinery/pkg/util/intstr" cgoscheme "k8s.io/client-go/kubernetes/scheme" ) @@ -147,3 +150,58 @@ func GetWatchNamespace() (string, error) { } return ns, nil } + +// GetOperatorName return the operator name +func GetOperatorName() (string, error) { + operatorName, found := os.LookupEnv(OperatorNameEnvVar) + if !found { + return "", fmt.Errorf("%s must be set", OperatorNameEnvVar) + } + if len(operatorName) == 0 { + return "", fmt.Errorf("%s must not be empty", OperatorNameEnvVar) + } + return operatorName, nil +} + +// InitOperatorService return the static service which expose operator metrics +func InitOperatorService() (*v1.Service, error) { + operatorName, err := GetOperatorName() + if err != nil { + return nil, err + } + namespace, err := GetWatchNamespace() + if err != nil { + return nil, err + } + service := &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: operatorName, + Namespace: namespace, + Labels: map[string]string{"name": operatorName}, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "Service", + APIVersion: "v1", + }, + Spec: v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Port: PrometheusMetricsPort, + Protocol: v1.ProtocolTCP, + TargetPort: intstr.IntOrString{ + Type: intstr.String, + StrVal: "metrics", + }, + Name: "metrics", + }, + }, + Selector: map[string]string{"name": operatorName}, + }, + } + return service, nil +} + +// GetPrometheusMetricsPort convert constant to string +func GetPrometheusMetricsPort() string { + return ":" + strconv.Itoa(PrometheusMetricsPort) +} diff --git a/pkg/util/k8sutil/k8sutil_test.go b/pkg/util/k8sutil/k8sutil_test.go new file mode 100644 index 0000000000..0e5c257874 --- /dev/null +++ b/pkg/util/k8sutil/k8sutil_test.go @@ -0,0 +1,61 @@ +package k8sutil + +import ( + "fmt" + "os" + "reflect" + "testing" +) + +func TestGetOperatorName(t *testing.T) { + type Output struct { + operatorName string + err error + } + + type Scenario struct { + name string + envVarKey string + envVarValue string + expectedOutput Output + } + + tests := []Scenario{ + Scenario{ + name: "Simple case", + envVarKey: OperatorNameEnvVar, + envVarValue: "myoperator", + expectedOutput: Output{ + operatorName: "myoperator", + err: nil, + }, + }, + Scenario{ + name: "Unset env var", + envVarKey: "", + envVarValue: "", + expectedOutput: Output{ + operatorName: "", + err: fmt.Errorf("%s must be set", OperatorNameEnvVar), + }, + }, + Scenario{ + name: "Empty env var", + envVarKey: OperatorNameEnvVar, + envVarValue: "", + expectedOutput: Output{ + operatorName: "", + err: fmt.Errorf("%s must not be empty", OperatorNameEnvVar), + }, + }, + } + + for _, test := range tests { + _ = os.Setenv(test.envVarKey, test.envVarValue) + operatorName, err := GetOperatorName() + if !(operatorName == test.expectedOutput.operatorName && reflect.DeepEqual(err, test.expectedOutput.err)) { + t.Errorf("test %s failed, expected ouput: %s,%v; got: %s,%v", test.name, test.expectedOutput.operatorName, test.expectedOutput.err, operatorName, err) + } + _ = os.Unsetenv(test.envVarKey) + } +} From 083f4329c810f000266f31867c48fac43190d1d6 Mon Sep 17 00:00:00 2001 From: Etienne Coutaud Date: Fri, 15 Jun 2018 15:02:06 +0200 Subject: [PATCH 21/21] pkg/generator update after refactor --- Gopkg.toml | 4 - pkg/generator/gen_deploy.go | 129 ------------------------------- pkg/generator/gen_deploy_test.go | 129 ------------------------------- pkg/generator/gen_main.go | 64 --------------- pkg/generator/gen_main_test.go | 89 --------------------- pkg/generator/generator.go | 12 ++- pkg/generator/templates.go | 34 ++++---- pkg/util/k8sutil/constants.go | 3 + pkg/util/k8sutil/k8sutil.go | 10 +-- 9 files changed, 34 insertions(+), 440 deletions(-) delete mode 100644 pkg/generator/gen_deploy.go delete mode 100644 pkg/generator/gen_deploy_test.go delete mode 100644 pkg/generator/gen_main.go delete mode 100644 pkg/generator/gen_main_test.go diff --git a/Gopkg.toml b/Gopkg.toml index 492b98e2b4..5a72d67e2e 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -6,10 +6,6 @@ name = "github.com/spf13/cobra" version = "0.0.2" -[[override]] - name = "github.com/prometheus/client_golang" - version = "0.8.0" - [[override]] name = "k8s.io/api" version = "kubernetes-1.9.3" diff --git a/pkg/generator/gen_deploy.go b/pkg/generator/gen_deploy.go deleted file mode 100644 index 131147c1eb..0000000000 --- a/pkg/generator/gen_deploy.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "fmt" - "io" - "strings" - "text/template" - - "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" -) - -const ( - crdTmplName = "deploy/crd.yaml" - operatorTmplName = "deploy/operator.yaml" - rbacTmplName = "deploy/rbac.yaml" - crTmplName = "deploy/cr.yaml" -) - -// CRDYaml contains data needed to generate deploy/crd.yaml -type CRDYaml struct { - Kind string - KindSingular string - KindPlural string - GroupName string - Version string -} - -// renderCRDYaml generates deploy/crd.yaml -func renderCRDYaml(w io.Writer, kind, apiVersion string) error { - t := template.New(crdTmplName) - t, err := t.Parse(crdYamlTmpl) - if err != nil { - return fmt.Errorf("failed to parse crd yaml template: %v", err) - } - - ks := strings.ToLower(kind) - o := CRDYaml{ - Kind: kind, - KindSingular: ks, - KindPlural: toPlural(ks), - GroupName: groupName(apiVersion), - Version: version(apiVersion), - } - return t.Execute(w, o) -} - -// OperatorYaml contains data needed to generate deploy/operator.yaml -type OperatorYaml struct { - ProjectName string - Image string - NameEnv string - NamespaceEnv string - MetricsPort int -} - -// renderOperatorYaml generates deploy/operator.yaml. -func renderOperatorYaml(w io.Writer, projectName, image string) error { - t := template.New(operatorTmplName) - t, err := t.Parse(operatorYamlTmpl) - if err != nil { - return fmt.Errorf("failed to parse operator yaml template: %v", err) - } - - o := OperatorYaml{ - ProjectName: projectName, - Image: image, - NameEnv: k8sutil.OperatorNameEnvVar, - NamespaceEnv: k8sutil.WatchNamespaceEnvVar, - MetricsPort: k8sutil.PrometheusMetricsPort, - } - return t.Execute(w, o) -} - -// RBACYaml contains all the customized data needed to generate deploy/rbac.yaml for a new operator -// when pairing with rbacYamlTmpl template. -type RBACYaml struct { - ProjectName string - GroupName string -} - -// renderRBACYaml generates deploy/rbac.yaml. -func renderRBACYaml(w io.Writer, projectName, groupName string) error { - t := template.New(rbacTmplName) - t, err := t.Parse(rbacYamlTmpl) - if err != nil { - return fmt.Errorf("failed to parse rbac yaml template: %v", err) - } - - r := RBACYaml{ - ProjectName: projectName, - GroupName: groupName, - } - return t.Execute(w, r) -} - -// CRYaml contains all the customized data needed to generate deploy/cr.yaml. -type CRYaml struct { - APIVersion string - Kind string - Name string -} - -func renderCustomResourceYaml(w io.Writer, apiVersion, kind string) error { - t := template.New(crTmplName) - t, err := t.Parse(crYamlTmpl) - if err != nil { - return fmt.Errorf("failed to parse cr yaml template: %v", err) - } - - r := CRYaml{ - APIVersion: apiVersion, - Kind: kind, - } - return t.Execute(w, r) -} diff --git a/pkg/generator/gen_deploy_test.go b/pkg/generator/gen_deploy_test.go deleted file mode 100644 index b2f5df2186..0000000000 --- a/pkg/generator/gen_deploy_test.go +++ /dev/null @@ -1,129 +0,0 @@ -package generator - -import ( - "bytes" - "testing" -) - -const crdYamlExp = `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 -` - -const operatorYamlExp = `apiVersion: apps/v1 -kind: Deployment -metadata: - name: app-operator - labels: - name: app-operator -spec: - replicas: 1 - selector: - matchLabels: - name: app-operator - template: - metadata: - labels: - name: app-operator - spec: - containers: - - name: app-operator - image: quay.io/example-inc/app-operator:0.0.1 - ports: - - containerPort: 60000 - name: metrics - command: - - app-operator - imagePullPolicy: Always - env: - - name: WATCH_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: OPERATOR_NAME - value: "app-operator" -` - -const rbacYamlExp = `kind: Role -apiVersion: rbac.authorization.k8s.io/v1beta1 -metadata: - name: app-operator -rules: -- apiGroups: - - app.example.com - resources: - - "*" - verbs: - - "*" -- apiGroups: - - "" - resources: - - pods - - services - - endpoints - - persistentvolumeclaims - - events - - configmaps - - secrets - verbs: - - "*" -- apiGroups: - - apps - resources: - - deployments - - daemonsets - - replicasets - - statefulsets - verbs: - - "*" - ---- - -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1beta1 -metadata: - name: default-account-app-operator -subjects: -- kind: ServiceAccount - name: default -roleRef: - kind: Role - name: app-operator - apiGroup: rbac.authorization.k8s.io -` - -func TestGenDeploy(t *testing.T) { - buf := &bytes.Buffer{} - if err := renderCRDYaml(buf, appKind, appAPIVersion); err != nil { - t.Error(err) - } - if crdYamlExp != buf.String() { - t.Errorf(errorMessage, crdYamlExp, buf.String()) - } - - buf = &bytes.Buffer{} - if err := renderOperatorYaml(buf, appProjectName, appImage); err != nil { - t.Error(err) - } - if operatorYamlExp != buf.String() { - t.Errorf(errorMessage, operatorYamlExp, buf.String()) - } - - buf = &bytes.Buffer{} - if err := renderRBACYaml(buf, appProjectName, appGroupName); err != nil { - t.Error(err) - } - if rbacYamlExp != buf.String() { - t.Errorf(errorMessage, rbacYamlExp, buf.String()) - } -} diff --git a/pkg/generator/gen_main.go b/pkg/generator/gen_main.go deleted file mode 100644 index 455e85d3d1..0000000000 --- a/pkg/generator/gen_main.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "io" - "path/filepath" - "text/template" - - "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" -) - -const ( - // sdkImport is the operator-sdk import path. - sdkImport = "github.com/operator-framework/operator-sdk/pkg/sdk" - k8sutilImport = "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" - versionImport = "github.com/operator-framework/operator-sdk/version" -) - -// Main contains all the customized data needed to generate cmd//main.go for a new operator -// when pairing with mainTmpl template. -type Main struct { - // imports - OperatorSDKImport string - StubImport string - K8sutilImport string - SDKVersionImport string - - APIVersion string - Kind string - MetricsPort string -} - -// renderMainFile generates the cmd//main.go file. -func renderMainFile(w io.Writer, repo, apiVersion, kind string) error { - t := template.New("cmd//main.go") - t, err := t.Parse(mainTmpl) - if err != nil { - return err - } - - m := Main{ - OperatorSDKImport: sdkImport, - StubImport: filepath.Join(repo, stubDir), - K8sutilImport: k8sutilImport, - SDKVersionImport: versionImport, - APIVersion: apiVersion, - Kind: kind, - MetricsPort: k8sutil.GetPrometheusMetricsPort(), - } - return t.Execute(w, m) -} diff --git a/pkg/generator/gen_main_test.go b/pkg/generator/gen_main_test.go deleted file mode 100644 index 501714e4ec..0000000000 --- a/pkg/generator/gen_main_test.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2018 The Operator-SDK 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 generator - -import ( - "bytes" - "testing" -) - -const mainExp = `package main - -import ( - "context" - "runtime" - "net/http" - - stub "github.com/example-inc/app-operator/pkg/stub" - sdk "github.com/operator-framework/operator-sdk/pkg/sdk" - k8sutil "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" - sdkVersion "github.com/operator-framework/operator-sdk/version" - - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/sirupsen/logrus" -) - -func printVersion() { - logrus.Infof("Go Version: %s", runtime.Version()) - logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) - logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) - logrus.Infof("operator prometheus port %s", ":60000") -} - -func initOperatorService() { - service, err := k8sutil.InitOperatorService() - if err != nil { - logrus.Fatalf("Failed to init operator service: %v", err) - } - err = sdk.Create(service) - if err != nil { - logrus.Infof("Failed to create operator service: %v", err) - return - } - logrus.Infof("Service %s have been created", service.Name) -} - -func main() { - printVersion() - initOperatorService() - - http.Handle("/metrics", promhttp.Handler()) - go http.ListenAndServe(":60000", nil) - - resource := "app.example.com/v1alpha1" - kind := "AppService" - namespace, err := k8sutil.GetWatchNamespace() - if err != nil { - logrus.Fatalf("Failed to get watch namespace: %v", err) - } - resyncPeriod := 5 - logrus.Infof("Watching %s, %s, %s, %d", resource, kind, namespace, resyncPeriod) - sdk.Watch(resource, kind, namespace, resyncPeriod) - sdk.Handle(stub.NewHandler()) - sdk.Run(context.TODO()) -} -` - -func TestGenMain(t *testing.T) { - buf := &bytes.Buffer{} - if err := renderMainFile(buf, appRepoPath, appAPIVersion, appKind); err != nil { - t.Error(err) - return - } - - if mainExp != buf.String() { - t.Errorf(errorMessage, mainExp, buf.String()) - } -} diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go index 4bd9aaa63e..1e529f8e68 100644 --- a/pkg/generator/generator.go +++ b/pkg/generator/generator.go @@ -23,6 +23,8 @@ import ( "path/filepath" "strings" "text/template" + + k8sutil "github.com/operator-framework/operator-sdk/pkg/util/k8sutil" ) const ( @@ -183,6 +185,7 @@ func renderCmdFiles(cmdProjectDir, repoPath, apiVersion, kind string) error { SDKVersionImport: versionImport, APIVersion: apiVersion, Kind: kind, + MetricsPort: k8sutil.PrometheusMetricsPort, } return renderWriteFile(filepath.Join(cmdProjectDir, main), "cmd//main.go", mainTmpl, td) @@ -245,8 +248,10 @@ func renderDeployFiles(deployDir, projectName, apiVersion, kind string) error { // RenderOperatorYaml generates "deploy/operator.yaml" func RenderOperatorYaml(c *Config, image string) error { td := tmplData{ - ProjectName: c.ProjectName, - Image: image, + ProjectName: c.ProjectName, + Image: image, + MetricsPort: k8sutil.PrometheusMetricsPort, + MetricsPortName: k8sutil.PrometheusMetricsPortName, } return renderWriteFile(operatorYaml, operatorTmplName, operatorYamlTmpl, td) } @@ -436,6 +441,9 @@ type tmplData struct { K8sutilImport string SDKVersionImport string + MetricsPort int + MetricsPortName string + APIVersion string Kind string diff --git a/pkg/generator/templates.go b/pkg/generator/templates.go index 1ac4fe643e..dba844c379 100644 --- a/pkg/generator/templates.go +++ b/pkg/generator/templates.go @@ -130,24 +130,24 @@ spec: const mainTmpl = `package main import ( - "context" - "runtime" - "net/http" + "context" + "runtime" + "net/http" - stub "{{.StubImport}}" - sdk "{{.OperatorSDKImport}}" - k8sutil "{{.K8sutilImport}}" - sdkVersion "{{.SDKVersionImport}}" + stub "{{.StubImport}}" + sdk "{{.OperatorSDKImport}}" + k8sutil "{{.K8sutilImport}}" + sdkVersion "{{.SDKVersionImport}}" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/sirupsen/logrus" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/sirupsen/logrus" ) func printVersion() { logrus.Infof("Go Version: %s", runtime.Version()) logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) - logrus.Infof("operator prometheus port %s", "{{.MetricsPort}}") + logrus.Infof("operator prometheus port %d", {{.MetricsPort}}) } func initOperatorService() { @@ -156,11 +156,11 @@ func initOperatorService() { logrus.Fatalf("Failed to init operator service: %v", err) } err = sdk.Create(service) - if err != nil { + if err != nil && !errors.IsAlreadyExists(err) { logrus.Infof("Failed to create operator service: %v", err) return } - logrus.Infof("Service %s have been created", service.Name) + logrus.Infof("Metrics service %s created", service.Name) } func main() { @@ -168,7 +168,7 @@ func main() { initOperatorService() http.Handle("/metrics", promhttp.Handler()) - go http.ListenAndServe("{{.MetricsPort}}", nil) + go http.ListenAndServe(":{{.MetricsPort}}", nil) resource := "{{.APIVersion}}" kind := "{{.Kind}}" @@ -399,7 +399,11 @@ const gopkgTomlTmpl = `[[override]] [[override]] name = "k8s.io/client-go" - version = "kubernetes-1.9.3" + version = "kubernetes-1.9.3" + +[[override]] + name = "github.com/prometheus/client_golang" + version = "0.8.0" [[constraint]] name = "github.com/operator-framework/operator-sdk" @@ -553,7 +557,7 @@ spec: image: {{.Image}} ports: - containerPort: {{.MetricsPort}} - name: metrics + name: {{.MetricsPortName}} command: - {{.ProjectName}} imagePullPolicy: Always diff --git a/pkg/util/k8sutil/constants.go b/pkg/util/k8sutil/constants.go index bc56cc77bf..f447c5344d 100644 --- a/pkg/util/k8sutil/constants.go +++ b/pkg/util/k8sutil/constants.go @@ -15,4 +15,7 @@ const ( // PrometheusMetricsPort defines the port which expose prometheus metrics PrometheusMetricsPort = 60000 + + // PrometheusMetricsPortName define the port name used in kubernetes deployment and service + PrometheusMetricsPortName = "metrics" ) diff --git a/pkg/util/k8sutil/k8sutil.go b/pkg/util/k8sutil/k8sutil.go index 02a584a56d..ae8eb143f5 100644 --- a/pkg/util/k8sutil/k8sutil.go +++ b/pkg/util/k8sutil/k8sutil.go @@ -18,7 +18,6 @@ import ( "encoding/json" "fmt" "os" - "strconv" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" @@ -190,9 +189,9 @@ func InitOperatorService() (*v1.Service, error) { Protocol: v1.ProtocolTCP, TargetPort: intstr.IntOrString{ Type: intstr.String, - StrVal: "metrics", + StrVal: PrometheusMetricsPortName, }, - Name: "metrics", + Name: PrometheusMetricsPortName, }, }, Selector: map[string]string{"name": operatorName}, @@ -200,8 +199,3 @@ func InitOperatorService() (*v1.Service, error) { } return service, nil } - -// GetPrometheusMetricsPort convert constant to string -func GetPrometheusMetricsPort() string { - return ":" + strconv.Itoa(PrometheusMetricsPort) -}