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

Add code for building and running helm operator binary #110

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ require (
github.com/onsi/gomega v1.14.0
github.com/operator-framework/operator-lib v0.3.0
github.com/prometheus/client_golang v1.11.0
github.com/sergi/go-diff v1.1.0
github.com/sirupsen/logrus v1.8.1
github.com/spf13/afero v1.2.2
github.com/spf13/cobra v1.1.3
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.0
gomodules.xyz/jsonpatch/v2 v2.2.0
gomodules.xyz/jsonpatch/v3 v3.0.1
helm.sh/helm/v3 v3.6.2
k8s.io/api v0.22.1
k8s.io/apiextensions-apiserver v0.22.1
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,10 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
gomodules.xyz/jsonpatch/v3 v3.0.1 h1:Te7hKxV52TKCbNYq3t84tzKav3xhThdvSsSp/W89IyI=
gomodules.xyz/jsonpatch/v3 v3.0.1/go.mod h1:CBhndykehEwTOlEfnsfJwvkFQbSN8YZFr9M+cIHAJto=
gomodules.xyz/orderedmap v0.1.0 h1:fM/+TGh/O1KkqGR5xjTKg6bU8OKBkg7p0Y+x/J9m8Os=
gomodules.xyz/orderedmap v0.1.0/go.mod h1:g9/TPUCm1t2gwD3j3zfV8uylyYhVdCNSi+xCEIu7yTU=
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
Expand Down
221 changes: 221 additions & 0 deletions internal/cmd/helm-operator/run/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
// Copyright 2020 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 (
"errors"
"flag"
"fmt"
"os"
"runtime"
"strings"

"github.com/operator-framework/helm-operator-plugins/internal/flags"
"github.com/operator-framework/helm-operator-plugins/internal/legacy/controller"
"github.com/operator-framework/helm-operator-plugins/internal/legacy/release"
watches "github.com/operator-framework/helm-operator-plugins/internal/legacy/watches"
"github.com/operator-framework/helm-operator-plugins/internal/metrics"
"github.com/operator-framework/helm-operator-plugins/internal/version"
helmmgr "github.com/operator-framework/helm-operator-plugins/pkg/manager"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/controller-runtime/pkg/healthz"
logf "sigs.k8s.io/controller-runtime/pkg/log"
zapf "sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
crmetrics "sigs.k8s.io/controller-runtime/pkg/metrics"
)

var log = logf.Log.WithName("cmd")

func printVersion() {
log.Info("Version",
"Go Version", runtime.Version(),
"GOOS", runtime.GOOS,
"GOARCH", runtime.GOARCH,
"helm-operator", version.GitVersion,
"commit", version.GitCommit)
}

func NewCmd() *cobra.Command {
f := &flags.Flags{}
zapfs := flag.NewFlagSet("zap", flag.ExitOnError)
opts := &zapf.Options{}
opts.BindFlags(zapfs)

cmd := &cobra.Command{
Use: "run",
Short: "Run the operator",
Run: func(cmd *cobra.Command, _ []string) {
logf.SetLogger(zapf.New(zapf.UseFlagOptions(opts)))
run(cmd, f)
},
}

f.AddTo(cmd.Flags())
cmd.Flags().AddGoFlagSet(zapfs)
return cmd
}

