Skip to content

Commit

Permalink
Merge pull request #293 from projectsyn/feat/disentangle-envvars
Browse files Browse the repository at this point in the history
Disentangle random environment variables
  • Loading branch information
HappyTetrahedron authored Jul 25, 2024
2 parents 3bbe176 + b6327fe commit 704dc7d
Show file tree
Hide file tree
Showing 13 changed files with 111 additions and 159 deletions.
6 changes: 6 additions & 0 deletions controllers/cluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ type ClusterReconciler struct {

CreateSATokenSecret bool
DefaultCreationPolicy synv1alpha1.CreationPolicy
DefaultDeletionPolicy synv1alpha1.DeletionPolicy
UseVault bool
DeleteProtection bool
}

//+kubebuilder:rbac:groups=syn.tools,resources=clusters,verbs=get;list;watch;create;update;patch;delete
Expand Down Expand Up @@ -55,6 +58,9 @@ func (r *ClusterReconciler) Reconcile(ctx context.Context, request ctrl.Request)
Reconciler: r,
CreateSATokenSecret: r.CreateSATokenSecret,
DefaultCreationPolicy: r.DefaultCreationPolicy,
DefaultDeletionPolicy: r.DefaultDeletionPolicy,
UseVault: r.UseVault,
UseDeletionProtection: r.DeleteProtection,
}

