diff --git a/pkg/common/ingress/controller/controller.go b/pkg/common/ingress/controller/controller.go index aba0d8045..366883a87 100644 --- a/pkg/common/ingress/controller/controller.go +++ b/pkg/common/ingress/controller/controller.go @@ -70,10 +70,13 @@ type Configuration struct { WatchNamespace string ConfigMapName string + ReloadStrategy string + MaxOldConfigFiles int + ValidateConfig bool + ForceNamespaceIsolation bool WaitBeforeShutdown int AllowCrossNamespace bool - DisableNodeList bool DisablePodList bool DisableExternalName bool AnnPrefix []string diff --git a/pkg/common/ingress/controller/launch.go b/pkg/common/ingress/controller/launch.go index 8ae692aee..377614391 100644 --- a/pkg/common/ingress/controller/launch.go +++ b/pkg/common/ingress/controller/launch.go @@ -34,44 +34,66 @@ func NewIngressController(backend ingress.Controller) *GenericController { var ( flags = pflag.NewFlagSet("", pflag.ExitOnError) - apiserverHost = flags.String("apiserver-host", "", "The address of the Kubernetes Apiserver "+ - "to connect to in the format of protocol://address:port, e.g., "+ - "http://localhost:8080. If not specified, the assumption is that the binary runs inside a "+ - "Kubernetes cluster and local discovery is attempted.") + apiserverHost = flags.String("apiserver-host", "", + `The address of the Kubernetes API server to connect to, in the format of +protocol://address:port, e.g., http://localhost:8080. If not specified, the +assumption is that the binary runs inside a Kubernetes cluster and local +discovery is attempted.`) - kubeConfigFile = flags.String("kubeconfig", "", "Path to kubeconfig file with authorization and master location information.") + kubeConfigFile = flags.String("kubeconfig", "", + `Path to kubeconfig file with authorization and master location information.`) - disableAPIWarnings = flags.Bool("disable-api-warnings", false, "Declare to disable warnings from the API server.") + disableAPIWarnings = flags.Bool("disable-api-warnings", false, + `Disable warnings from the API server.`) defaultSvc = flags.String("default-backend-service", "", `Service used to serve a 404 page for the default backend. Takes the form - namespace/name. The controller uses the first node port of this Service for - the default backend.`) +namespace/name. The controller uses the first node port of this Service for the +default backend.`) - ingressClass = flags.String("ingress-class", "", + ingressClass = flags.String("ingress-class", "haproxy", `Name of the IngressClass to route through this controller.`) + reloadStrategy = flags.String("reload-strategy", "reusesocket", + `Name of the reload strategy. Options are: native or reusesocket`) + + maxOldConfigFiles = flags.Int("max-old-config-files", 0, + `Maximum number of old HAProxy timestamped config files to retain. Older files +are cleaned up. A value <= 0 indicates only a single non-timestamped config +file will be retained.`) + + validateConfig = flags.Bool("validate-config", false, + `Define if the resulting configuration files should be validated when a dynamic +update was applied. Default value is false, which means the validation will +only happen when HAProxy needs to be reloaded. If validation fails, HAProxy +Ingress will log the error and set the metric 'haproxyingress_update_success' +as failed (zero)`) + controllerClass = flags.String("controller-class", "", - `Defines an alternative controller name this controller should listen to. If empty, this controller will listen to - ingress resources whose controller's IngressClass is 'haproxy-ingress.github.io/controller'. Non empty values add a new /path, - eg controller-class=staging will make this controller look for 'haproxy-ingress.github.io/controller/staging'`) + `Defines an alternative controller name this controller should listen to. If +empty, this controller will listen to ingress resources whose controller's +IngressClass is 'haproxy-ingress.github.io/controller'. Non-empty values add a +new /path, e.g., controller-class=staging will make this controller look for +'haproxy-ingress.github.io/controller/staging'`) watchIngressWithoutClass = flags.Bool("watch-ingress-without-class", false, - `Defines if this controller should also listen to ingress resources that doesn't declare neither the - kubernetes.io/ingress.class annotation nor the .spec.ingressClassName field. Defaults to false`) + `Defines if this controller should also listen to ingress resources that don't +declare neither the kubernetes.io/ingress.class annotation nor the +.spec.ingressClassName field. Defaults to false`) - watchGateway = flags.Bool("watch-gateway", false, `Watch and parse resources from the Gateway API`) + watchGateway = flags.Bool("watch-gateway", false, + `Watch and parse resources from the Gateway API`) masterSocket = flags.String("master-socket", "", - `Defines the master CLI unix socket of an external HAProxy running in master-worker mode. - Defaults to use the embedded HAProxy if not declared.`) + `Defines the master CLI unix socket of an external HAProxy running in +master-worker mode. Defaults to use the embedded HAProxy if not declared.`) configMap = flags.String("configmap", "", `Name of the ConfigMap that contains the custom configuration to use`) acmeServer = flags.Bool("acme-server", false, - `Enables acme server. This server is used to receive and answer challenges from - Lets Encrypt or other acme implementations.`) + `Enables ACME server. This server is used to receive and answer challenges from +Let's Encrypt or other ACME implementations.`) acmeCheckPeriod = flags.Duration("acme-check-period", 24*time.Hour, `Time between checks of invalid or expiring certificates`) @@ -80,49 +102,48 @@ func NewIngressController(backend ingress.Controller) *GenericController { `Prefix of the election ID used to choose the acme leader`) acmeFailInitialDuration = flags.Duration("acme-fail-initial-duration", 5*time.Minute, - `The initial time to wait to retry sign a new certificate after a failure. - The time between retries will grow exponentially until 'acme-fail-max-duration'`) + `The initial time to wait to retry sign a new certificate after a failure. The +time between retries will grow exponentially until 'acme-fail-max-duration'`) acmeFailMaxDuration = flags.Duration("acme-fail-max-duration", 8*time.Hour, `The maximum time to wait after failing to sign a new certificate`) acmeSecretKeyName = flags.String("acme-secret-key-name", "acme-private-key", `Name and an optional namespace of the secret which will store the acme account - private key. If a namespace is not provided, the secret will be created in the same - namespace of the controller pod`) +private key. If a namespace is not provided, the secret will be created in the +same namespace of the controller pod`) acmeTokenConfigmapName = flags.String("acme-token-configmap-name", "acme-validation-tokens", `Name and an optional namespace of the configmap which will store acme tokens - used to answer the acme challenges. If a namespace is not provided, the secret will be created - in the same namespace of the controller pod`) +used to answer the acme challenges. If a namespace is not provided, the secret +will be created in the same namespace of the controller pod`) acmeTrackTLSAnn = flags.Bool("acme-track-tls-annotation", false, `Enable tracking of ingress objects annotated with 'kubernetes.io/tls-acme'`) - bucketsResponseTime = flags.Float64Slice("buckets-response-time", - []float64{.0005, .001, .002, .005, .01}, - `Configures the buckets of the histogram used to compute the response time of the haproxy's admin socket. - The response time unit is in seconds.`) + bucketsResponseTime = flags.Float64Slice("buckets-response-time", []float64{.0005, .001, .002, .005, .01}, + `Configures the buckets of the histogram used to compute the response time of +the haproxy's admin socket. The response time unit is in seconds.`) publishSvc = flags.String("publish-service", "", - `Service fronting the ingress controllers. Takes the form - namespace/name. The controller will set the endpoint records on the - ingress objects to reflect those on the service.`) + `Service fronting the ingress controllers. Takes the form namespace/name. The +controller will set the endpoint records on the ingress objects to reflect +those on the service.`) tcpConfigMapName = flags.String("tcp-services-configmap", "", - `Name of the ConfigMap that contains the definition of the TCP services to expose. - The key in the map indicates the external port to be used. The value is the name of the - service with the format namespace/serviceName and the port of the service could be a - number of the name of the port. - The ports 80 and 443 are not allowed as external ports. This ports are reserved for the backend`) + `Name of the ConfigMap that contains the definition of the TCP services to +expose. The key in the map indicates the external port to be used. The value is +the name of the service with the format namespace/serviceName and the port of +the service could be a number of the name of the port. The ports 80 and 443 are +not allowed as external ports. This ports are reserved for the backend`) annPrefix = flags.String("annotations-prefix", "haproxy-ingress.github.io,ingress.kubernetes.io", `Defines a comma-separated list of annotation prefix for ingress and service`) rateLimitUpdate = flags.Float32("rate-limit-update", 0.5, - `Maximum of updates per second this controller should perform. - Default is 0.5, which means wait 2 seconds between Ingress updates in order - to add more changes in a single reload`) + `Maximum of updates per second this controller should perform. Default is 0.5, +which means wait 2 seconds between Ingress updates in order to add more changes +in a single reload`) reloadInterval = flags.Duration("reload-interval", 0, `Minimal time between two consecutive HAProxy reloads. The default value is 0, @@ -133,85 +154,97 @@ the second reload will be enqueued until 30 seconds have passed from the first one, applying every new configuration changes made between this interval`) waitBeforeUpdate = flags.Duration("wait-before-update", 200*time.Millisecond, - `Amount of time to wait before start a reconciliation and update haproxy, - giving the time to receive all/most of the changes of a batch update.`) + `Amount of time to wait before start a reconciliation and update haproxy, giving +the time to receive all/most of the changes of a batch update.`) resyncPeriod = flags.Duration("sync-period", 600*time.Second, - `Relist and confirm cloud resources this often. Default is 10 minutes`) + `Configures the default resync period of Kubernetes' informer factory.`) watchNamespace = flags.String("watch-namespace", apiv1.NamespaceAll, `Namespace to watch for Ingress. Default is to watch all namespaces`) - healthzPort = flags.Int("healthz-port", 10254, "port for healthz endpoint.") + healthzPort = flags.Int("healthz-port", 10254, + `port for healthz endpoint.`) statsCollectProcPeriod = flags.Duration("stats-collect-processing-period", 500*time.Millisecond, - `Defines the interval between two consecutive readings of haproxy's Idle_pct. haproxy - updates Idle_pct every 500ms, which makes that the best configuration value. - Change to 0 (zero) to disable this metric.`) + `Defines the interval between two consecutive readings of haproxy's Idle_pct. +haproxy updates Idle_pct every 500ms, which makes that the best configuration +value. Change to 0 (zero) to disable this metric.`) - profiling = flags.Bool("profiling", true, `Enable profiling via web interface host:port/debug/pprof/`) + profiling = flags.Bool("profiling", true, + `Enable profiling via web interface host:port/debug/pprof/`) - defSSLCertificate = flags.String("default-ssl-certificate", "", `Name of the secret - that contains a SSL certificate to be used as default for a HTTPS catch-all server`) + defSSLCertificate = flags.String("default-ssl-certificate", "", + `Name of the secret that contains a SSL certificate to be used as +default for a HTTPS catch-all server`) verifyHostname = flags.Bool("verify-hostname", true, - `Defines if the controller should verify if the provided certificate is valid, ie, it's - SAN extension has the hostname. Default is true`) + `Defines if the controller should verify if the provided certificate is valid, +ie, it's SAN extension has the hostname.`) - defHealthzURL = flags.String("health-check-path", "/healthz", `Defines - the URL to be used as health check inside in the default server.`) + defHealthzURL = flags.String("health-check-path", "/healthz", + `Defines the URL to be used as health check inside in the default server.`) - updateStatus = flags.Bool("update-status", true, `Indicates if the - ingress controller should update the Ingress status IP/hostname. Default is true`) + updateStatus = flags.Bool("update-status", true, + `Indicates if the controller should update the 'status' attribute of all the +Ingress resources that this controller is tracking.`) - electionID = flags.String("election-id", "ingress-controller-leader", `Election id to use for status update.`) + electionID = flags.String("election-id", "ingress-controller-leader", + `Election id to be used for status update.`) forceIsolation = flags.Bool("force-namespace-isolation", false, - `Force namespace isolation. This flag is required to avoid the reference of secrets, - configmaps or the default backend service located in a different namespace than the specified - in the flag --watch-namespace.`) + `Force namespace isolation. This flag is required to avoid the reference of +secrets, configmaps or the default backend service located in a different +namespace than the specified in the flag --watch-namespace.`) - waitBeforeShutdown = flags.Int("wait-before-shutdown", 0, `Define time controller waits until it shuts down - when SIGTERM signal was received`) + waitBeforeShutdown = flags.Int("wait-before-shutdown", 0, + `Define time controller waits until it shuts down when SIGTERM signal was +received`) allowCrossNamespace = flags.Bool("allow-cross-namespace", false, - `Defines if the ingress controller can reference resources of another namespaces. - Cannot be used if force-namespace-isolation is true`) - - disableNodeList = flags.Bool("disable-node-list", false, - `Disable querying nodes. If --force-namespace-isolation is true, this should also be set.`) + `Defines if the ingress controller can reference resources of another +namespaces. Cannot be used if force-namespace-isolation is true`) disablePodList = flags.Bool("disable-pod-list", false, - `Defines if HAProxy Ingress should disable pod watch and in memory list. Pod list is - mandatory for drain-support (should not be disabled) and optional for blue/green.`) + `Defines if HAProxy Ingress should disable pod watch and in memory list. Pod +list is mandatory for drain-support (should not be disabled) and optional for +blue/green.`) disableExternalName = flags.Bool("disable-external-name", false, `Disables services of type ExternalName`) - updateStatusOnShutdown = flags.Bool("update-status-on-shutdown", true, `Indicates if the - ingress controller should update the Ingress status IP/hostname when the controller - is being stopped. Default is true`) + updateStatusOnShutdown = flags.Bool("update-status-on-shutdown", true, + `Indicates if the ingress controller should update the Ingress status +IP/hostname when the controller is being stopped.`) backendShards = flags.Int("backend-shards", 0, `Defines how much files should be used to configure the haproxy backends`) sortBackends = flags.Bool("sort-backends", false, - `Defines if backend's endpoints should be sorted by name. This option has less precedence than - --sort-endpoints-by if both are declared.`) + `Defines if backend's endpoints should be sorted by name. This option has less +precedence than --sort-endpoints-by if both are declared.`) sortEndpointsBy = flags.String("sort-endpoints-by", "", - `Defines how to sort backend's endpoints. Allowed values are: 'endpoint' - same k8s endpoint order (default); - 'name' - server/endpoint name; 'ip' - server/endpoint IP and port; 'random' - shuffle endpoints on every haproxy reload`) + `Defines how to sort backend's endpoints. Allowed values are: 'endpoint' - same +k8s endpoint order (default); 'name' - server/endpoint name; +'ip' - server/endpoint IP and port; 'random' - shuffle endpoints on every +haproxy reload`) useNodeInternalIP = flags.Bool("report-node-internal-ip-address", false, - `Defines if the nodes IP address to be returned in the ingress status should be the internal instead of the external IP address`) + `Defines if the nodes IP address to be returned in the ingress status should be +the internal instead of the external IP address`) showVersion = flags.Bool("version", false, `Shows release information about the Ingress controller`) + disableNodeList = flags.Bool("disable-node-list", false, + `DEPRECATED: This flag used to disable node listing due to missing permissions. +Actually node listing isn't needed and it is always disabled`) + ignoreIngressWithoutClass = flags.Bool("ignore-ingress-without-class", false, - `DEPRECATED, this option is ignored. Use --watch-ingress-without-class command-line option instead to define - if ingress without class should be tracked.`) + `DEPRECATED, this option is ignored. Use --watch-ingress-without-class +command-line option instead to define if ingress without class should be +tracked.`) ) flags.AddGoFlagSet(flag.CommandLine) @@ -252,10 +285,21 @@ one, applying every new configuration changes made between this interval`) glog.Infof("DEPRECATED: --ignore-ingress-without-class is now ignored and can be safely removed") } + if *disableNodeList { + glog.Infof("DEPRECATED: --disable-node-list is now ignored and can be safely removed") + } + if *watchGateway { glog.Infof("watching for Gateway API resources - --watch-gateway is true") } + if !(*reloadStrategy == "native" || *reloadStrategy == "reusesocket" || *reloadStrategy == "multibinder") { + glog.Fatalf("Unsupported reload strategy: %v", *reloadStrategy) + } + if *reloadStrategy == "multibinder" { + glog.Warningf("multibinder is deprecated, using reusesocket strategy instead. update your deployment configuration") + } + kubeClient, err := createApiserverClient(*apiserverHost, *kubeConfigFile, *disableAPIWarnings) if err != nil { handleFatalInitError(err) @@ -414,6 +458,9 @@ one, applying every new configuration changes made between this interval`) WatchGateway: *watchGateway, WatchNamespace: *watchNamespace, ConfigMapName: *configMap, + ReloadStrategy: *reloadStrategy, + MaxOldConfigFiles: *maxOldConfigFiles, + ValidateConfig: *validateConfig, TCPConfigMapName: *tcpConfigMapName, AnnPrefix: annPrefixList, DefaultSSLCertificate: *defSSLCertificate, @@ -425,7 +472,6 @@ one, applying every new configuration changes made between this interval`) ForceNamespaceIsolation: *forceIsolation, WaitBeforeShutdown: *waitBeforeShutdown, AllowCrossNamespace: *allowCrossNamespace, - DisableNodeList: *disableNodeList, DisablePodList: *disablePodList, DisableExternalName: *disableExternalName, UpdateStatusOnShutdown: *updateStatusOnShutdown, diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index fb7841086..6b1ef22a8 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -44,27 +44,24 @@ import ( // HAProxyController has internal data of a HAProxyController instance type HAProxyController struct { - instance haproxy.Instance - logger *logger - cache *k8scache - metrics *metrics - tracker convtypes.Tracker - stopCh chan struct{} - writeModelMutex sync.Mutex - ingressQueue utils.Queue - acmeQueue utils.Queue - reloadQueue utils.Queue - leaderelector types.LeaderElector - updateCount int - reloadCount int - controller *controller.GenericController - cfg *controller.Configuration - configMap *api.ConfigMap - converterOptions *convtypes.ConverterOptions - dynamicConfig *convtypes.DynamicConfig - reloadStrategy *string - maxOldConfigFiles *int - validateConfig *bool + instance haproxy.Instance + logger *logger + cache *k8scache + metrics *metrics + tracker convtypes.Tracker + stopCh chan struct{} + writeModelMutex sync.Mutex + ingressQueue utils.Queue + acmeQueue utils.Queue + reloadQueue utils.Queue + leaderelector types.LeaderElector + updateCount int + reloadCount int + controller *controller.GenericController + cfg *controller.Configuration + configMap *api.ConfigMap + converterOptions *convtypes.ConverterOptions + dynamicConfig *convtypes.DynamicConfig } // NewHAProxyController constructor @@ -95,9 +92,6 @@ func (hc *HAProxyController) Start() { } func (hc *HAProxyController) configController() { - if *hc.reloadStrategy == "multibinder" { - glog.Warningf("multibinder is deprecated, using reusesocket strategy instead. update your deployment configuration") - } hc.cfg = hc.controller.GetConfig() hc.stopCh = hc.controller.GetStopCh() hc.controller.SetNewCtrl(hc) @@ -133,11 +127,11 @@ func (hc *HAProxyController) configController() { ReloadQueue: hc.reloadQueue, LeaderElector: hc.leaderelector, Metrics: hc.metrics, - ReloadStrategy: *hc.reloadStrategy, - MaxOldConfigFiles: *hc.maxOldConfigFiles, + ReloadStrategy: hc.cfg.ReloadStrategy, + MaxOldConfigFiles: hc.cfg.MaxOldConfigFiles, SortEndpointsBy: hc.cfg.SortEndpointsBy, StopCh: hc.stopCh, - ValidateConfig: *hc.validateConfig, + ValidateConfig: hc.cfg.ValidateConfig, } hc.instance = haproxy.CreateInstance(hc.logger, instanceOptions) if err := hc.instance.ParseTemplates(); err != nil { @@ -297,24 +291,10 @@ func (hc *HAProxyController) UpdateIngressStatus(*networking.Ingress) []api.Load // ConfigureFlags allow to configure more flags before the parsing of // command line arguments func (hc *HAProxyController) ConfigureFlags(flags *pflag.FlagSet) { - hc.reloadStrategy = flags.String("reload-strategy", "reusesocket", - `Name of the reload strategy. Options are: native or reusesocket (default)`) - hc.maxOldConfigFiles = flags.Int("max-old-config-files", 0, - `Maximum old haproxy timestamped config files to allow before being cleaned up. A value <= 0 indicates a single non-timestamped config file will be used`) - hc.validateConfig = flags.Bool("validate-config", false, - `Define if the resulting configuration files should be validated when a dynamic update was applied. Default value is false, which means the validation will only happen when HAProxy need to be reloaded.`) - ingressClass := flags.Lookup("ingress-class") - if ingressClass != nil { - ingressClass.Value.Set("haproxy") - ingressClass.DefValue = "haproxy" - } } // OverrideFlags allows controller to override command line parameter flags func (hc *HAProxyController) OverrideFlags(flags *pflag.FlagSet) { - if !(*hc.reloadStrategy == "native" || *hc.reloadStrategy == "reusesocket" || *hc.reloadStrategy == "multibinder") { - glog.Fatalf("Unsupported reload strategy: %v", *hc.reloadStrategy) - } } // SetConfig receives the ConfigMap the user has configured diff --git a/pkg/controller/listers.go b/pkg/controller/listers.go index ef7355443..a5e381271 100644 --- a/pkg/controller/listers.go +++ b/pkg/controller/listers.go @@ -56,8 +56,7 @@ type listers struct { recorder record.EventRecorder running bool // - hasPodLister bool - hasNodeLister bool + hasPodLister bool // ingressLister listersnetworking.IngressLister ingressClassLister listersnetworking.IngressClassLister @@ -73,7 +72,6 @@ type listers struct { secretLister listerscore.SecretLister configMapLister listerscore.ConfigMapLister podLister listerscore.PodLister - nodeLister listerscore.NodeLister // ingressInformer cache.SharedInformer ingressClassInformer cache.SharedInformer @@ -89,7 +87,6 @@ type listers struct { secretInformer cache.SharedInformer configMapInformer cache.SharedInformer podInformer cache.SharedInformer - nodeInformer cache.SharedInformer } func createListers( @@ -137,13 +134,6 @@ func createListers( } else { l.createPodLister(localInformer.Core().V1().Pods()) } - if clusterWatch { - // ignoring --disable-node-list - l.createNodeLister(resourceInformer.Core().V1().Nodes()) - l.hasNodeLister = true - } else { - l.createNodeLister(localInformer.Core().V1().Nodes()) - } if watchGateway { var option informersgateway.SharedInformerOption @@ -216,7 +206,6 @@ func (l *listers) RunAsync(stopCh <-chan struct{}) { go l.secretInformer.Run(stopCh) go l.configMapInformer.Run(stopCh) go l.podInformer.Run(stopCh) - go l.nodeInformer.Run(stopCh) synced := cache.WaitForCacheSync(stopCh, l.ingressInformer.HasSynced, l.endpointInformer.HasSynced, @@ -224,7 +213,6 @@ func (l *listers) RunAsync(stopCh <-chan struct{}) { l.secretInformer.HasSynced, l.configMapInformer.HasSynced, l.podInformer.HasSynced, - l.nodeInformer.HasSynced, ) if synced { l.logger.Info("cache successfully synced") @@ -617,8 +605,3 @@ func (l *listers) createPodLister(informer informerscore.PodInformer) { }, }) } - -func (l *listers) createNodeLister(informer informerscore.NodeInformer) { - l.nodeLister = informer.Lister() - l.nodeInformer = informer.Informer() -}