Skip to content

Commit 363e697

Browse files
feature: Support Dynamic namespaces using Labels (#3299)
* Add labels flag and create namespace watcher when present * Create namespaced watchers dynamically for simple case * Handle unwatched app protect resources * Add dynamic watchers to externaldns and cert-manager controllers * Add initial python tests * Add app protect waf tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add python tests for cert-manager and external-dns * Add helm config and docs * Update logging for new and deleted watched namespaces * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent e67d1b8 commit 363e697

23 files changed

+1287
-148
lines changed

cmd/nginx-ingress/flags.go

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"github.com/golang/glog"
1313
api_v1 "k8s.io/api/core/v1"
14+
"k8s.io/apimachinery/pkg/labels"
1415
"k8s.io/apimachinery/pkg/util/validation"
1516
)
1617

@@ -27,15 +28,18 @@ var (
2728
The Ingress Controller does not start NGINX and does not write any generated NGINX configuration files to disk`)
2829

2930
watchNamespace = flag.String("watch-namespace", api_v1.NamespaceAll,
30-
`Comma separated list of namespaces the Ingress Controller should watch for resources. By default the Ingress Controller watches all namespaces`)
31+
`Comma separated list of namespaces the Ingress Controller should watch for resources. By default the Ingress Controller watches all namespaces. Mutually exclusive with "watch-namespace-label".`)
3132

3233
watchNamespaces []string
3334

3435
watchSecretNamespace = flag.String("watch-secret-namespace", "",
35-
`Comma separated list of namespaces the Ingress Controller should watch for secrets. If this arg is not configured, the Ingress Controller watches the same namespaces for all resources. See "watch-namespace". `)
36+
`Comma separated list of namespaces the Ingress Controller should watch for secrets. If this arg is not configured, the Ingress Controller watches the same namespaces for all resources. See "watch-namespace" and "watch-namespace-label". `)
3637

3738
watchSecretNamespaces []string
3839

40+
watchNamespaceLabel = flag.String("watch-namespace-label", "",
41+
`Configures the Ingress Controller to watch only those namespaces with label foo=bar. By default the Ingress Controller watches all namespaces. Mutually exclusive with "watch-namespace". `)
42+
3943
nginxConfigMaps = flag.String("nginx-configmaps", "",
4044
`A ConfigMap resource for customizing NGINX configuration. If a ConfigMap is set,
4145
but the Ingress Controller is not able to fetch it from Kubernetes API, the Ingress Controller will fail to start.
@@ -192,17 +196,7 @@ func parseFlags() {
192196

193197
initialChecks()
194198

195-
watchNamespaces = strings.Split(*watchNamespace, ",")
196-
glog.Infof("Namespaces watched: %v", watchNamespaces)
197-
198-
if len(*watchSecretNamespace) > 0 {
199-
watchSecretNamespaces = strings.Split(*watchSecretNamespace, ",")
200-
} else {
201-
// empty => default to watched namespaces
202-
watchSecretNamespaces = watchNamespaces
203-
}
204-
205-
glog.Infof("Namespaces watched for secrets: %v", watchSecretNamespaces)
199+
validateWatchedNamespaces()
206200

207201
validationChecks()
208202

@@ -295,6 +289,42 @@ func initialChecks() {
295289
}
296290
}
297291

292+
func validateWatchedNamespaces() {
293+
if *watchNamespace != "" && *watchNamespaceLabel != "" {
294+
glog.Fatal("watch-namespace and -watch-namespace-label are mutually exclusive")
295+
}
296+
297+
watchNamespaces = strings.Split(*watchNamespace, ",")
298+
299+
if *watchNamespace != "" {
300+
glog.Infof("Namespaces watched: %v", watchNamespaces)
301+
namespacesNameValidationError := validateNamespaceNames(watchNamespaces)
302+
if namespacesNameValidationError != nil {
303+
glog.Fatalf("Invalid values for namespaces: %v", namespacesNameValidationError)
304+
}
305+
}
306+
307+
if len(*watchSecretNamespace) > 0 {
308+
watchSecretNamespaces = strings.Split(*watchSecretNamespace, ",")
309+
glog.Infof("Namespaces watched for secrets: %v", watchSecretNamespaces)
310+
namespacesNameValidationError := validateNamespaceNames(watchSecretNamespaces)
311+
if namespacesNameValidationError != nil {
312+
glog.Fatalf("Invalid values for secret namespaces: %v", namespacesNameValidationError)
313+
}
314+
} else {
315+
// empty => default to watched namespaces
316+
watchSecretNamespaces = watchNamespaces
317+
}
318+
319+
if *watchNamespaceLabel != "" {
320+
var err error
321+
_, err = labels.Parse(*watchNamespaceLabel)
322+
if err != nil {
323+
glog.Fatalf("Unable to parse label %v for watch namespace label: %v", *watchNamespaceLabel, err)
324+
}
325+
}
326+
}
327+
298328
// validationChecks checks the values for various flags
299329
func validationChecks() {
300330
healthStatusURIValidationError := validateLocation(*healthStatusURI)
@@ -307,16 +337,6 @@ func validationChecks() {
307337
glog.Fatalf("Invalid value for leader-election-lock-name: %v", statusLockNameValidationError)
308338
}
309339

310-
namespacesNameValidationError := validateNamespaceNames(watchNamespaces)
311-
if namespacesNameValidationError != nil {
312-
glog.Fatalf("Invalid values for namespaces: %v", namespacesNameValidationError)
313-
}
314-
315-
namespacesNameValidationError = validateNamespaceNames(watchSecretNamespaces)
316-
if namespacesNameValidationError != nil {
317-
glog.Fatalf("Invalid values for secret namespaces: %v", namespacesNameValidationError)
318-
}
319-
320340
statusPortValidationError := validatePort(*nginxStatusPort)
321341
if statusPortValidationError != nil {
322342
glog.Fatalf("Invalid value for nginx-status-port: %v", statusPortValidationError)

cmd/nginx-ingress/main.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,7 @@ func main() {
5353

5454
validateIngressClass(kubeClient)
5555

56-
checkNamespaceExists(kubeClient, watchNamespaces)
57-
58-
checkNamespaceExists(kubeClient, watchSecretNamespaces)
56+
checkNamespaces(kubeClient)
5957

6058
dynClient, confClient := createCustomClients(config)
6159

@@ -160,6 +158,7 @@ func main() {
160158
CertManagerEnabled: *enableCertManager,
161159
ExternalDNSEnabled: *enableExternalDNS,
162160
IsIPV6Disabled: *disableIPV6,
161+
WatchNamespaceLabel: *watchNamespaceLabel,
163162
}
164163

165164
lbc := k8s.NewLoadBalancerController(lbcInput)
@@ -243,6 +242,25 @@ func validateIngressClass(kubeClient kubernetes.Interface) {
243242
}
244243
}
245244

245+
func checkNamespaces(kubeClient kubernetes.Interface) {
246+
if *watchNamespaceLabel != "" {
247+
// bootstrap the watched namespace list
248+
var newWatchNamespaces []string
249+
nsList, err := kubeClient.CoreV1().Namespaces().List(context.TODO(), meta_v1.ListOptions{LabelSelector: *watchNamespaceLabel})
250+
if err != nil {
251+
glog.Errorf("error when getting Namespaces with the label selector %v: %v", watchNamespaceLabel, err)
252+
}
253+
for _, ns := range nsList.Items {
254+
newWatchNamespaces = append(newWatchNamespaces, ns.Name)
255+
}
256+
watchNamespaces = newWatchNamespaces
257+
glog.Infof("Namespaces watched using label %v: %v", *watchNamespaceLabel, watchNamespaces)
258+
} else {
259+
checkNamespaceExists(kubeClient, watchNamespaces)
260+
}
261+
checkNamespaceExists(kubeClient, watchSecretNamespaces)
262+
}
263+
246264
func checkNamespaceExists(kubeClient kubernetes.Interface, namespaces []string) {
247265
for _, ns := range namespaces {
248266
if ns != "" {

deployments/helm-chart/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,9 @@ Parameter | Description | Default
186186
`controller.replicaCount` | The number of replicas of the Ingress Controller deployment. | 1
187187
`controller.ingressClass` | A class of the Ingress Controller. An IngressClass resource with the name equal to the class must be deployed. Otherwise, the Ingress Controller will fail to start. The Ingress Controller only processes resources that belong to its class - i.e. have the "ingressClassName" field resource equal to the class. The Ingress Controller processes all the VirtualServer/VirtualServerRoute/TransportServer resources that do not have the "ingressClassName" field for all versions of kubernetes. | nginx
188188
`controller.setAsDefaultIngress` | New Ingresses without an `"ingressClassName"` field specified will be assigned the class specified in `controller.ingressClass`. | false
189-
`controller.watchNamespace` | Comma separated list of namespaces the Ingress Controller should watch for resources. By default the Ingress Controller watches all namespaces. Please note that if configuring multiple namespaces using the Helm cli `--set` option, the string needs to wrapped in double quotes and the commas escaped using a backslash - e.g. `--set controller.watchNamespace="default\,nginx-ingress"`. | ""
190-
`controller.watchSecretNamespace` | Comma separated list of namespaces the Ingress Controller should watch for resources of type Secret. If this arg is not configured, the Ingress Controller watches the same namespaces for all resources. See `watch-namespace`. Please note that if configuring multiple namespaces using the Helm cli `--set` option, the string needs to wrapped in double quotes and the commas escaped using a backslash - e.g. `--set controller.watchSecretNamespace="default\,nginx-ingress"`. | ""
189+
`controller.watchNamespace` | Comma separated list of namespaces the Ingress Controller should watch for resources. By default the Ingress Controller watches all namespaces. Mutually exclusive with `controller.watchNamespaceLabel`. Please note that if configuring multiple namespaces using the Helm cli `--set` option, the string needs to wrapped in double quotes and the commas escaped using a backslash - e.g. `--set controller.watchNamespace="default\,nginx-ingress"`. | ""
190+
`controller.watchNamespaceLabel` | Configures the Ingress Controller to watch only those namespaces with label foo=bar. By default the Ingress Controller watches all namespaces. Mutually exclusive with `controller.watchNamespace`. | ""
191+
`controller.watchSecretNamespace` | Comma separated list of namespaces the Ingress Controller should watch for resources of type Secret. If this arg is not configured, the Ingress Controller watches the same namespaces for all resources. See `controller.watchNamespace` and `controller.watchNamespaceLabel`. Please note that if configuring multiple namespaces using the Helm cli `--set` option, the string needs to wrapped in double quotes and the commas escaped using a backslash - e.g. `--set controller.watchSecretNamespace="default\,nginx-ingress"`. | ""
191192
`controller.enableCustomResources` | Enable the custom resources. | true
192193
`controller.enablePreviewPolicies` | Enable preview policies. This parameter is deprecated. To enable OIDC Policies please use `controller.enableOIDC` instead. | false
193194
`controller.enableOIDC` | Enable OIDC policies. | false

deployments/helm-chart/templates/controller-daemonset.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ spec:
164164
{{- if .Values.controller.watchNamespace }}
165165
- -watch-namespace={{ .Values.controller.watchNamespace }}
166166
{{- end }}
167+
{{- if .Values.controller.watchNamespaceLabel }}
168+
- -watch-namespace-label={{ .Values.controller.watchNamespaceLabel }}
169+
{{- end }}
167170
{{- if .Values.controller.watchSecretNamespace }}
168171
- -watch-secret-namespace={{ .Values.controller.watchSecretNamespace }}
169172
{{- end }}

deployments/helm-chart/templates/controller-deployment.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ spec:
167167
{{- if .Values.controller.watchNamespace }}
168168
- -watch-namespace={{ .Values.controller.watchNamespace }}
169169
{{- end }}
170+
{{- if .Values.controller.watchNamespaceLabel }}
171+
- -watch-namespace-label={{ .Values.controller.watchNamespaceLabel }}
172+
{{- end }}
170173
{{- if .Values.controller.watchSecretNamespace }}
171174
- -watch-secret-namespace={{ .Values.controller.watchSecretNamespace }}
172175
{{- end }}

deployments/helm-chart/values.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,12 @@ controller:
198198
## New Ingresses without an ingressClassName field specified will be assigned the class specified in `controller.ingressClass`.
199199
setAsDefaultIngress: false
200200

201-
## Comma separated list of namespaces to watch for Ingress resources. By default the Ingress Controller watches all namespaces.
201+
## Comma separated list of namespaces to watch for Ingress resources. By default the Ingress Controller watches all namespaces. Mutually exclusive with "controller.watchNamespaceLabel".
202202
watchNamespace: ""
203203

204+
## Configures the Ingress Controller to watch only those namespaces with label foo=bar. By default the Ingress Controller watches all namespaces. Mutually exclusive with "controller.watchNamespace".
205+
watchNamespaceLabel: ""
206+
204207
## Comma separated list of namespaces to watch for Secret resources. By default the Ingress Controller watches all namespaces.
205208
watchSecretNamespace: ""
206209

docs/content/configuration/global-configuration/command-line-arguments.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,19 @@ A comma-separated list of pattern=N settings for file-filtered logging.
302302

303303
### -watch-namespace `<string>`
304304

305-
Comma separated list of namespaces the Ingress Controller should watch for resources. By default the Ingress Controller watches all namespaces.
305+
Comma separated list of namespaces the Ingress Controller should watch for resources. By default the Ingress Controller watches all namespaces. Mutually exclusive with "watch-namespace-label".
306+
&nbsp;
307+
<a name="cmdoption-watch-namespace-label"></a>
308+
309+
### -watch-namespace-label `<string>`
310+
311+
Configures the Ingress Controller to watch only those namespaces with label foo=bar. By default the Ingress Controller watches all namespaces. Mutually exclusive with "watch-namespace".
312+
&nbsp;
313+
<a name="cmdoption-watch-secret-namespace"></a>
314+
315+
### -watch-secret-namespace `<string>`
316+
317+
Comma separated list of namespaces the Ingress Controller should watch for secrets. If this arg is not configured, the Ingress Controller watches the same namespaces for all resources. See "watch-namespace" and "watch-namespace-label".
306318
&nbsp;
307319
<a name="cmdoption-enable-prometheus-metrics"></a>
308320

docs/content/installation/installation-with-helm.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,9 @@ The following tables lists the configurable parameters of the NGINX Ingress Cont
185185
|``controller.replicaCount`` | The number of replicas of the Ingress Controller deployment. | 1 |
186186
|``controller.ingressClass`` | A class of the Ingress Controller. An IngressClass resource with the name equal to the class must be deployed. Otherwise, the Ingress Controller will fail to start. The Ingress Controller only processes resources that belong to its class - i.e. have the "ingressClassName" field resource equal to the class. The Ingress Controller processes all the VirtualServer/VirtualServerRoute/TransportServer resources that do not have the "ingressClassName" field for all versions of kubernetes. | nginx |
187187
|``controller.setAsDefaultIngress`` | New Ingresses without an ingressClassName field specified will be assigned the class specified in `controller.ingressClass`. | false |
188-
|``controller.watchNamespace`` | Comma separated list of namespaces the Ingress Controller should watch for resources. By default the Ingress Controller watches all namespaces. Please note that if configuring multiple namespaces using the Helm cli `--set` option, the string needs to wrapped in double quotes and the commas escaped using a backslash - e.g. ``--set controller.watchNamespace="default\,nginx-ingress"``. | "" |
189-
|``controller.watchSecretNamespace`` | Comma separated list of namespaces the Ingress Controller should watch for resources of type Secret. If this arg is not configured, the Ingress Controller watches the same namespaces for all resources. See `watch-namespace`. Please note that if configuring multiple namespaces using the Helm cli `--set` option, the string needs to wrapped in double quotes and the commas escaped using a backslash - e.g. ``--set controller.watchSecretNamespace="default\,nginx-ingress"``. | "" |
188+
|``controller.watchNamespace`` | Comma separated list of namespaces the Ingress Controller should watch for resources. By default the Ingress Controller watches all namespaces. Mutually exclusive with `controller.watchNamespaceLabel`. Please note that if configuring multiple namespaces using the Helm cli `--set` option, the string needs to wrapped in double quotes and the commas escaped using a backslash - e.g. ``--set controller.watchNamespace="default\,nginx-ingress"``. | "" |
189+
|``controller.watchNamespaceLabel`` | Configures the Ingress Controller to watch only those namespaces with label foo=bar. By default the Ingress Controller watches all namespaces. Mutually exclusive with `controller.watchNamespace`. | "" |
190+
|``controller.watchSecretNamespace`` | Comma separated list of namespaces the Ingress Controller should watch for resources of type Secret. If this arg is not configured, the Ingress Controller watches the same namespaces for all resources. See `controller.watchNamespace` and `controller.watchNamespaceLabel`. Please note that if configuring multiple namespaces using the Helm cli `--set` option, the string needs to wrapped in double quotes and the commas escaped using a backslash - e.g. ``--set controller.watchSecretNamespace="default\,nginx-ingress"``. | "" |
190191
|``controller.enableCustomResources`` | Enable the custom resources. | true |
191192
|``controller.enablePreviewPolicies`` | Enable preview policies. This parameter is deprecated. To enable OIDC Policies please use ``controller.enableOIDC`` instead. | false |
192193
|``controller.enableOIDC`` | Enable OIDC policies. | false |

0 commit comments

Comments
 (0)