2021-01-05 18:55:51 +03:00
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
2021-01-05 17:46:53 +03:00
package main
import (
2021-05-11 09:36:57 +03:00
"context"
2021-01-05 17:46:53 +03:00
"flag"
"os"
2021-05-11 09:36:57 +03:00
"time"
2021-01-05 17:46:53 +03:00
2021-06-11 17:54:22 +03:00
"github.com/Azure/Orkestra/pkg/utils"
2021-02-03 05:49:42 +03:00
"github.com/Azure/Orkestra/pkg/workflow"
2021-06-11 17:54:22 +03:00
"github.com/Azure/Orkestra/pkg/registry"
2021-01-05 17:46:53 +03:00
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
orkestrav1alpha1 "github.com/Azure/Orkestra/api/v1alpha1"
"github.com/Azure/Orkestra/controllers"
2021-06-15 01:47:05 +03:00
v1alpha13 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
2021-04-28 22:40:59 +03:00
fluxhelmv2beta1 "github.com/fluxcd/helm-controller/api/v2beta1"
2021-01-05 17:46:53 +03:00
// +kubebuilder:scaffold:imports
)
2021-02-03 05:49:42 +03:00
const (
2021-04-06 09:07:50 +03:00
stagingRepoURLEnv = "STAGING_REPO_URL"
2021-02-03 05:49:42 +03:00
)
2021-01-05 17:46:53 +03:00
var (
scheme = runtime . NewScheme ( )
setupLog = ctrl . Log . WithName ( "setup" )
)
func init ( ) {
_ = clientgoscheme . AddToScheme ( scheme )
_ = orkestrav1alpha1 . AddToScheme ( scheme )
// +kubebuilder:scaffold:scheme
2021-02-03 05:49:42 +03:00
// Add Argo Workflow scheme to operator
2021-06-15 01:47:05 +03:00
_ = v1alpha13 . AddToScheme ( scheme )
2021-02-03 05:49:42 +03:00
// Add HelmRelease scheme to operator
2021-04-28 22:40:59 +03:00
_ = fluxhelmv2beta1 . AddToScheme ( scheme )
2021-01-05 17:46:53 +03:00
}
func main ( ) {
2021-08-05 07:40:09 +03:00
var (
metricsAddr string
enableLeaderElection bool
configPath string
stagingRepoURL string
tempChartStoreTargetDir string
disableRemediation bool
cleanupDownloadedCharts bool
debug bool
workflowParallelism int64
logLevel int
enableZapLogDevMode bool
)
2021-02-03 05:49:42 +03:00
2021-04-11 01:27:44 +03:00
flag . StringVar ( & metricsAddr , "metrics-addr" , ":8081" , "The address the metric endpoint binds to." )
2021-01-05 17:46:53 +03:00
flag . BoolVar ( & enableLeaderElection , "enable-leader-election" , false ,
"Enable leader election for controller manager. " +
"Enabling this will ensure there is only one active controller manager." )
2021-02-03 05:49:42 +03:00
flag . StringVar ( & configPath , "config" , "" , "The path to the controller config file" )
2021-04-06 09:07:50 +03:00
flag . StringVar ( & stagingRepoURL , "staging-repo-url" , "" , "The URL for the helm registry used for staging artifacts (ENV - STAGING_REPO_URL). NOTE: Flag overrides env value" )
2021-02-03 05:49:42 +03:00
flag . StringVar ( & tempChartStoreTargetDir , "chart-store-path" , "" , "The temporary storage path for the downloaded and staged chart artifacts" )
2021-03-24 01:29:32 +03:00
flag . BoolVar ( & disableRemediation , "disable-remediation" , false , "Disable the remediation (delete/rollback) of the workflow on failure (useful if you wish to debug failures in the workflow/executor container" )
flag . BoolVar ( & cleanupDownloadedCharts , "cleanup-downloaded-charts" , false , "Enable/disable the cleanup of the charts downloaded to the chart-store-path" )
2021-05-24 20:01:50 +03:00
flag . BoolVar ( & debug , "debug" , false , "Enable debug run of the appgroup controller" )
2021-04-23 20:05:23 +03:00
flag . Int64Var ( & workflowParallelism , "workflow-parallelism" , 10 , "Specifies the max number of workflow pods that can be executed in parallel" )
2021-05-24 20:01:50 +03:00
flag . IntVar ( & logLevel , "log-level" , 0 , "Log Level" )
2021-01-05 17:46:53 +03:00
flag . Parse ( )
2021-08-05 07:40:09 +03:00
if logLevel < 0 {
enableZapLogDevMode = true
2021-03-24 01:29:32 +03:00
}
2021-08-05 07:40:09 +03:00
ctrl . SetLogger ( zap . New ( zap . UseDevMode ( enableZapLogDevMode ) ) )
2021-03-24 01:29:32 +03:00
2021-05-11 09:36:57 +03:00
// Start the probe at the very beginning
2021-05-20 20:10:46 +03:00
probe , err := utils . ProbeHandler ( stagingRepoURL , "health" )
2021-05-11 09:36:57 +03:00
if err != nil {
setupLog . Error ( err , "unable to start readiness/liveness probes" , "controller" , "ApplicationGroup" )
os . Exit ( 1 )
}
probe . Start ( "8086" )
2021-05-24 20:01:50 +03:00
ctrl . Log . V ( logLevel )
2021-01-05 17:46:53 +03:00
mgr , err := ctrl . NewManager ( ctrl . GetConfigOrDie ( ) , ctrl . Options {
Scheme : scheme ,
MetricsBindAddress : metricsAddr ,
Port : 9443 ,
LeaderElection : enableLeaderElection ,
LeaderElectionID : "fdcf4a0d.azure.microsoft.com" ,
} )
if err != nil {
setupLog . Error ( err , "unable to start manager" )
os . Exit ( 1 )
}
2021-05-24 20:01:50 +03:00
// Grabbing the values based on the passed helm flags, these values change if we run in debug mode
stagingHelmURL , workflowHelmURL , tempChartStoreTargetDir := getValues ( stagingRepoURL , tempChartStoreTargetDir , debug )
if stagingHelmURL == "" {
2021-08-05 07:40:09 +03:00
s := os . Getenv ( stagingRepoURLEnv )
if s == "" {
2021-02-03 05:49:42 +03:00
setupLog . Error ( err , "staging repo URL must be set" )
os . Exit ( 1 )
}
2021-08-05 07:40:09 +03:00
stagingHelmURL = s
2021-02-03 05:49:42 +03:00
}
rc , err := registry . NewClient (
2021-04-15 21:32:15 +03:00
ctrl . Log ,
2021-02-03 05:49:42 +03:00
registry . TargetDir ( tempChartStoreTargetDir ) ,
)
if err != nil {
setupLog . Error ( err , "unable to create new registry client" , "controller" , "registry-client" )
os . Exit ( 1 )
}
2021-04-06 09:07:50 +03:00
// Register the staging helm repository/registry
2021-05-11 09:36:57 +03:00
// We perform retry on this so that we don't go into a crash loop backoff
retryChan := make ( chan bool )
retryCtx , cancel := context . WithTimeout ( context . Background ( ) , time . Minute * 5 )
go func ( ) {
for {
err = rc . AddRepo ( & registry . Config {
Name : "staging" ,
2021-05-24 20:01:50 +03:00
URL : stagingHelmURL ,
2021-05-11 09:36:57 +03:00
} )
if err != nil {
2021-08-05 07:40:09 +03:00
setupLog . Error ( err , "failed to add staging helm repo, retrying..." )
2021-05-11 09:36:57 +03:00
time . Sleep ( time . Second * 5 )
} else {
retryChan <- true
break
}
}
} ( )
select {
case <- retryChan :
cancel ( )
close ( retryChan )
setupLog . Info ( "successfully set-up the local chartmuseum helm repository" )
case <- retryCtx . Done ( ) :
cancel ( )
close ( retryChan )
setupLog . Error ( err , "pod timed out while trying to setup the helm chart museum..." )
2021-02-03 05:49:42 +03:00
os . Exit ( 1 )
}
2021-06-11 17:54:22 +03:00
baseLogger := ctrl . Log . WithName ( "controllers" ) . WithName ( "ApplicationGroup" )
2021-01-05 17:46:53 +03:00
if err = ( & controllers . ApplicationGroupReconciler {
2021-04-06 09:07:50 +03:00
Client : mgr . GetClient ( ) ,
2021-06-11 17:54:22 +03:00
Log : baseLogger ,
2021-04-06 09:07:50 +03:00
Scheme : mgr . GetScheme ( ) ,
RegistryClient : rc ,
StagingRepoName : "staging" ,
2021-06-11 17:54:22 +03:00
WorkflowClientBuilder : workflow . NewBuilder ( mgr . GetClient ( ) , baseLogger ) . WithStagingRepo ( workflowHelmURL ) . WithParallelism ( workflowParallelism ) . InNamespace ( workflow . GetNamespace ( ) ) ,
2021-04-06 09:07:50 +03:00
TargetDir : tempChartStoreTargetDir ,
Recorder : mgr . GetEventRecorderFor ( "appgroup-controller" ) ,
DisableRemediation : disableRemediation ,
CleanupDownloadedCharts : cleanupDownloadedCharts ,
2021-01-05 17:46:53 +03:00
} ) . SetupWithManager ( mgr ) ; err != nil {
setupLog . Error ( err , "unable to create controller" , "controller" , "ApplicationGroup" )
os . Exit ( 1 )
}
2021-09-24 19:38:42 +03:00
if err = ( & controllers . WorkflowStatusReconciler {
Client : mgr . GetClient ( ) ,
Log : baseLogger ,
Scheme : mgr . GetScheme ( ) ,
WorkflowClientBuilder : workflow . NewBuilder ( mgr . GetClient ( ) , baseLogger ) . WithStagingRepo ( workflowHelmURL ) . WithParallelism ( workflowParallelism ) . InNamespace ( workflow . GetNamespace ( ) ) ,
Recorder : mgr . GetEventRecorderFor ( "appgroup-controller" ) ,
} ) . SetupWithManager ( mgr ) ; err != nil {
setupLog . Error ( err , "unable to create controller" , "controller" , "WorkflowStatus" )
os . Exit ( 1 )
}
2021-01-05 17:46:53 +03:00
// +kubebuilder:scaffold:builder
setupLog . Info ( "starting manager" )
if err := mgr . Start ( ctrl . SetupSignalHandler ( ) ) ; err != nil {
setupLog . Error ( err , "problem running manager" )
os . Exit ( 1 )
}
}
2021-05-24 20:01:50 +03:00
// getValues returns the stagingRepoUrl unless the appGroup controller
// is run in a debug mode, then it returns the port forwarded url
func getValues ( stagingHelmURL , tempChartStoreTargetDir string , debug bool ) ( string , string , string ) {
if debug {
return "http://127.0.0.1:8080" , "http://orkestra-chartmuseum.orkestra:8080" , os . TempDir ( )
}
return stagingHelmURL , stagingHelmURL , tempChartStoreTargetDir
}