steps := []pipeline.Step{
Expand Down
2 changes: 1 addition & 1 deletion controllers/gitrepo/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func CreateOrUpdate(obj pipeline.Object, data *pipeline.Context) pipeline.Result

if template.DeletionPolicy == "" {
if obj.GetDeletionPolicy() == "" {
template.DeletionPolicy = pipeline.GetDefaultDeletionPolicy()
template.DeletionPolicy = data.DefaultDeletionPolicy
} else {
template.DeletionPolicy = obj.GetDeletionPolicy()
}
Expand Down
3 changes: 3 additions & 0 deletions controllers/gitrepo_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ type GitRepoReconciler struct {

// MaxReconcileInterval is the maximum time between two reconciliations.
MaxReconcileInterval time.Duration

DeleteProtection bool
}

//+kubebuilder:rbac:groups=syn.tools,resources=gitrepos,verbs=get;list;watch;create;update;patch;delete
Expand Down Expand Up @@ -62,6 +64,7 @@ func (r *GitRepoReconciler) Reconcile(ctx context.Context, request ctrl.Request)
FinalizerName: synv1alpha1.FinalizerName,
Reconciler: r,
DefaultCreationPolicy: r.DefaultCreationPolicy,
UseDeletionProtection: r.DeleteProtection,
}

steps := []pipeline.Step{
Expand Down
8 changes: 3 additions & 5 deletions controllers/tenant/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package tenant

import (
"fmt"
"os"

synv1alpha1 "github.com/projectsyn/lieutenant-operator/api/v1alpha1"
"github.com/projectsyn/lieutenant-operator/git/manager"
Expand Down Expand Up @@ -59,15 +58,14 @@ func updateTenantGitRepo(obj pipeline.Object, data *pipeline.Context) pipeline.R
return pipeline.Result{}
}

func setGlobalGitRepoURL(obj pipeline.Object, _ *pipeline.Context) pipeline.Result {
func setGlobalGitRepoURL(obj pipeline.Object, data *pipeline.Context) pipeline.Result {
instance, ok := obj.(*synv1alpha1.Tenant)
if !ok {
return pipeline.Result{Err: fmt.Errorf("object is not a tenant")}
}

defaultGlobalGitRepoURL := os.Getenv(DefaultGlobalGitRepoURL)
if len(instance.Spec.GlobalGitRepoURL) == 0 && len(defaultGlobalGitRepoURL) > 0 {
instance.Spec.GlobalGitRepoURL = defaultGlobalGitRepoURL
if len(instance.Spec.GlobalGitRepoURL) == 0 && len(data.DefaultGlobalGitRepoUrl) > 0 {
instance.Spec.GlobalGitRepoURL = data.DefaultGlobalGitRepoUrl
}
return pipeline.Result{}
}
21 changes: 14 additions & 7 deletions controllers/tenant_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ type TenantReconciler struct {

CreateSATokenSecret bool
DefaultCreationPolicy synv1alpha1.CreationPolicy
DefaultDeletionPolicy synv1alpha1.DeletionPolicy

DefaultGlobalGitRepoUrl string
DeleteProtection bool
}

//+kubebuilder:rbac:groups=syn.tools,resources=tenants,verbs=get;list;watch;create;update;patch;delete
Expand All @@ -52,13 +56,16 @@ func (r *TenantReconciler) Reconcile(ctx context.Context, request ctrl.Request)
}

data := &pipeline.Context{
Context: ctx,
Client: r.Client,
Log: reqLogger,
FinalizerName: "",
Reconciler: r,
CreateSATokenSecret: r.CreateSATokenSecret,
DefaultCreationPolicy: r.DefaultCreationPolicy,
Context: ctx,
Client: r.Client,
Log: reqLogger,
FinalizerName: "",
Reconciler: r,
CreateSATokenSecret: r.CreateSATokenSecret,
DefaultCreationPolicy: r.DefaultCreationPolicy,
DefaultDeletionPolicy: r.DefaultDeletionPolicy,
DefaultGlobalGitRepoUrl: r.DefaultGlobalGitRepoUrl,
UseDeletionProtection: r.DeleteProtection,
}

steps := []pipeline.Step{
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ require (
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kouhin/envflag v0.0.0-20150818174321-0e9a86061649 // indirect
github.com/leosayous21/go-azure-msi v0.0.0-20210509193526-19353bedcfc8 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kouhin/envflag v0.0.0-20150818174321-0e9a86061649 h1:l95EUBxc0iMtMeam3pHFb9jko9ntaLYe2Nc+2evKElM=
github.com/kouhin/envflag v0.0.0-20150818174321-0e9a86061649/go.mod h1:BT0PpXv8Y4EL/WUsQmYsQ2FSB9HwQXIuvY+pElZVdFg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
Expand Down
111 changes: 48 additions & 63 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"flag"
"fmt"
"os"
"strconv"
"time"

// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
Expand All @@ -23,6 +22,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/metrics"
"sigs.k8s.io/controller-runtime/pkg/metrics/server"

"github.com/kouhin/envflag"
synv1alpha1 "github.com/projectsyn/lieutenant-operator/api/v1alpha1"
"github.com/projectsyn/lieutenant-operator/controllers"
operatorMetrics "github.com/projectsyn/lieutenant-operator/metrics"
Expand All @@ -34,19 +34,6 @@ var (
setupLog = ctrl.Log.WithName("setup")
)

const (
// WatchNamespaceEnvVar is the constant for env variable WATCH_NAMESPACE
// which specifies the Namespace to watch.
// An empty value means the operator is running with cluster scope.
watchNamespaceEnvVar = "WATCH_NAMESPACE"
// createSAEnvVar is the constant for the env variable which indicates
// whether to create ServiceAccount token secrets
createSATokenEnvVar = "LIEUTENANT_CREATE_SERVICEACCOUNT_TOKEN_SECRET"
// createSAEnvVar is the constant for the env variable which indicates
// the default creation policy for git repositories
defaultCreationPolicy = "DEFAULT_CREATION_POLICY"
)

func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))

Expand All @@ -61,33 +48,42 @@ func main() {
var enableLeaderElection bool
var probeAddr string
var gitRepoMaxReconcileInterval time.Duration

var skipVaultSetup bool
var defaultDeletionPolicy string
var defaultCreationPolicy string
var useDeleteProtection bool
var defGlobalGitRepoUrl string
var watchNamespace string
var createSaTokenSecret bool
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.DurationVar(&gitRepoMaxReconcileInterval, "git-repo-max-reconcile-interval", 3*time.Hour, "The maximum time between reconciliations of GitRepos.")
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
flag.BoolVar(&skipVaultSetup, "skip-vault-setup", false, "Set to `true` in order to skip vault setup.")
flag.StringVar(&defaultDeletionPolicy, "default-deletion-policy", "Archive", "Default deletion policy for git repos. Can be `Delete`, `Retain` or `Archive`.")
flag.StringVar(&defaultCreationPolicy, "default-creation-policy", "Create", "Default creation policy for git repos. Can be `Create` or `Adopt`.")
flag.BoolVar(&useDeleteProtection, "lieutenant-delete-protection", false, "Whether to enable deletion protection.")
flag.StringVar(&defGlobalGitRepoUrl, "default-global-git-repo-url", "", "Default URL for global git repo; used if global git repo isn't explicitly configured.")
flag.StringVar(&watchNamespace, "watch-namespace", "default", "The namespace which should be watched by the operator")
flag.BoolVar(&createSaTokenSecret, "lieutenant-create-serviceaccount-token-secret", false, "Whether Lieutenant should create ServiceAccount token secrets")
opts := zap.Options{
Development: true,
}
opts.BindFlags(flag.CommandLine)
flag.Parse()

ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))

watchNamespace, err := getWatchNamespace()
err := envflag.Parse()
if err != nil {
setupLog.Error(err, "unable to get WatchNamespace, "+
"the manager will watch and manage resources in all namespaces")
// The setupLog is not working yet at this point; resort to fmt.Printf
fmt.Printf("unable to parse flags and environment variables: %s", err.Error())
os.Exit(1)
}

createSATokenSecret, err := getCreateSATokenSecret()
if err != nil {
setupLog.Error(err, "unable to get TokenSecret flag, "+
"the operator won't manage ServiceAccount token secrets.")
}
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))

creationPolicy := getDefaultCreationPolicy()
creationPolicy := getDefaultCreationPolicy(defaultCreationPolicy)
deletionPolicy := getDefaultDeletionPolicy(defaultDeletionPolicy)

mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
Expand Down Expand Up @@ -133,8 +129,11 @@ func main() {
if err = (&controllers.ClusterReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
CreateSATokenSecret: createSATokenSecret,
CreateSATokenSecret: createSaTokenSecret,
DefaultCreationPolicy: creationPolicy,
DefaultDeletionPolicy: deletionPolicy,
DeleteProtection: useDeleteProtection,
UseVault: !skipVaultSetup,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Cluster")
os.Exit(1)
Expand All @@ -143,17 +142,20 @@ func main() {
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
DefaultCreationPolicy: creationPolicy,

MaxReconcileInterval: gitRepoMaxReconcileInterval,
DeleteProtection: useDeleteProtection,
MaxReconcileInterval: gitRepoMaxReconcileInterval,
}).SetupWithManager(ctx, mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "GitRepo")
os.Exit(1)
}
if err = (&controllers.TenantReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
CreateSATokenSecret: createSATokenSecret,
DefaultCreationPolicy: creationPolicy,
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
CreateSATokenSecret: createSaTokenSecret,
DefaultCreationPolicy: creationPolicy,
DefaultDeletionPolicy: deletionPolicy,
DefaultGlobalGitRepoUrl: defGlobalGitRepoUrl,
DeleteProtection: useDeleteProtection,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Tenant")
os.Exit(1)
Expand All @@ -176,40 +178,23 @@ func main() {
}
}

// getWatchNamespace returns the Namespace the operator should be watching for changes
func getWatchNamespace() (string, error) {

ns, found := os.LookupEnv(watchNamespaceEnvVar)
if !found {
return "", fmt.Errorf("environment variable '%s' not found", watchNamespaceEnvVar)
}
return ns, nil
}

// getCreateSATokenSecret returns a boolean indicating whether the operator should manage ServiceAccount token secrets
func getCreateSATokenSecret() (bool, error) {
value, found := os.LookupEnv(createSATokenEnvVar)
if !found {
return false, fmt.Errorf("environment variable '%s' not found", createSATokenEnvVar)
}
create, err := strconv.ParseBool(value)
if err != nil {
return false, fmt.Errorf("unable to parse '%s': %v", value, err)
}
return create, nil
}

// getDefaultCreationPolicy returns to fallback creation policy for git repositories
func getDefaultCreationPolicy() synv1alpha1.CreationPolicy {
p, found := os.LookupEnv(defaultCreationPolicy)
if !found {
return synv1alpha1.CreatePolicy
}
cp := synv1alpha1.CreationPolicy(p)
func getDefaultCreationPolicy(stringArg string) synv1alpha1.CreationPolicy {
cp := synv1alpha1.CreationPolicy(stringArg)
switch cp {
case synv1alpha1.CreatePolicy, synv1alpha1.AdoptPolicy:
return cp
default:
return synv1alpha1.CreatePolicy
}
}

func getDefaultDeletionPolicy(stringArg string) synv1alpha1.DeletionPolicy {
cp := synv1alpha1.DeletionPolicy(stringArg)
switch cp {
case synv1alpha1.DeletePolicy, synv1alpha1.RetainPolicy, synv1alpha1.ArchivePolicy:
return cp
default:
return synv1alpha1.ArchivePolicy
}
}
22 changes: 13 additions & 9 deletions pipeline/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,19 @@ type Object interface {

// Context contains additional data about the CRD being processed.
type Context struct {
Context context.Context
FinalizerName string
Client client.Client
Log logr.Logger
Deleted bool
originalObject Object
Reconciler reconcile.Reconciler
CreateSATokenSecret bool
DefaultCreationPolicy synv1alpha1.CreationPolicy
Context context.Context
FinalizerName string
Client client.Client
Log logr.Logger
Deleted bool
originalObject Object
Reconciler reconcile.Reconciler
CreateSATokenSecret bool
DefaultCreationPolicy synv1alpha1.CreationPolicy
DefaultDeletionPolicy synv1alpha1.DeletionPolicy
DefaultGlobalGitRepoUrl string
UseVault bool
UseDeletionProtection bool
}

// Result indicates whether the current execution should be aborted and
Expand Down
18 changes: 1 addition & 17 deletions pipeline/steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package pipeline

import (
"fmt"
"os"
"strconv"

"errors"
Expand All @@ -15,27 +14,12 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

func GetDefaultDeletionPolicy() synv1alpha1.DeletionPolicy {
policy := synv1alpha1.DeletionPolicy(os.Getenv("DEFAULT_DELETION_POLICY"))
switch policy {
case synv1alpha1.ArchivePolicy, synv1alpha1.DeletePolicy, synv1alpha1.RetainPolicy:
return policy
default:
return synv1alpha1.ArchivePolicy
}
}

func addDeletionProtection(instance Object, data *Context) Result {
if data.Deleted {
return Result{}
}

config := os.Getenv(protectionSettingEnvVar)

protected, err := strconv.ParseBool(config)
if err != nil {
protected = true
}
protected := data.UseDeletionProtection

if protected {
annotations := instance.GetAnnotations()
Expand Down
Loading

0 comments on commit 704dc7d

Please sign in to comment.