Skip to content

Commit

Permalink
feat: improve configuration parsing (#24)
Browse files Browse the repository at this point in the history
This PR ensures, that the configuration of the garm-operator can be done
with `ENVs`, `Flags` and `Config File (yaml)`

---------

Co-authored-by: bavarianbidi <mario.constanti@mercedes-benz.com>
  • Loading branch information
H777K and bavarianbidi authored Nov 21, 2023
1 parent df70011 commit 9a99d0d
Show file tree
Hide file tree
Showing 15 changed files with 536 additions and 112 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:

- uses: actions/setup-go@v4
with:
go-version: '1.21.3'
go-version: '1.21.4'

- name: make verify
run: make verify
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/foss.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v4
with:
go-version: '1.21.3'
go-version: '1.21.4'
id: go

- name: Checkout code
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
- run: git fetch --force --tags
- uses: actions/setup-go@v4
with:
go-version: '1.21.3'
go-version: '1.21.4'

- name: Synopsys Detect
run: |
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: MIT
# Build the manager binary
FROM golang:1.21.3 as builder
FROM golang:1.21.4 as builder
ARG TARGETOS
ARG TARGETARCH

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,12 @@ export GARM_OPERATOR_VERSION=<garm-operator-version>
export GARM_SERVER_URL=<garm-server-url>
export GARM_SERVER_USERNAME=<garm-server-username>
export GARM_SERVER_PASSWORD=<garm-server-password>
export OPERATOR_WATCH_NAMESPACE=<operator-watch-namespace>
curl -L https://github.com/mercedes-benz/garm-operator/releases/download/${GARM_OPERATOR_VERSION}/garm-operator-all.yaml | envsubst | kubectl apply -f -
```

The full configuration parsing documentation can be found in the [configuration parsing guide](./docs/config/configuration-parsing.md)

#### Custom Resources

The CRD documentation can be also seen via [docs.crds.dev](https://doc.crds.dev/github.com/mercedes-benz/garm-operator).
Expand Down
153 changes: 57 additions & 96 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,23 @@
package main

import (
"errors"
"flag"
"fmt"
"os"
"time"

"github.com/spf13/pflag"
"gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/klog/v2"
"k8s.io/klog/v2/klogr"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/healthz"

garmoperatorv1alpha1 "github.com/mercedes-benz/garm-operator/api/v1alpha1"
"github.com/mercedes-benz/garm-operator/internal/controller"
"github.com/mercedes-benz/garm-operator/pkg/config"
"github.com/mercedes-benz/garm-operator/pkg/flags"
)

var (
Expand All @@ -36,68 +35,45 @@ func init() {
}

func main() {
var (
metricsAddr string
enableLeaderElection bool
probeAddr string
syncPeriod time.Duration

watchNamespace string

garmServer string
garmUsername string
garmPassword string
)

flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
flag.DurationVar(&syncPeriod, "sync-period", 5*time.Minute,
"The minimum interval at which watched resources are reconciled (e.g. 15m)")

flag.StringVar(&watchNamespace, "namespace", "",
"Namespace that the controller watches to reconcile garm objects. If unspecified, the controller watches for garm objects across all namespaces.")

flag.StringVar(&garmServer, "garm-server", "", "The address of the GARM server")
flag.StringVar(&garmUsername, "garm-username", "", "The username for the GARM server")
flag.StringVar(&garmPassword, "garm-password", "", "The password for the GARM server")

klog.InitFlags(flag.CommandLine)
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
ctrl.SetLogger(klogr.New())

// configure garm client from environment variables
if len(os.Getenv("GARM_SERVER")) > 0 {
setupLog.Info("Using garm-server from environment variable")
garmServer = os.Getenv("GARM_SERVER")
}
if len(os.Getenv("GARM_USERNAME")) > 0 {
setupLog.Info("Using garm-username from environment variable")
garmUsername = os.Getenv("GARM_USERNAME")
}
if len(os.Getenv("GARM_PASSWORD")) > 0 {
setupLog.Info("Using garm-password from environment variable")
garmPassword = os.Getenv("GARM_PASSWORD")
// initiate flags
f := flags.InitiateFlags()

// retrieve config flag value for GenerateConfig() function
configFile := f.Lookup("config").Value.String()

// call GenerateConfig() function from config package
if err := config.GenerateConfig(f, configFile); err != nil {
setupLog.Error(err, "failed to read config")
os.Exit(1)
}
if len(os.Getenv("WATCH_NAMESPACE")) > 0 {
setupLog.Info("using watch-namespace from environment variable")
watchNamespace = os.Getenv("WATCH_NAMESPACE")

// check if dry-run flag is set to true
dryRun, _ := f.GetBool("dry-run")

// perform dry-run if enabled and print out the generated Config as yaml
if dryRun {
yamlConfig, err := yaml.Marshal(config.Config)
if err != nil {
setupLog.Error(err, "failed to marshal config as yaml")
os.Exit(1)
}
fmt.Printf("generated Config as yaml:\n%s\n", yamlConfig)
os.Exit(0)
}

var watchNamespaces []string
if watchNamespace != "" {
watchNamespaces = []string{watchNamespace}
if config.Config.Operator.WatchNamespace != "" {
watchNamespaces = []string{config.Config.Operator.WatchNamespace}
}

mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
MetricsBindAddress: metricsAddr,
MetricsBindAddress: config.Config.Operator.MetricsBindAddress,
Port: 9443,
HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection,
HealthProbeBindAddress: config.Config.Operator.HealthProbeBindAddress,
LeaderElection: config.Config.Operator.LeaderElection,
LeaderElectionID: "b608d8b3.mercedes-benz.com",
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
// when the Manager ends. This requires the binary to immediately end when the
Expand All @@ -113,38 +89,25 @@ func main() {
//
// Default Sync Period = 10 hours.
// Set default via flag to 5 minutes
SyncPeriod: &syncPeriod,
SyncPeriod: &config.Config.Operator.SyncPeriod,
Cache: cache.Options{
Namespaces: watchNamespaces,
SyncPeriod: &syncPeriod,
SyncPeriod: &config.Config.Operator.SyncPeriod,
},
})
if err != nil {
setupLog.Error(err, "unable to start manager")
os.Exit(1)
}

if garmServer == "" {
setupLog.Error(errors.New("unable to fetch garm server from either flag or os_env"), "unable to start manager")
os.Exit(1)
}
if garmUsername == "" {
setupLog.Error(errors.New("unable to fetch garm username from either flag or os_env"), "unable to start manager")
os.Exit(1)
}
if garmPassword == "" {
setupLog.Error(errors.New("unable to fetch garm password from either flag or os_env"), "unable to start manager")
os.Exit(1)
}

if err = (&controller.EnterpriseReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("enterprise-controller"),

BaseURL: garmServer,
Username: garmUsername,
Password: garmPassword,
BaseURL: config.Config.Garm.Server,
Username: config.Config.Garm.Username,
Password: config.Config.Garm.Password,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Enterprise")
os.Exit(1)
Expand All @@ -154,37 +117,35 @@ func main() {
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("pool-controller"),

BaseURL: garmServer,
Username: garmUsername,
Password: garmPassword,
BaseURL: config.Config.Garm.Server,
Username: config.Config.Garm.Username,
Password: config.Config.Garm.Password,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Pool")
os.Exit(1)
}

if os.Getenv("CREATE_WEBHOOK") == "true" {
if err = (&garmoperatorv1alpha1.Pool{}).SetupWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "Pool")
os.Exit(1)
}
if err = (&garmoperatorv1alpha1.Image{}).SetupWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "Image")
os.Exit(1)
}
if err = (&garmoperatorv1alpha1.Repository{}).SetupWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "Repository")
os.Exit(1)
}
if err = (&garmoperatorv1alpha1.Pool{}).SetupWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "Pool")
os.Exit(1)
}
if err = (&garmoperatorv1alpha1.Image{}).SetupWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "Image")
os.Exit(1)
}
if err = (&garmoperatorv1alpha1.Repository{}).SetupWebhookWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create webhook", "webhook", "Repository")
os.Exit(1)
}

if err = (&controller.OrganizationReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("organization-controller"),

BaseURL: garmServer,
Username: garmUsername,
Password: garmPassword,
BaseURL: config.Config.Garm.Server,
Username: config.Config.Garm.Username,
Password: config.Config.Garm.Password,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Organization")
os.Exit(1)
Expand All @@ -195,9 +156,9 @@ func main() {
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("repository-controller"),

BaseURL: garmServer,
Username: garmUsername,
Password: garmPassword,
BaseURL: config.Config.Garm.Server,
Username: config.Config.Garm.Username,
Password: config.Config.Garm.Password,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Repository")
os.Exit(1)
Expand Down
8 changes: 1 addition & 7 deletions config/manager/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,8 @@ spec:
- --garm-server=$GARM_SERVER_URL
- --garm-username=$GARM_SERVER_USERNAME
- --garm-password=$GARM_SERVER_PASSWORD
- --operator-watch-namespace=$OPERATOR_WATCH_NAMESPACE
image: controller:latest
env:
- name: CREATE_WEBHOOK
value: "true"
- name: WATCH_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
name: manager
securityContext:
allowPrivilegeEscalation: false
Expand Down
Loading

0 comments on commit 9a99d0d

Please sign in to comment.