Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

commands,pkg/scaffold,hack,pkg/helm: run and migrate command support for helm #897

Merged
merged 7 commits into from
Jan 15, 2019
Merged
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
48 changes: 41 additions & 7 deletions commands/operator-sdk/cmd/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,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"

log "github.com/sirupsen/logrus"
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -76,13 +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.Infof("Renamed Dockerfile to %s and replaced with newer version. Compare the new Dockerfile to your old one and manually migrate any customizations", newDockerfilePath)
renameDockerfile()

s := &scaffold.Scaffold{}
err = s.Execute(cfg,
Expand All @@ -96,3 +93,40 @@ func migrateAnsible() {
log.Fatalf("Migrate 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("Migrate 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.Infof("Renamed Dockerfile to %s and replaced with newer version. Compare the new Dockerfile to your old one and manually migrate any customizations", newDockerfilePath)
}
1 change: 1 addition & 0 deletions commands/operator-sdk/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ should use "up local" instead.`,
}

runCmd.AddCommand(run.NewAnsibleCmd())
runCmd.AddCommand(run.NewHelmCmd())
return runCmd
}
3 changes: 1 addition & 2 deletions commands/operator-sdk/cmd/run/ansible.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
40 changes: 40 additions & 0 deletions commands/operator-sdk/cmd/run/helm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// 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",
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)
},
}
flags = hoflags.AddTo(newCmd.Flags())

return newCmd
}
57 changes: 6 additions & 51 deletions commands/operator-sdk/cmd/up/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -172,50 +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,
WatchDependentResources: true,
})
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() {
Expand Down
24 changes: 15 additions & 9 deletions doc/dev/testing/travis-build.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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.
Expand All @@ -86,12 +86,18 @@ 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 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.
5. Wait for operator to be ready.
6. Create nginx CR and wait for it to be ready.
7. Scale up the dependent deployment and verify the operator reconciles it back down.
8. Scale up the CR and verify the dependent deployment scales up accordingly.
9. Delete nginx CR and verify that finalizer (which writes a message in the operator logs) ran.
10. Run `operator-sdk migrate` to add go source to the operator.
11. Run `operator-sdk build` to compile the new binary and build a new image.
12. Re-run steps 4-9 to test the migrated operator.

**NOTE**: All created resources, including the namespace, are deleted using a bash trap when the test finishes

Expand All @@ -110,8 +116,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
17 changes: 17 additions & 0 deletions doc/sdk-cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion hack/image/build-ansible-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 14 additions & 3 deletions hack/image/build-helm-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
45 changes: 45 additions & 0 deletions hack/image/helm/scaffold-helm-image.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
Loading