func run(cmd *cobra.Command, f *flags.Flags) {
printVersion()
metrics.RegisterBuildInfo(crmetrics.Registry)

// Load config options from the config at f.ManagerConfigPath.
// These options will not override those set by flags.
var (
options manager.Options
err error
)
if f.ManagerConfigPath != "" {
cfgLoader := ctrl.ConfigFile().AtPath(f.ManagerConfigPath)
if options, err = options.AndFrom(cfgLoader); err != nil {
log.Error(err, "Unable to load the manager config file")
os.Exit(1)
}
}
exitIfUnsupported(options)

cfg, err := config.GetConfig()
if err != nil {
log.Error(err, "Failed to get config.")
os.Exit(1)
}

// TODO(2.0.0): remove
// Deprecated: OPERATOR_NAME environment variable is an artifact of the
// legacy operator-sdk project scaffolding. Flag `--leader-election-id`
// should be used instead.
if operatorName, found := os.LookupEnv("OPERATOR_NAME"); found {
log.Info("Environment variable OPERATOR_NAME has been deprecated, use --leader-election-id instead.")
if cmd.Flags().Changed("leader-election-id") {
log.Info("Ignoring OPERATOR_NAME environment variable since --leader-election-id is set")
} else if options.LeaderElectionID == "" {
// Only set leader election ID using OPERATOR_NAME if unset everywhere else,
// since this env var is deprecated.
options.LeaderElectionID = operatorName
}
}

//TODO(2.0.0): remove the following checks. they are required just because of the flags deprecation
if cmd.Flags().Changed("leader-elect") && cmd.Flags().Changed("enable-leader-election") {
log.Error(errors.New("only one of --leader-elect and --enable-leader-election may be set"), "invalid flags usage")
os.Exit(1)
}

if cmd.Flags().Changed("metrics-addr") && cmd.Flags().Changed("metrics-bind-address") {
log.Error(errors.New("only one of --metrics-addr and --metrics-bind-address may be set"), "invalid flags usage")
os.Exit(1)
}

// Set default manager options
options = f.ToManagerOptions(options)

if options.NewClient == nil {
options.NewClient = helmmgr.NewCachingClientFunc()
}
namespace, found := os.LookupEnv(helmmgr.WatchNamespaceEnvVar)
log = log.WithValues("Namespace", namespace)
if found {
log.V(1).Info(fmt.Sprintf("Setting namespace with value in %s", helmmgr.WatchNamespaceEnvVar))
if namespace == metav1.NamespaceAll {
log.Info("Watching all namespaces.")
options.Namespace = metav1.NamespaceAll
} else {
if strings.Contains(namespace, ",") {
log.Info("Watching multiple namespaces.")
options.NewCache = cache.MultiNamespacedCacheBuilder(strings.Split(namespace, ","))
} else {
log.Info("Watching single namespace.")
options.Namespace = namespace
}
}
} else if options.Namespace == "" {
log.Info(fmt.Sprintf("Watch namespaces not configured by environment variable %s or file. "+
"Watching all namespaces.", helmmgr.WatchNamespaceEnvVar))
options.Namespace = metav1.NamespaceAll
}

mgr, err := manager.New(cfg, options)
if err != nil {
log.Error(err, "Failed to create a new manager")
os.Exit(1)
}

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
log.Error(err, "Unable to set up health check")
os.Exit(1)
}
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
log.Error(err, "Unable to set up ready check")
os.Exit(1)
}

ws, err := watches.Load(f.WatchesFile)
if err != nil {
log.Error(err, "Failed to create new manager factories.")
os.Exit(1)
}

for _, w := range ws {
// Register the controller with the factory.
err := controller.Add(mgr, controller.WatchOptions{
Namespace: namespace,
GVK: w.GroupVersionKind,
ManagerFactory: release.NewManagerFactory(mgr, w.ChartDir),
ReconcilePeriod: f.ReconcilePeriod,
WatchDependentResources: *w.WatchDependentResources,
OverrideValues: w.OverrideValues,
MaxConcurrentReconciles: f.MaxConcurrentReconciles,
Selector: w.Selector,
})
if err != nil {
log.Error(err, "Failed to add manager factory to controller.")
os.Exit(1)
}
}

// Start the Cmd
if err = mgr.Start(signals.SetupSignalHandler()); err != nil {
log.Error(err, "Manager exited non-zero.")
os.Exit(1)
}

}

// exitIfUnsupported prints an error containing unsupported field names and exits
// if any of those fields are not their default values.
func exitIfUnsupported(options manager.Options) {
var keys []string
// The below options are webhook-specific, which is not supported by ansible.
if options.CertDir != "" {
keys = append(keys, "certDir")
}
if options.Host != "" {
keys = append(keys, "host")
}
if options.Port != 0 {
keys = append(keys, "port")
}

if len(keys) > 0 {
log.Error(fmt.Errorf("%s set in manager options", strings.Join(keys, ", ")), "unsupported fields")
os.Exit(1)
}
}
File renamed without changes.
Loading