...

Source file src/github.com/chaos-mesh/chaos-mesh/cmd/chaos-controller-manager/main.go

Documentation: github.com/chaos-mesh/chaos-mesh/cmd/chaos-controller-manager

     1  // Copyright 2021 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  
    16  package main
    17  
    18  import (
    19  	"flag"
    20  	stdlog "log"
    21  	"net/http"
    22  	_ "net/http/pprof"
    23  	"os"
    24  
    25  	"github.com/99designs/gqlgen/graphql/handler"
    26  	"github.com/99designs/gqlgen/graphql/playground"
    27  	fxlogr "github.com/chaos-mesh/fx-logr"
    28  	"github.com/go-logr/logr"
    29  	"go.uber.org/fx"
    30  	authorizationv1 "k8s.io/client-go/kubernetes/typed/authorization/v1"
    31  	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
    32  	ctrl "sigs.k8s.io/controller-runtime"
    33  	controllermetrics "sigs.k8s.io/controller-runtime/pkg/metrics"
    34  	"sigs.k8s.io/controller-runtime/pkg/webhook"
    35  
    36  	"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
    37  	"github.com/chaos-mesh/chaos-mesh/cmd/chaos-controller-manager/provider"
    38  	"github.com/chaos-mesh/chaos-mesh/controllers"
    39  	ccfg "github.com/chaos-mesh/chaos-mesh/controllers/config"
    40  	"github.com/chaos-mesh/chaos-mesh/controllers/types"
    41  	"github.com/chaos-mesh/chaos-mesh/controllers/utils/chaosdaemon"
    42  	ctrlserver "github.com/chaos-mesh/chaos-mesh/pkg/ctrl"
    43  	grpcUtils "github.com/chaos-mesh/chaos-mesh/pkg/grpc"
    44  	"github.com/chaos-mesh/chaos-mesh/pkg/log"
    45  	"github.com/chaos-mesh/chaos-mesh/pkg/metrics"
    46  	"github.com/chaos-mesh/chaos-mesh/pkg/selector"
    47  	"github.com/chaos-mesh/chaos-mesh/pkg/version"
    48  	apiWebhook "github.com/chaos-mesh/chaos-mesh/pkg/webhook"
    49  )
    50  
    51  var (
    52  	printVersion bool
    53  
    54  	// TODO: create the logger through dependency injection
    55  	setupLog = ctrl.Log.WithName("setup")
    56  )
    57  
    58  func parseFlags() {
    59  	flag.BoolVar(&printVersion, "version", false, "print version information and exit")
    60  	flag.Parse()
    61  }
    62  
    63  func main() {
    64  	parseFlags()
    65  	version.PrintVersionInfo("Controller manager")
    66  	if printVersion {
    67  		os.Exit(0)
    68  	}
    69  
    70  	rootLogger, err := log.NewDefaultZapLogger()
    71  	if err != nil {
    72  		stdlog.Fatal("failed to create root logger", err)
    73  	}
    74  	log.ReplaceGlobals(rootLogger)
    75  	ctrl.SetLogger(rootLogger)
    76  	fxLogger := rootLogger.WithName("fx")
    77  
    78  	// set RPCTimeout config
    79  	grpcUtils.RPCTimeout = ccfg.ControllerCfg.RPCTimeout
    80  	app := fx.New(
    81  		fx.WithLogger(fxlogr.WithLogr(&fxLogger)),
    82  		fx.Supply(controllermetrics.Registry),
    83  		fx.Supply(rootLogger),
    84  		fx.Provide(metrics.NewChaosControllerManagerMetricsCollector),
    85  		fx.Provide(ctrlserver.New),
    86  		fx.Options(
    87  			provider.Module,
    88  			controllers.Module,
    89  			selector.Module,
    90  			types.ChaosObjects,
    91  			types.WebhookObjects,
    92  		),
    93  		fx.Invoke(Run),
    94  	)
    95  
    96  	app.Run()
    97  }
    98  
    99  // RunParams contains all the parameters needed to run the chaos-controller-manager
   100  type RunParams struct {
   101  	fx.In
   102  	// Mgr is the controller-runtime Manager to register controllers and webhooks to.
   103  	Mgr ctrl.Manager
   104  	// Logger is the root logger used in the application.
   105  	Logger logr.Logger
   106  	// AuthCli is the typed kubernetes authorization client. Required for the authentication webhooks.
   107  	AuthCli *authorizationv1.AuthorizationV1Client
   108  	// DaemonClientBuilder is the builder/factory for creating chaos daemon clients.
   109  	DaemonClientBuilder *chaosdaemon.ChaosDaemonClientBuilder
   110  	// MetricsCollector collects metrics for observability.
   111  	MetricsCollector *metrics.ChaosControllerManagerMetricsCollector
   112  	// CtrlServer is the graphql server for chaosctl.
   113  	CtrlServer *handler.Server
   114  
   115  	// Objs collects all the kinds of chaos custom resource objects that would be handled by the controller/reconciler.
   116  	Objs []types.Object `group:"objs"`
   117  	// WebhookObjs collects all the kinds of chaos custom resource objects that would be handled by the validation and mutation webhooks.
   118  	WebhookObjs []types.WebhookObject `group:"webhookObjs"`
   119  }
   120  
   121  // Run is the one of the entrypoints for fx application of chaos-controller-manager. It would bootstrap the
   122  // controller-runtime manager and register all the controllers and webhooks.
   123  // Please notice that Run is NOT the only one entrypoint, every other functions called by fx.Invoke are also entrypoint.
   124  func Run(params RunParams) error {
   125  	mgr := params.Mgr
   126  	authCli := params.AuthCli
   127  
   128  	var err error
   129  	for _, obj := range params.Objs {
   130  		if !ccfg.ShouldStartWebhook(obj.Name) {
   131  			continue
   132  		}
   133  
   134  		err = ctrl.NewWebhookManagedBy(mgr).
   135  			For(obj.Object).
   136  			Complete()
   137  		if err != nil {
   138  			return err
   139  		}
   140  	}
   141  
   142  	for _, obj := range params.WebhookObjs {
   143  		if !ccfg.ShouldStartWebhook(obj.Name) {
   144  			continue
   145  		}
   146  
   147  		err = ctrl.NewWebhookManagedBy(mgr).
   148  			For(obj.Object).
   149  			Complete()
   150  		if err != nil {
   151  			return err
   152  		}
   153  	}
   154  
   155  	if ccfg.ShouldStartWebhook("schedule") {
   156  		// setup schedule webhook
   157  		err = ctrl.NewWebhookManagedBy(mgr).
   158  			For(&v1alpha1.Schedule{}).
   159  			Complete()
   160  		if err != nil {
   161  			return err
   162  		}
   163  	}
   164  
   165  	if ccfg.ShouldStartWebhook("workflow") {
   166  		err = ctrl.NewWebhookManagedBy(mgr).
   167  			For(&v1alpha1.Workflow{}).
   168  			Complete()
   169  		if err != nil {
   170  			return err
   171  		}
   172  	}
   173  
   174  	setupLog.Info("Setting up webhook server")
   175  	hookServer := mgr.GetWebhookServer()
   176  
   177  	controllerRuntimeSignalHandler := ctrl.SetupSignalHandler()
   178  
   179  	if ccfg.ControllerCfg.PprofAddr != "0" {
   180  		go func() {
   181  			if err := http.ListenAndServe(ccfg.ControllerCfg.PprofAddr, nil); err != nil {
   182  				setupLog.Error(err, "unable to start pprof server")
   183  				os.Exit(1)
   184  			}
   185  		}()
   186  	}
   187  
   188  	if ccfg.ControllerCfg.CtrlAddr != "" {
   189  		go func() {
   190  			mutex := http.NewServeMux()
   191  			mutex.Handle("/", playground.Handler("GraphQL playground", "/query"))
   192  			mutex.Handle("/query", params.CtrlServer)
   193  			setupLog.Info("setup ctrlserver", "addr", ccfg.ControllerCfg.CtrlAddr)
   194  			setupLog.Error(http.ListenAndServe(ccfg.ControllerCfg.CtrlAddr, mutex), "unable to start ctrlserver")
   195  		}()
   196  	}
   197  
   198  	hookServer.Register("/validate-auth", &webhook.Admission{
   199  		Handler: apiWebhook.NewAuthValidator(ccfg.ControllerCfg.SecurityMode, authCli, mgr.GetScheme(),
   200  			ccfg.ControllerCfg.ClusterScoped, ccfg.ControllerCfg.TargetNamespace, ccfg.ControllerCfg.EnableFilterNamespace,
   201  			params.Logger.WithName("validate-auth"),
   202  		),
   203  	},
   204  	)
   205  
   206  	setupLog.Info("Starting manager")
   207  	if err := mgr.Start(controllerRuntimeSignalHandler); err != nil {
   208  		setupLog.Error(err, "unable to start manager")
   209  		// TODO: return the error instead of exit
   210  		os.Exit(1)
   211  	}
   212  
   213  	return nil
   214  }
   215