| // Copyright Istio 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 main |
| |
| import ( |
| "fmt" |
| "os" |
| "strings" |
| "time" |
| ) |
| |
| import ( |
| ocprom "contrib.go.opencensus.io/exporter/prometheus" |
| "github.com/prometheus/client_golang/prometheus" |
| "github.com/spf13/cobra" |
| "go.opencensus.io/stats/view" |
| "istio.io/pkg/ctrlz" |
| "istio.io/pkg/log" |
| "istio.io/pkg/version" |
| _ "k8s.io/client-go/plugin/pkg/client/auth" |
| "sigs.k8s.io/controller-runtime/pkg/cache" |
| "sigs.k8s.io/controller-runtime/pkg/client/config" |
| "sigs.k8s.io/controller-runtime/pkg/manager" |
| "sigs.k8s.io/controller-runtime/pkg/manager/signals" |
| ctrlmetrics "sigs.k8s.io/controller-runtime/pkg/metrics" |
| ) |
| |
| import ( |
| root "github.com/apache/dubbo-go-pixiu/operator/cmd/mesh" |
| "github.com/apache/dubbo-go-pixiu/operator/pkg/apis" |
| "github.com/apache/dubbo-go-pixiu/operator/pkg/controller" |
| "github.com/apache/dubbo-go-pixiu/operator/pkg/controller/istiocontrolplane" |
| "github.com/apache/dubbo-go-pixiu/operator/pkg/metrics" |
| ) |
| |
| // Should match deploy/service.yaml |
| const ( |
| metricsHost = "0.0.0.0" |
| metricsPort int32 = 8383 |
| ) |
| |
| type serverArgs struct { |
| // force proceeds even if there are validation errors |
| force bool |
| } |
| |
| func addServerFlags(cmd *cobra.Command, args *serverArgs) { |
| cmd.PersistentFlags().BoolVar(&args.force, "force", false, root.ForceFlagHelpStr) |
| } |
| |
| func serverCmd() *cobra.Command { |
| loggingOptions := log.DefaultOptions() |
| introspectionOptions := ctrlz.DefaultOptions() |
| sArgs := &serverArgs{} |
| serverCmd := &cobra.Command{ |
| Use: "server", |
| Short: "Starts the Istio operator server", |
| Args: cobra.ExactArgs(0), |
| RunE: func(cmd *cobra.Command, args []string) error { |
| if err := log.Configure(loggingOptions); err != nil { |
| log.Errorf("Unable to configure logging: %v", err) |
| } |
| |
| if cs, err := ctrlz.Run(introspectionOptions, nil); err == nil { |
| defer cs.Close() |
| } else { |
| log.Errorf("Unable to initialize ControlZ: %v", err) |
| } |
| |
| run(sArgs) |
| return nil |
| }, |
| } |
| |
| loggingOptions.AttachCobraFlags(serverCmd) |
| introspectionOptions.AttachCobraFlags(serverCmd) |
| addServerFlags(serverCmd, sArgs) |
| |
| return serverCmd |
| } |
| |
| // getWatchNamespaces returns the namespaces the operator should be watching for changes |
| func getWatchNamespaces() ([]string, error) { |
| value, found := os.LookupEnv("WATCH_NAMESPACE") |
| if !found { |
| return nil, fmt.Errorf("WATCH_NAMESPACE must be set") |
| } |
| if value == "" { |
| return nil, nil |
| } |
| return strings.Split(value, ","), nil |
| } |
| |
| // getLeaderElectionNamespace returns the namespace in which the leader election configmap will be created |
| func getLeaderElectionNamespace() (string, bool) { |
| return os.LookupEnv("LEADER_ELECTION_NAMESPACE") |
| } |
| |
| // getRenewDeadline returns the renew deadline for active control plane to refresh leadership. |
| func getRenewDeadline() *time.Duration { |
| ddl, found := os.LookupEnv("RENEW_DEADLINE") |
| df := time.Second * 10 |
| if !found { |
| return &df |
| } |
| duration, err := time.ParseDuration(ddl) |
| if err != nil { |
| log.Errorf("Failed to parse renewDeadline: %v, use default value: %s", err, df.String()) |
| return &df |
| } |
| return &duration |
| } |
| |
| func run(sArgs *serverArgs) { |
| watchNamespaces, err := getWatchNamespaces() |
| if err != nil { |
| log.Fatalf("Failed to get watch namespaces: %v", err) |
| } |
| |
| leaderElectionNS, leaderElectionEnabled := getLeaderElectionNamespace() |
| if !leaderElectionEnabled { |
| log.Warn("Leader election namespace not set. Leader election is disabled. NOT APPROPRIATE FOR PRODUCTION USE!") |
| } |
| |
| // renewDeadline cannot be greater than leaseDuration |
| renewDeadline := getRenewDeadline() |
| leaseDuration := time.Duration(renewDeadline.Nanoseconds() * 2) |
| |
| // Get a config to talk to the apiserver |
| cfg, err := config.GetConfig() |
| if err != nil { |
| log.Fatalf("Could not get apiserver config: %v", err) |
| } |
| |
| var mgrOpt manager.Options |
| leaderElectionID := "istio-operator-lock" |
| if operatorRevision, found := os.LookupEnv("REVISION"); found && operatorRevision != "" { |
| leaderElectionID += "-" + operatorRevision |
| } |
| log.Infof("Leader election cm: %s", leaderElectionID) |
| if len(watchNamespaces) > 0 { |
| // Create MultiNamespacedCache with watched namespaces if it's not empty. |
| mgrOpt = manager.Options{ |
| NewCache: cache.MultiNamespacedCacheBuilder(watchNamespaces), |
| MetricsBindAddress: fmt.Sprintf("%s:%d", metricsHost, metricsPort), |
| LeaderElection: leaderElectionEnabled, |
| LeaderElectionNamespace: leaderElectionNS, |
| LeaderElectionID: leaderElectionID, |
| LeaseDuration: &leaseDuration, |
| RenewDeadline: renewDeadline, |
| } |
| } else { |
| // Create manager option for watching all namespaces. |
| mgrOpt = manager.Options{ |
| Namespace: "", |
| MetricsBindAddress: fmt.Sprintf("%s:%d", metricsHost, metricsPort), |
| LeaderElection: leaderElectionEnabled, |
| LeaderElectionNamespace: leaderElectionNS, |
| LeaderElectionID: leaderElectionID, |
| LeaseDuration: &leaseDuration, |
| RenewDeadline: renewDeadline, |
| } |
| } |
| |
| // Create a new Cmd to provide shared dependencies and start components |
| mgr, err := manager.New(cfg, mgrOpt) |
| if err != nil { |
| log.Fatalf("Could not create a controller manager: %v", err) |
| } |
| |
| log.Info("Creating operator metrics exporter") |
| exporter, err := ocprom.NewExporter(ocprom.Options{ |
| Registry: ctrlmetrics.Registry.(*prometheus.Registry), |
| Namespace: "istio_install_operator", |
| }) |
| if err != nil { |
| log.Warnf("Error while building exporter: %v", err) |
| } else { |
| view.RegisterExporter(exporter) |
| } |
| |
| log.Info("Registering Components.") |
| |
| // Setup Scheme for all resources |
| if err := apis.AddToScheme(mgr.GetScheme()); err != nil { |
| log.Fatalf("Could not add manager scheme: %v", err) |
| } |
| |
| // Setup all Controllers |
| options := &istiocontrolplane.Options{Force: sArgs.force} |
| if err := controller.AddToManager(mgr, options); err != nil { |
| log.Fatalf("Could not add all controllers to operator manager: %v", err) |
| } |
| |
| // Record version of operator in metrics |
| metrics.Version. |
| With(metrics.OperatorVersionLabel.Value(version.Info.String())). |
| Record(1.0) |
| |
| log.Info("Starting the Cmd.") |
| |
| // Start the Cmd |
| if err := mgr.Start(signals.SetupSignalHandler()); err != nil { |
| log.Fatalf("Manager exited non-zero: %v", err) |
| } |
| } |