From 9dd86f0c8be0f3841678bcb281408230ec84e251 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Thu, 10 Jan 2019 00:03:31 -0500 Subject: [PATCH 1/4] [travis deploy] commands,pkg/scaffold,hack,pkg/helm: run and migrate command support for helm --- Makefile | 2 +- commands/operator-sdk/cmd/migrate.go | 50 +++++-- commands/operator-sdk/cmd/run.go | 1 + commands/operator-sdk/cmd/run/ansible.go | 3 +- commands/operator-sdk/cmd/run/helm.go | 37 +++++ commands/operator-sdk/cmd/up/local.go | 56 +------- doc/dev/testing/travis-build.md | 22 +-- .../{ => ansible}/scaffold-ansible-image.go | 0 hack/image/build-ansible-image.sh | 2 +- hack/image/build-helm-image.sh | 17 ++- hack/image/helm/scaffold-helm-image.go | 45 ++++++ hack/tests/e2e-helm.sh | 133 +++++++++++------- .../helm-operator/main.go => pkg/helm/run.go | 28 ++-- pkg/scaffold/helm/dockerfilehybrid.go | 64 +++++++++ pkg/scaffold/helm/entrypoint.go | 49 +++++++ pkg/scaffold/helm/gopkgtoml.go | 44 ++++++ pkg/scaffold/helm/main.go | 51 +++++++ pkg/scaffold/helm/usersetup.go | 50 +++++++ release.sh | 6 + test/helm-operator/Dockerfile | 16 --- test/helm-operator/README.md | 2 - test/helm-operator/bin/entrypoint | 13 -- test/helm-operator/bin/user_setup | 13 -- 23 files changed, 520 insertions(+), 184 deletions(-) create mode 100644 commands/operator-sdk/cmd/run/helm.go rename hack/image/{ => ansible}/scaffold-ansible-image.go (100%) create mode 100644 hack/image/helm/scaffold-helm-image.go rename test/helm-operator/cmd/helm-operator/main.go => pkg/helm/run.go (84%) create mode 100644 pkg/scaffold/helm/dockerfilehybrid.go create mode 100644 pkg/scaffold/helm/entrypoint.go create mode 100644 pkg/scaffold/helm/gopkgtoml.go create mode 100644 pkg/scaffold/helm/main.go create mode 100644 pkg/scaffold/helm/usersetup.go delete mode 100644 test/helm-operator/Dockerfile delete mode 100644 test/helm-operator/README.md delete mode 100755 test/helm-operator/bin/entrypoint delete mode 100755 test/helm-operator/bin/user_setup diff --git a/Makefile b/Makefile index 6b53198fa78..f7da20fe21b 100644 --- a/Makefile +++ b/Makefile @@ -108,7 +108,7 @@ image/build: image/build/ansible image/build/helm image/build/ansible: build/operator-sdk-dev-x86_64-linux-gnu ./hack/image/build-ansible-image.sh $(ANSIBLE_BASE_IMAGE):dev -image/build/helm: +image/build/helm: build/operator-sdk-dev-x86_64-linux-gnu ./hack/image/build-helm-image.sh $(HELM_BASE_IMAGE):dev image/push: image/push/ansible image/push/helm diff --git a/commands/operator-sdk/cmd/migrate.go b/commands/operator-sdk/cmd/migrate.go index 1bfabd59c8c..61c767882ee 100644 --- a/commands/operator-sdk/cmd/migrate.go +++ b/commands/operator-sdk/cmd/migrate.go @@ -22,6 +22,7 @@ import ( "github.com/operator-framework/operator-sdk/internal/util/projutil" "github.com/operator-framework/operator-sdk/pkg/scaffold" "github.com/operator-framework/operator-sdk/pkg/scaffold/ansible" + "github.com/operator-framework/operator-sdk/pkg/scaffold/helm" "github.com/operator-framework/operator-sdk/pkg/scaffold/input" "github.com/spf13/cobra" @@ -48,6 +49,8 @@ func migrateRun(cmd *cobra.Command, args []string) { switch opType { case projutil.OperatorTypeAnsible: migrateAnsible() + case projutil.OperatorTypeHelm: + migrateHelm() default: log.Fatalf("operator of type %s cannot be migrated.", opType) } @@ -76,14 +79,7 @@ func migrateAnsible() { log.Fatalf("error trying to stat playbook.yaml: (%v)", err) } - dockerfilePath := filepath.Join(scaffold.BuildDir, scaffold.DockerfileFile) - newDockerfilePath := dockerfilePath + ".sdkold" - err = os.Rename(dockerfilePath, newDockerfilePath) - if err != nil { - log.Fatalf("failed to rename Dockerfile: (%v)", err) - } - log.Printf("renamed Dockerfile to %s and replaced with newer version", newDockerfilePath) - log.Print("Compare the new Dockerfile to your old one and manually migrate any customizations") + renameDockerfile() s := &scaffold.Scaffold{} err = s.Execute(cfg, @@ -97,3 +93,41 @@ func migrateAnsible() { log.Fatalf("add scaffold failed: (%v)", err) } } + +// migrateHelm runs the migration process for a helm-based operator +func migrateHelm() { + wd := projutil.MustGetwd() + + cfg := &input.Config{ + AbsProjectPath: wd, + ProjectName: filepath.Base(wd), + } + + renameDockerfile() + + s := &scaffold.Scaffold{} + err := s.Execute(cfg, + &helm.Main{}, + &helm.GopkgToml{}, + &helm.DockerfileHybrid{ + Watches: true, + HelmCharts: true, + }, + &helm.Entrypoint{}, + &helm.UserSetup{}, + ) + if err != nil { + log.Fatalf("add scaffold failed: (%v)", err) + } +} + +func renameDockerfile() { + dockerfilePath := filepath.Join(scaffold.BuildDir, scaffold.DockerfileFile) + newDockerfilePath := dockerfilePath + ".sdkold" + err := os.Rename(dockerfilePath, newDockerfilePath) + if err != nil { + log.Fatalf("failed to rename Dockerfile: (%v)", err) + } + log.Printf("renamed Dockerfile to %s and replaced with newer version", newDockerfilePath) + log.Print("Compare the new Dockerfile to your old one and manually migrate any customizations") +} diff --git a/commands/operator-sdk/cmd/run.go b/commands/operator-sdk/cmd/run.go index bbbcfbd50fa..6d368aa6ce7 100644 --- a/commands/operator-sdk/cmd/run.go +++ b/commands/operator-sdk/cmd/run.go @@ -29,5 +29,6 @@ func NewRunCmd() *cobra.Command { } runCmd.AddCommand(run.NewAnsibleCmd()) + runCmd.AddCommand(run.NewHelmCmd()) return runCmd } diff --git a/commands/operator-sdk/cmd/run/ansible.go b/commands/operator-sdk/cmd/run/ansible.go index 90889b9f4ca..2542af008e9 100644 --- a/commands/operator-sdk/cmd/run/ansible.go +++ b/commands/operator-sdk/cmd/run/ansible.go @@ -21,10 +21,9 @@ import ( "github.com/spf13/cobra" ) -var flags *aoflags.AnsibleOperatorFlags - // NewAnsibleCmd returns a command that will run an ansible operator func NewAnsibleCmd() *cobra.Command { + var flags *aoflags.AnsibleOperatorFlags newCmd := &cobra.Command{ Use: "ansible", Short: "Runs as an ansible operator", diff --git a/commands/operator-sdk/cmd/run/helm.go b/commands/operator-sdk/cmd/run/helm.go new file mode 100644 index 00000000000..c924b0c720e --- /dev/null +++ b/commands/operator-sdk/cmd/run/helm.go @@ -0,0 +1,37 @@ +// Copyright 2019 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 run + +import ( + "github.com/operator-framework/operator-sdk/pkg/helm" + hoflags "github.com/operator-framework/operator-sdk/pkg/helm/flags" + + "github.com/spf13/cobra" +) + +// NewHelmCmd returns a command that will run a helm operator +func NewHelmCmd() *cobra.Command { + var flags *hoflags.HelmOperatorFlags + newCmd := &cobra.Command{ + Use: "helm", + Short: "Runs as a Helm operator", + Run: func(cmd *cobra.Command, args []string) { + helm.Run(flags) + }, + } + flags = hoflags.AddTo(newCmd.Flags()) + + return newCmd +} diff --git a/commands/operator-sdk/cmd/up/local.go b/commands/operator-sdk/cmd/up/local.go index 930a0a8972d..8b5fbdbe0db 100644 --- a/commands/operator-sdk/cmd/up/local.go +++ b/commands/operator-sdk/cmd/up/local.go @@ -25,26 +25,17 @@ import ( "strings" "syscall" - "sigs.k8s.io/controller-runtime/pkg/runtime/signals" - "github.com/operator-framework/operator-sdk/internal/util/projutil" "github.com/operator-framework/operator-sdk/pkg/ansible" aoflags "github.com/operator-framework/operator-sdk/pkg/ansible/flags" - "github.com/operator-framework/operator-sdk/pkg/helm/client" - "github.com/operator-framework/operator-sdk/pkg/helm/controller" + "github.com/operator-framework/operator-sdk/pkg/helm" hoflags "github.com/operator-framework/operator-sdk/pkg/helm/flags" - "github.com/operator-framework/operator-sdk/pkg/helm/release" "github.com/operator-framework/operator-sdk/pkg/k8sutil" "github.com/operator-framework/operator-sdk/pkg/scaffold" sdkVersion "github.com/operator-framework/operator-sdk/version" - "k8s.io/helm/pkg/storage" - "k8s.io/helm/pkg/storage/driver" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "sigs.k8s.io/controller-runtime/pkg/client/config" - "sigs.k8s.io/controller-runtime/pkg/manager" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" ) // NewLocalCmd - up local command to run an operator loccally @@ -172,49 +163,14 @@ func upLocalHelm() { log.Fatalf("failed to set %s environment variable: (%v)", k8sutil.KubeConfigEnvVar, err) } - logf.SetLogger(logf.ZapLogger(false)) - - printVersion() - - cfg, err := config.GetConfig() - if err != nil { - log.Fatal(err) - } - - mgr, err := manager.New(cfg, manager.Options{Namespace: namespace}) - if err != nil { - log.Fatal(err) - } - - // Create Tiller's storage backend and kubernetes client - storageBackend := storage.Init(driver.NewMemory()) - tillerKubeClient, err := client.NewFromManager(mgr) - if err != nil { - log.Fatal(err) - } - - factories, err := release.NewManagerFactoriesFromFile(storageBackend, tillerKubeClient, helmOperatorFlags.WatchesFile) - if err != nil { - log.Fatal(err) - } - - for gvk, factory := range factories { - // Register the controller with the factory. - err := controller.Add(mgr, controller.WatchOptions{ - Namespace: namespace, - GVK: gvk, - ManagerFactory: factory, - ReconcilePeriod: helmOperatorFlags.ReconcilePeriod, - }) - if err != nil { - log.Fatal(err) + // Set the kubeconfig that the manager will be able to grab + if namespace != "" { + if err := os.Setenv(k8sutil.WatchNamespaceEnvVar, namespace); err != nil { + log.Fatalf("failed to set %s environment variable: (%v)", k8sutil.WatchNamespaceEnvVar, err) } } - // Start the Cmd - if err := mgr.Start(signals.SetupSignalHandler()); err != nil { - log.Fatal(err) - } + helm.Run(helmOperatorFlags) } func printVersion() { diff --git a/doc/dev/testing/travis-build.md b/doc/dev/testing/travis-build.md index 4f0acc138d0..445b2b9dc47 100644 --- a/doc/dev/testing/travis-build.md +++ b/doc/dev/testing/travis-build.md @@ -69,7 +69,7 @@ The Go, Ansible, and Helm tests then differ in what tests they run. ### Ansible tests 1. Run [ansible e2e tests][ansible-e2e]. - 1. Create base ansible operator image by running [`hack/image/scaffold-ansible-image.go`][ansible-base]. + 1. Create base ansible operator image by running [`hack/image/ansible/scaffold-ansible-image.go`][ansible-base]. 2. Build base ansible operator image. 3. Create and configure a new ansible type memcached-operator. 4. Create cluster resources. @@ -86,12 +86,16 @@ The Go, Ansible, and Helm tests then differ in what tests they run. ### Helm Tests 1. Run [helm e2e tests][helm-e2e]. - 1. Build base helm operator image from [`test/helm-operator`][helm-base]. - 2. Create and configure a new helm type nginx-operator. - 3. Create cluster resources. - 4. Wait for operator to be ready. - 5. Create nginx CR and wait for it to be ready. - 6. Delete nginx CR and verify that finalizer (which writes a message in the operator logs) ran. + 1. Create base helm operator image by running [`hack/image/helm/scaffold-helm-image.go`][helm-base]. + 2. Build base helm operator image. + 3. Create and configure a new helm type nginx-operator. + 4. Create cluster resources. + 5. Wait for operator to be ready. + 6. Create nginx CR and wait for it to be ready. + 7. Delete nginx CR and verify that finalizer (which writes a message in the operator logs) ran. + 8. Run `operator-sdk migrate` to add go source to the operator. + 9. Run `operator-sdk build` to compile the new binary and build a new image. + 10. Re-run steps 4-7 to test the migrated operator. **NOTE**: All created resources, including the namespace, are deleted using a bash trap when the test finishes @@ -110,8 +114,8 @@ The markdown test does not create a new cluster and runs in a barebones travis V [go-e2e]: ../../../hack/tests/e2e-go.sh [tls-tests]: ../../../test/e2e/tls_util_test.go [ansible-e2e]: ../../../hack/tests/e2e-ansible.sh -[ansible-base]: ../../../hack/image/scaffold-ansible-image.go +[ansible-base]: ../../../hack/image/ansible/scaffold-ansible-image.go [helm-e2e]: ../../../hack/tests/e2e-helm.sh -[helm-base]: ../../../test/helm-operator +[helm-base]: ../../../hack/image/helm/scaffold-helm-image.go [marker-github]: https://github.com/crawford/marker [marker-local]: ../../../hack/ci/marker diff --git a/hack/image/scaffold-ansible-image.go b/hack/image/ansible/scaffold-ansible-image.go similarity index 100% rename from hack/image/scaffold-ansible-image.go rename to hack/image/ansible/scaffold-ansible-image.go diff --git a/hack/image/build-ansible-image.sh b/hack/image/build-ansible-image.sh index 8965c60a8b8..d134245ff46 100755 --- a/hack/image/build-ansible-image.sh +++ b/hack/image/build-ansible-image.sh @@ -12,7 +12,7 @@ mkdir -p "$BASEIMAGEDIR" # build operator binary and base image pushd "$BASEIMAGEDIR" -go run "$ROOTDIR/hack/image/scaffold-ansible-image.go" +go run "$ROOTDIR/hack/image/ansible/scaffold-ansible-image.go" mkdir -p build/_output/bin/ cp $ROOTDIR/build/operator-sdk-dev-x86_64-linux-gnu build/_output/bin/ansible-operator diff --git a/hack/image/build-helm-image.sh b/hack/image/build-helm-image.sh index f559e192b16..80781618a12 100755 --- a/hack/image/build-helm-image.sh +++ b/hack/image/build-helm-image.sh @@ -2,8 +2,19 @@ set -eux +source hack/lib/test_lib.sh + +ROOTDIR="$(pwd)" +GOTMP="$(mktemp -d -p $GOPATH/src)" +trap_add 'rm -rf $GOTMP' EXIT +BASEIMAGEDIR="$GOTMP/helm-operator" +mkdir -p "$BASEIMAGEDIR" + # build operator binary and base image -GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o test/helm-operator/helm-operator test/helm-operator/cmd/helm-operator/main.go -pushd test/helm-operator -docker build -t "$1" . +pushd "$BASEIMAGEDIR" +go run "$ROOTDIR/hack/image/helm/scaffold-helm-image.go" + +mkdir -p build/_output/bin/ +cp $ROOTDIR/build/operator-sdk-dev-x86_64-linux-gnu build/_output/bin/helm-operator +operator-sdk build $1 popd diff --git a/hack/image/helm/scaffold-helm-image.go b/hack/image/helm/scaffold-helm-image.go new file mode 100644 index 00000000000..1a0a5dd9e19 --- /dev/null +++ b/hack/image/helm/scaffold-helm-image.go @@ -0,0 +1,45 @@ +// Copyright 2019 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 main + +import ( + "log" + + "github.com/operator-framework/operator-sdk/internal/util/projutil" + "github.com/operator-framework/operator-sdk/pkg/scaffold" + "github.com/operator-framework/operator-sdk/pkg/scaffold/helm" + "github.com/operator-framework/operator-sdk/pkg/scaffold/input" +) + +// main renders scaffolds that are required to build the helm operator base +// image. It is intended for release engineering use only. After running this, +// you can place a binary in `build/_output/bin/helm-operator` and then run +// `operator-sdk build`. +func main() { + cfg := &input.Config{ + AbsProjectPath: projutil.MustGetwd(), + ProjectName: "helm-operator", + } + + s := &scaffold.Scaffold{} + err := s.Execute(cfg, + &helm.DockerfileHybrid{}, + &helm.Entrypoint{}, + &helm.UserSetup{}, + ) + if err != nil { + log.Fatalf("add scaffold failed: (%v)", err) + } +} diff --git a/hack/tests/e2e-helm.sh b/hack/tests/e2e-helm.sh index ef7c986657d..686c50ba26b 100755 --- a/hack/tests/e2e-helm.sh +++ b/hack/tests/e2e-helm.sh @@ -2,9 +2,63 @@ source hack/lib/test_lib.sh -DEST_IMAGE="quay.io/example/nginx-operator:v0.0.2" +set -eux -set -ex +DEST_IMAGE="quay.io/example/nginx-operator:v0.0.2" +ROOTDIR="$(pwd)" +GOTMP="$(mktemp -d -p $GOPATH/src)" +trap_add 'rm -rf $GOTMP' EXIT + +deploy_operator() { + kubectl create -f "$OPERATORDIR/deploy/service_account.yaml" + kubectl create -f "$OPERATORDIR/deploy/role.yaml" + kubectl create -f "$OPERATORDIR/deploy/role_binding.yaml" + kubectl create -f "$OPERATORDIR/deploy/crds/helm_v1alpha1_nginx_crd.yaml" + kubectl create -f "$OPERATORDIR/deploy/operator.yaml" +} + +remove_operator() { + kubectl delete --ignore-not-found=true -f "$OPERATORDIR/deploy/service_account.yaml" + kubectl delete --ignore-not-found=true -f "$OPERATORDIR/deploy/role.yaml" + kubectl delete --ignore-not-found=true -f "$OPERATORDIR/deploy/role_binding.yaml" + kubectl delete --ignore-not-found=true -f "$OPERATORDIR/deploy/crds/helm_v1alpha1_nginx_crd.yaml" + kubectl delete --ignore-not-found=true -f "$OPERATORDIR/deploy/operator.yaml" +} + +test_operator() { + # wait for operator pod to run + if ! timeout 1m kubectl rollout status deployment/nginx-operator; + then + kubectl logs deployment/nginx-operator + exit 1 + fi + + # create CR + kubectl create -f deploy/crds/helm_v1alpha1_nginx_cr.yaml + trap_add 'kubectl delete --ignore-not-found -f ${OPERATORDIR}/deploy/crds/helm_v1alpha1_nginx_cr.yaml' EXIT + if ! timeout 1m bash -c -- 'until kubectl get nginxes.helm.example.com example-nginx -o jsonpath="{..status.conditions[1].release.info.status.code}" | grep 1; do sleep 1; done'; + then + kubectl logs deployment/nginx-operator + exit 1 + fi + + release_name=$(kubectl get nginxes.helm.example.com example-nginx -o jsonpath="{..status.conditions[1].release.name}") + nginx_deployment=$(kubectl get deployment -l "app.kubernetes.io/instance=${release_name}" -o jsonpath="{..metadata.name}") + + if ! timeout 1m kubectl rollout status deployment/${nginx_deployment}; + then + kubectl describe pods -l "app.kubernetes.io/instance=${release_name}" + kubectl describe deployments ${nginx_deployment} + kubectl logs deployment/${nginx_deployment} + exit 1 + fi + + nginx_service=$(kubectl get service -l "app.kubernetes.io/instance=${release_name}" -o jsonpath="{..metadata.name}") + kubectl get service ${nginx_service} + + kubectl delete -f deploy/crds/helm_v1alpha1_nginx_cr.yaml --wait=true + kubectl logs deployment/nginx-operator | grep "Uninstalled release" | grep "${release_name}" +} # if on openshift switch to the "default" namespace # and allow containers to run as root (necessary for @@ -15,71 +69,52 @@ then oc adm policy add-scc-to-user anyuid -z default fi -# Make a test directory for Helm tests so we avoid using default GOPATH. -# Save test directory so we can delete it on exit. -HELM_TEST_DIR="$(mktemp -d)" -trap_add 'rm -rf $HELM_TEST_DIR' EXIT -cp -a test/helm-* "$HELM_TEST_DIR" -pushd "$HELM_TEST_DIR" - -# Helm tests should not run in a Golang environment. -unset GOPATH GOROOT # create and build the operator +pushd "$GOTMP" operator-sdk new nginx-operator --api-version=helm.example.com/v1alpha1 --kind=Nginx --type=helm + pushd nginx-operator sed -i 's|\(FROM quay.io/operator-framework/helm-operator\)\(:.*\)\?|\1:dev|g' build/Dockerfile - operator-sdk build "$DEST_IMAGE" sed -i "s|REPLACE_IMAGE|$DEST_IMAGE|g" deploy/operator.yaml sed -i 's|Always|Never|g' deploy/operator.yaml sed -i 's|size: 3|replicaCount: 1|g' deploy/crds/helm_v1alpha1_nginx_cr.yaml -DIR2="$(pwd)" -# deploy the operator -kubectl create -f deploy/service_account.yaml -trap_add 'kubectl delete -f ${DIR2}/deploy/service_account.yaml' EXIT -kubectl create -f deploy/role.yaml -trap_add 'kubectl delete -f ${DIR2}/deploy/role.yaml' EXIT -kubectl create -f deploy/role_binding.yaml -trap_add 'kubectl delete -f ${DIR2}/deploy/role_binding.yaml' EXIT -kubectl create -f deploy/crds/helm_v1alpha1_nginx_crd.yaml -trap_add 'kubectl delete -f ${DIR2}/deploy/crds/helm_v1alpha1_nginx_crd.yaml' EXIT -kubectl create -f deploy/operator.yaml -trap_add 'kubectl delete -f ${DIR2}/deploy/operator.yaml' EXIT - -# wait for operator pod to run -if ! timeout 1m kubectl rollout status deployment/nginx-operator; -then - kubectl logs deployment/nginx-operator - exit 1 -fi +OPERATORDIR="$(pwd)" -# create CR -kubectl create -f deploy/crds/helm_v1alpha1_nginx_cr.yaml -trap_add 'kubectl delete --ignore-not-found -f ${DIR2}/deploy/crds/helm_v1alpha1_nginx_cr.yaml' EXIT -if ! timeout 1m bash -c -- 'until kubectl get nginxes.helm.example.com example-nginx -o jsonpath="{..status.conditions[1].release.info.status.code}" | grep 1; do sleep 1; done'; -then - kubectl logs deployment/nginx-operator - exit 1 -fi +deploy_operator +trap_add 'remove_operator' EXIT +test_operator +remove_operator -release_name=$(kubectl get nginxes.helm.example.com example-nginx -o jsonpath="{..status.conditions[1].release.name}") -nginx_deployment=$(kubectl get deployment -l "app.kubernetes.io/instance=${release_name}" -o jsonpath="{..metadata.name}") +echo "###" +echo "### Base image testing passed" +echo "### Now testing migrate to hybrid operator" +echo "###" -if ! timeout 1m kubectl rollout status deployment/${nginx_deployment}; +operator-sdk migrate + +if [[ ! -e build/Dockerfile.sdkold ]]; then - kubectl describe pods -l "app.kubernetes.io/instance=${release_name}" - kubectl describe deployments ${nginx_deployment} - kubectl logs deployment/${nginx_deployment} + echo FAIL the old Dockerfile should have been renamed to Dockerfile.sdkold exit 1 fi -nginx_service=$(kubectl get service -l "app.kubernetes.io/instance=${release_name}" -o jsonpath="{..metadata.name}") -kubectl get service ${nginx_service} +# We can't reliably run `dep ensure` because when there are changes to +# operator-sdk itself, and those changes are not merged upstream, we hit this +# bug: https://github.com/golang/dep/issues/1747 +# Instead, this re-uses operator-sdk's own vendor directory. +cp -a "$ROOTDIR"/vendor ./ +mkdir -p vendor/github.com/operator-framework/operator-sdk/ +# We cannot just use operator-sdk from $GOPATH because compilation tries to use +# its vendor directory, which can conflict with the local one. +cp -a "$ROOTDIR"/{internal,pkg,version,LICENSE} vendor/github.com/operator-framework/operator-sdk/ + +operator-sdk build "$DEST_IMAGE" -kubectl delete -f deploy/crds/helm_v1alpha1_nginx_cr.yaml --wait=true -kubectl logs deployment/nginx-operator | grep "Uninstalled release" | grep "${release_name}" +deploy_operator +test_operator popd popd diff --git a/test/helm-operator/cmd/helm-operator/main.go b/pkg/helm/run.go similarity index 84% rename from test/helm-operator/cmd/helm-operator/main.go rename to pkg/helm/run.go index b808213c82f..dd35a196c12 100644 --- a/test/helm-operator/cmd/helm-operator/main.go +++ b/pkg/helm/run.go @@ -1,4 +1,4 @@ -// Copyright 2018 The Operator-SDK Authors +// Copyright 2019 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. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package main +package helm import ( "fmt" @@ -25,7 +25,6 @@ import ( "github.com/operator-framework/operator-sdk/pkg/helm/release" "github.com/operator-framework/operator-sdk/pkg/k8sutil" sdkVersion "github.com/operator-framework/operator-sdk/version" - "github.com/spf13/pflag" "k8s.io/helm/pkg/storage" "k8s.io/helm/pkg/storage/driver" @@ -43,18 +42,17 @@ func printVersion() { log.Info(fmt.Sprintf("operator-sdk Version: %v", sdkVersion.Version)) } -func main() { - hflags := hoflags.AddTo(pflag.CommandLine) - pflag.Parse() - +// Run runs the helm operator +func Run(flags *hoflags.HelmOperatorFlags) { logf.SetLogger(logf.ZapLogger(false)) printVersion() - namespace, err := k8sutil.GetWatchNamespace() - if err != nil { - log.Error(err, "failed to get watch namespace") - os.Exit(1) + namespace, found := os.LookupEnv(k8sutil.WatchNamespaceEnvVar) + if found { + log.Info("Watching single namespace", "namespace", namespace) + } else { + log.Info(k8sutil.WatchNamespaceEnvVar + " environment variable not set, watching all namespaces") } cfg, err := config.GetConfig() @@ -69,8 +67,6 @@ func main() { os.Exit(1) } - log.Info("Registering Components.") - // Create Tiller's storage backend and kubernetes client storageBackend := storage.Init(driver.NewMemory()) tillerKubeClient, err := client.NewFromManager(mgr) @@ -79,7 +75,7 @@ func main() { os.Exit(1) } - factories, err := release.NewManagerFactoriesFromFile(storageBackend, tillerKubeClient, hflags.WatchesFile) + factories, err := release.NewManagerFactoriesFromFile(storageBackend, tillerKubeClient, flags.WatchesFile) if err != nil { log.Error(err, "") os.Exit(1) @@ -91,7 +87,7 @@ func main() { Namespace: namespace, GVK: gvk, ManagerFactory: factory, - ReconcilePeriod: hflags.ReconcilePeriod, + ReconcilePeriod: flags.ReconcilePeriod, }) if err != nil { log.Error(err, "") @@ -99,8 +95,6 @@ func main() { } } - log.Info("Starting the Cmd.") - // Start the Cmd if err := mgr.Start(signals.SetupSignalHandler()); err != nil { log.Error(err, "manager exited non-zero") diff --git a/pkg/scaffold/helm/dockerfilehybrid.go b/pkg/scaffold/helm/dockerfilehybrid.go new file mode 100644 index 00000000000..4954cac442b --- /dev/null +++ b/pkg/scaffold/helm/dockerfilehybrid.go @@ -0,0 +1,64 @@ +// Copyright 2019 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 helm + +import ( + "path/filepath" + + "github.com/operator-framework/operator-sdk/pkg/scaffold" + "github.com/operator-framework/operator-sdk/pkg/scaffold/input" +) + +//DockerfileHybrid - Dockerfile for a hybrid operator +type DockerfileHybrid struct { + input.Input + + // HelmCharts - if true, include a COPY statement for the helm-charts directory + HelmCharts bool + + // Watches - if true, include a COPY statement for watches.yaml + Watches bool +} + +// GetInput - gets the input +func (d *DockerfileHybrid) GetInput() (input.Input, error) { + if d.Path == "" { + d.Path = filepath.Join(scaffold.BuildDir, scaffold.DockerfileFile) + } + d.TemplateBody = dockerFileHybridHelmTmpl + return d.Input, nil +} + +const dockerFileHybridHelmTmpl = `FROM alpine:3.6 + +ENV OPERATOR=/usr/local/bin/helm-operator \ + USER_UID=1001 \ + USER_NAME=helm \ + HOME=/opt/helm + +# install operator binary +COPY build/_output/bin/{{.ProjectName}} ${OPERATOR} + +COPY bin /usr/local/bin +RUN /usr/local/bin/user_setup + +{{- if .HelmCharts }} +COPY helm-charts/ ${HOME}/helm-charts/{{ end }} +{{- if .Watches }} +COPY watches.yaml ${HOME}/watches.yaml{{ end }} + +ENTRYPOINT ["/usr/local/bin/entrypoint"] + +USER ${USER_UID}` diff --git a/pkg/scaffold/helm/entrypoint.go b/pkg/scaffold/helm/entrypoint.go new file mode 100644 index 00000000000..69c4125e820 --- /dev/null +++ b/pkg/scaffold/helm/entrypoint.go @@ -0,0 +1,49 @@ +// Copyright 2019 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 helm + +import ( + "path/filepath" + + "github.com/operator-framework/operator-sdk/pkg/scaffold/input" +) + +// Entrypoint - entrypoint script +type Entrypoint struct { + input.Input +} + +func (e *Entrypoint) GetInput() (input.Input, error) { + if e.Path == "" { + e.Path = filepath.Join("bin", "entrypoint") + } + e.TemplateBody = entrypointTmpl + e.IsExec = true + return e.Input, nil +} + +const entrypointTmpl = `#!/bin/sh -e + +# This is documented here: +# https://docs.openshift.com/container-platform/3.11/creating_images/guidelines.html#openshift-specific-guidelines + +if ! whoami &>/dev/null; then + if [ -w /etc/passwd ]; then + echo "${USER_NAME:-helm}:x:$(id -u):$(id -g):${USER_NAME:-helm} user:${HOME}:/sbin/nologin" >> /etc/passwd + fi +fi + +exec ${OPERATOR} run helm --watches-file=/opt/helm/watches.yaml $@ +` diff --git a/pkg/scaffold/helm/gopkgtoml.go b/pkg/scaffold/helm/gopkgtoml.go new file mode 100644 index 00000000000..d0e68100912 --- /dev/null +++ b/pkg/scaffold/helm/gopkgtoml.go @@ -0,0 +1,44 @@ +// Copyright 2019 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 helm + +import ( + "github.com/operator-framework/operator-sdk/pkg/scaffold" + "github.com/operator-framework/operator-sdk/pkg/scaffold/input" +) + +// GopkgToml - the Gopkg.toml file for a hybrid operator +type GopkgToml struct { + input.Input +} + +func (s *GopkgToml) GetInput() (input.Input, error) { + if s.Path == "" { + s.Path = scaffold.GopkgTomlFile + } + s.TemplateBody = gopkgTomlTmpl + return s.Input, nil +} + +const gopkgTomlTmpl = `[[constraint]] + name = "github.com/operator-framework/operator-sdk" + # The version rule is used for a specific release and the master branch for in between releases. + branch = "master" #osdk_branch_annotation + # version = "=v0.3.0" #osdk_version_annotation + +[prune] + go-tests = true + unused-packages = true +` diff --git a/pkg/scaffold/helm/main.go b/pkg/scaffold/helm/main.go new file mode 100644 index 00000000000..f3df14f681f --- /dev/null +++ b/pkg/scaffold/helm/main.go @@ -0,0 +1,51 @@ +// Copyright 2019 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 helm + +import ( + "path/filepath" + + "github.com/operator-framework/operator-sdk/pkg/scaffold/input" +) + +// Main - main source file for helm operator +type Main struct { + input.Input +} + +func (m *Main) GetInput() (input.Input, error) { + if m.Path == "" { + m.Path = filepath.Join("cmd", "manager", "main.go") + } + m.TemplateBody = mainTmpl + return m.Input, nil +} + +const mainTmpl = `package main + +import ( + hoflags "github.com/operator-framework/operator-sdk/pkg/helm/flags" + "github.com/operator-framework/operator-sdk/pkg/helm" + + "github.com/spf13/pflag" +) + +func main() { + hflags := hoflags.AddTo(pflag.CommandLine) + pflag.Parse() + + helm.Run(hflags) +} +` diff --git a/pkg/scaffold/helm/usersetup.go b/pkg/scaffold/helm/usersetup.go new file mode 100644 index 00000000000..b76f57b39f8 --- /dev/null +++ b/pkg/scaffold/helm/usersetup.go @@ -0,0 +1,50 @@ +// Copyright 2019 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 helm + +import ( + "path/filepath" + + "github.com/operator-framework/operator-sdk/pkg/scaffold/input" +) + +// UserSetup - userSetup script +type UserSetup struct { + input.Input +} + +func (u *UserSetup) GetInput() (input.Input, error) { + if u.Path == "" { + u.Path = filepath.Join("bin", "user_setup") + } + u.TemplateBody = userSetupTmpl + u.IsExec = true + return u.Input, nil +} + +const userSetupTmpl = `#!/bin/sh +set -x + +# ensure $HOME exists and is accessible by group 0 (we don't know what the runtime UID will be) +mkdir -p ${HOME} +chown ${USER_UID}:0 ${HOME} +chmod ug+rwx ${HOME} + +# runtime user will need to be able to self-insert in /etc/passwd +chmod g+rw /etc/passwd + +# no need for this script to remain in the image after running +rm $0 +` diff --git a/release.sh b/release.sh index ab36eaf8579..618cee55755 100755 --- a/release.sh +++ b/release.sh @@ -33,6 +33,7 @@ fi VER_FILE="version/version.go" TOML_TMPL_FILE="pkg/scaffold/gopkgtoml.go" ANS_TOML_TMPL_FILE="pkg/scaffold/ansible/gopkgtoml.go" +HELM_TOML_TMPL_FILE="pkg/scaffold/helm/gopkgtoml.go" CURR_VER_VER_FILE="$(sed -nr 's/Version = "(.+)"/\1/p' "$VER_FILE" | tr -d ' \t\n')" CURR_VER_TMPL_FILE="$(sed -nr 's/.*".*v(.+)".*#osdk_version_annotation/v\1/p' "$TOML_TMPL_FILE" | tr -d ' \t\n')" if [[ "$VER" != "$CURR_VER_VER_FILE" || "$VER" != "$CURR_VER_TMPL_FILE" ]]; then @@ -44,6 +45,11 @@ if [[ "$VER" != "$CURR_VER_ANS_TMPL_FILE" ]]; then echo "versions are not set correctly in $ANS_TOML_TMPL_FILE" exit 1 fi +CURR_VER_HELM_TMPL_FILE="$(sed -nr 's/.*".*v(.+)".*#osdk_version_annotation/v\1/p' "$HELM_TOML_TMPL_FILE" | tr -d ' \t\n')" +if [[ "$VER" != "$CURR_VER_HELM_TMPL_FILE" ]]; then + echo "versions are not set correctly in $HELM_TOML_TMPL_FILE" + exit 1 +fi git tag --sign --message "Operator SDK $VER" "$VER" diff --git a/test/helm-operator/Dockerfile b/test/helm-operator/Dockerfile deleted file mode 100644 index 9808aef5900..00000000000 --- a/test/helm-operator/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM alpine:3.6 - -ENV OPERATOR=/usr/local/bin/helm-operator \ - USER_UID=1001 \ - USER_NAME=helm-operator \ - HOME=/opt/helm - -# install operator binary -COPY helm-operator ${OPERATOR} - -COPY bin /usr/local/bin -RUN /usr/local/bin/user_setup - -ENTRYPOINT ["/usr/local/bin/entrypoint"] - -USER ${USER_UID} diff --git a/test/helm-operator/README.md b/test/helm-operator/README.md deleted file mode 100644 index a8b63d71eaf..00000000000 --- a/test/helm-operator/README.md +++ /dev/null @@ -1,2 +0,0 @@ -This directory temporarily holds the artifacts that are required to build the -helm operator base image, until they find a more permanent home. diff --git a/test/helm-operator/bin/entrypoint b/test/helm-operator/bin/entrypoint deleted file mode 100755 index e8c18b48fc0..00000000000 --- a/test/helm-operator/bin/entrypoint +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -e - -# This is documented here: -# https://docs.openshift.com/container-platform/3.10/creating_images/guidelines.html#openshift-specific-guidelines - -if ! whoami &>/dev/null; then - if [ -w /etc/passwd ]; then - echo "${USER_NAME:-helm}:x:$(id -u):$(id -g):${USER_NAME:-helm} user:${HOME}:/sbin/nologin" >> /etc/passwd - fi -fi - -#Watches file will be overridden if the flag is provided again. -exec ${OPERATOR} --watches-file=/opt/helm/watches.yaml $@ diff --git a/test/helm-operator/bin/user_setup b/test/helm-operator/bin/user_setup deleted file mode 100755 index 1e36064cbf0..00000000000 --- a/test/helm-operator/bin/user_setup +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -set -x - -# ensure $HOME exists and is accessible by group 0 (we don't know what the runtime UID will be) -mkdir -p ${HOME} -chown ${USER_UID}:0 ${HOME} -chmod ug+rwx ${HOME} - -# runtime user will need to be able to self-insert in /etc/passwd -chmod g+rw /etc/passwd - -# no need for this script to remain in the image after running -rm $0 From 6d0f7e02f5cd8e340514c1143eba360cf2b5c947 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Fri, 11 Jan 2019 16:18:37 -0500 Subject: [PATCH 2/4] CHANGELOG.md,doc,commands/.../run/helm.go: document helm support for run and migrate commands --- CHANGELOG.md | 4 ++-- commands/operator-sdk/cmd/run/helm.go | 5 ++++- doc/sdk-cli-reference.md | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f38f07f6bf2..9dec478d5c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,8 @@ ### Added -- A new command [`operator-sdk migrate`](https://github.com/operator-framework/operator-sdk/blob/master/doc/sdk-cli-reference.md#migrate) which adds a main.go source file and any associated source files for an operator that is not of the "go" type. ([#887](https://github.com/operator-framework/operator-sdk/pull/887)) -- A new command [`operator-sdk run ansible`](https://github.com/operator-framework/operator-sdk/blob/master/doc/sdk-cli-reference.md#ansible) which runs as an ansible operator process. This is intended to be used when running in a Pod inside a cluster. Developers wanting to run their operator locally should continue to use `up local`. ([#887](https://github.com/operator-framework/operator-sdk/pull/887)) +- A new command [`operator-sdk migrate`](https://github.com/operator-framework/operator-sdk/blob/master/doc/sdk-cli-reference.md#migrate) which adds a main.go source file and any associated source files for an operator that is not of the "go" type. ([#887](https://github.com/operator-framework/operator-sdk/pull/887) and [#897](https://github.com/operator-framework/operator-sdk/pull/897)) +- New commands [`operator-sdk run ansible`](https://github.com/operator-framework/operator-sdk/blob/master/doc/sdk-cli-reference.md#ansible) and [`operator-sdk run helm`](https://github.com/operator-framework/operator-sdk/blob/master/doc/sdk-cli-reference.md#helm) which run the SDK as ansible and helm operator processes, respectively. These are intended to be used when running in a Pod inside a cluster. Developers wanting to run their operator locally should continue to use `up local`. ([#887](https://github.com/operator-framework/operator-sdk/pull/887) and [#897](https://github.com/operator-framework/operator-sdk/pull/897)) ### Changed diff --git a/commands/operator-sdk/cmd/run/helm.go b/commands/operator-sdk/cmd/run/helm.go index c924b0c720e..3835a286884 100644 --- a/commands/operator-sdk/cmd/run/helm.go +++ b/commands/operator-sdk/cmd/run/helm.go @@ -26,7 +26,10 @@ func NewHelmCmd() *cobra.Command { var flags *hoflags.HelmOperatorFlags newCmd := &cobra.Command{ Use: "helm", - Short: "Runs as a Helm operator", + Short: "Runs as a helm operator", + Long: `Runs as a helm operator. This is intended to be used when running +in a Pod inside a cluster. Developers wanting to run their operator locally +should use "up local" instead.`, Run: func(cmd *cobra.Command, args []string) { helm.Run(flags) }, diff --git a/doc/sdk-cli-reference.md b/doc/sdk-cli-reference.md index 20507203809..cd254d3f973 100644 --- a/doc/sdk-cli-reference.md +++ b/doc/sdk-cli-reference.md @@ -300,6 +300,23 @@ should use `up local` instead. $ operator-sdk run ansible --watches-file=/opt/ansible/watches.yaml --reconcile-period=30s ``` +### helm + +Runs as a helm operator process. This is intended to be used when running +in a Pod inside a cluster. Developers wanting to run their operator locally +should use `up local` instead. + +#### Flags + +* `--reconcile-period` string - Default reconcile period for controllers (default 1m0s) +* `--watches-file` string - Path to the watches file to use (default "./watches.yaml") + +#### Example + +```bash +$ operator-sdk run helm --watches-file=/opt/helm/watches.yaml --reconcile-period=30s +``` + ## test ### Available Commands From 8ce2ff52ffea7fc24c7028c00a7a800fb5bf8279 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Mon, 14 Jan 2019 17:31:43 -0500 Subject: [PATCH 3/4] doc/dev/testing/travis-build.md: ansible/helm e2e doc update --- doc/dev/testing/travis-build.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/dev/testing/travis-build.md b/doc/dev/testing/travis-build.md index 998a93b29ae..691f98553c0 100644 --- a/doc/dev/testing/travis-build.md +++ b/doc/dev/testing/travis-build.md @@ -69,7 +69,7 @@ The Go, Ansible, and Helm tests then differ in what tests they run. ### Ansible tests 1. Run [ansible e2e tests][ansible-e2e]. - 1. Create base ansible operator image by running [`hack/image/ansible/scaffold-ansible-image.go`][ansible-base]. + 1. Create base ansible operator project by running [`hack/image/ansible/scaffold-ansible-image.go`][ansible-base]. 2. Build base ansible operator image. 3. Create and configure a new ansible type memcached-operator. 4. Create cluster resources. @@ -86,7 +86,7 @@ The Go, Ansible, and Helm tests then differ in what tests they run. ### Helm Tests 1. Run [helm e2e tests][helm-e2e]. - 1. Create base helm operator image by running [`hack/image/helm/scaffold-helm-image.go`][helm-base]. + 1. Create base helm operator project by running [`hack/image/helm/scaffold-helm-image.go`][helm-base]. 2. Build base helm operator image. 3. Create and configure a new helm type nginx-operator. 4. Create cluster resources. From 04501f853b9ead50c2fcfad142dbf6fd3cc34396 Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Mon, 14 Jan 2019 18:23:24 -0500 Subject: [PATCH 4/4] doc/dev/release.md: documenting new release steps for ansible/helm gopkgtoml.go --- doc/dev/release.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/dev/release.md b/doc/dev/release.md index f7b323412dd..6c4643ab0d6 100644 --- a/doc/dev/release.md +++ b/doc/dev/release.md @@ -171,13 +171,15 @@ Create a new branch to push release commits: $ git checkout -b release-v1.3.0 ``` -Commit changes to the following four files: +Commit changes to the following six files: * `version/version.go`: update `Version` to `v1.3.0`. * `pkg/scaffold/gopkgtoml.go`, under the `[[constraint]]` for `github.com/operator-framework/operator-sdk`: * Comment out `branch = "master"` * Un-comment `version = "v1.2.0"` * Change `v1.2.0` to `v1.3.0` * `pkg/scaffold/gopkgtoml_test.go`: same as for `pkg/scaffold/gopkgtoml.go`. +* `pkg/scaffold/ansible/gopkgtoml.go`: same as for `pkg/scaffold/gopkgtoml.go`. +* `pkg/scaffold/helm/gopkgtoml.go`: same as for `pkg/scaffold/gopkgtoml.go`. * `CHANGELOG.md`: update the `## Unreleased` header to `## v1.3.0`. Create a new PR for `release-v1.3.0`. @@ -216,6 +218,8 @@ Check out a new branch from master (or use your `release-v1.3.0`) and commit the * Comment out `version = "v1.3.0"` * Un-comment `branch = "master"` * `pkg/scaffold/gopkgtoml_test.go`: same as for `pkg/scaffold/gopkgtoml.go`. +* `pkg/scaffold/ansible/gopkgtoml.go`: same as for `pkg/scaffold/gopkgtoml.go`. +* `pkg/scaffold/helm/gopkgtoml.go`: same as for `pkg/scaffold/gopkgtoml.go`. * `CHANGELOG.md`: add the following as a new set of headers above `## v1.3.0`: ``` ## Unreleased