Merge branch 'kubernetes:main' into pie
This commit is contained in:
commit
e87fd2273b
40 changed files with 1262 additions and 428 deletions
3
Makefile
3
Makefile
|
@ -201,7 +201,6 @@ dev-env-stop: ## Deletes local Kubernetes cluster created by kind.
|
|||
live-docs: ## Build and launch a local copy of the documentation website in http://localhost:8000
|
||||
@docker build ${PLATFORM_FLAG} ${PLATFORM} \
|
||||
--no-cache \
|
||||
$(MAC_DOCKER_FLAGS) \
|
||||
-t ingress-nginx-docs .github/actions/mkdocs
|
||||
@docker run ${PLATFORM_FLAG} ${PLATFORM} --rm -it \
|
||||
-p 8000:8000 \
|
||||
|
@ -241,6 +240,7 @@ release: ensure-buildx clean
|
|||
|
||||
docker buildx build \
|
||||
--no-cache \
|
||||
$(MAC_DOCKER_FLAGS) \
|
||||
--push \
|
||||
--pull \
|
||||
--progress plain \
|
||||
|
@ -253,6 +253,7 @@ release: ensure-buildx clean
|
|||
|
||||
docker buildx build \
|
||||
--no-cache \
|
||||
$(MAC_DOCKER_FLAGS) \
|
||||
--push \
|
||||
--pull \
|
||||
--progress plain \
|
||||
|
|
|
@ -38,7 +38,6 @@ the versions listed. Ingress-Nginx versions may work on older versions but the p
|
|||
|
||||
| Ingress-NGINX version | k8s supported version | Alpine Version | Nginx Version |
|
||||
|-----------------------|------------------------------|----------------|---------------|
|
||||
| v1.5.2 | 1.26, 1.25, 1.24, 1.23 | 3.17.2 | 1.21.6 |
|
||||
| v1.5.1 | 1.25, 1.24, 1.23 | 3.16.2 | 1.21.6 |
|
||||
| v1.4.0 | 1.25, 1.24, 1.23, 1.22 | 3.16.2 | 1.19.10† |
|
||||
| v1.3.1 | 1.24, 1.23, 1.22, 1.21, 1.20 | 3.16.2 | 1.19.10† |
|
||||
|
|
2
TAG
2
TAG
|
@ -1 +1 @@
|
|||
v1.5.1
|
||||
v1.6.0
|
|
@ -311,10 +311,12 @@ Kubernetes: `>=1.20.0-0`
|
|||
| controller.containerPort | object | `{"http":80,"https":443}` | Configures the ports that the nginx-controller listens on |
|
||||
| controller.customTemplate.configMapKey | string | `""` | |
|
||||
| controller.customTemplate.configMapName | string | `""` | |
|
||||
| controller.disablePathTypeValidation | bool | `false` | This configuration defines if Ingress Controller should validate pathType. If this is true, special characters will be allowed on paths of any pathType. If false, special characters are only allowed on paths with pathType = ImplementationSpecific |
|
||||
| controller.dnsConfig | object | `{}` | Optionally customize the pod dnsConfig. |
|
||||
| controller.dnsPolicy | string | `"ClusterFirst"` | Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'. By default, while using host network, name resolution uses the host's DNS. If you wish nginx-controller to keep resolving names inside the k8s network, use ClusterFirstWithHostNet. |
|
||||
| controller.electionID | string | `""` | Election ID to use for status update, by default it uses the controller name combined with a suffix of 'leader' |
|
||||
| controller.enableMimalloc | bool | `true` | Enable mimalloc as a drop-in replacement for malloc. # ref: https://github.com/microsoft/mimalloc # |
|
||||
| controller.enableTopologyAwareRouting | bool | `false` | This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-aware-hints="auto" Defaults to false |
|
||||
| controller.existingPsp | string | `""` | Use an existing PSP instead of creating one |
|
||||
| controller.extraArgs | object | `{}` | Additional command line arguments to pass to nginx-ingress-controller E.g. to specify the default SSL certificate you can use |
|
||||
| controller.extraContainers | list | `[]` | Additional containers to be added to the controller pod. See https://github.com/lemonldap-ng-controller/lemonldap-ng-controller as example. |
|
||||
|
@ -376,6 +378,7 @@ Kubernetes: `>=1.20.0-0`
|
|||
| controller.metrics.prometheusRule.rules | list | `[]` | |
|
||||
| controller.metrics.service.annotations | object | `{}` | |
|
||||
| controller.metrics.service.externalIPs | list | `[]` | List of IP addresses at which the stats-exporter service is available # Ref: https://kubernetes.io/docs/user-guide/services/#external-ips # |
|
||||
| controller.metrics.service.labels | object | `{}` | Labels to be added to the metrics service resource |
|
||||
| controller.metrics.service.loadBalancerSourceRanges | list | `[]` | |
|
||||
| controller.metrics.service.servicePort | int | `10254` | |
|
||||
| controller.metrics.service.type | string | `"ClusterIP"` | |
|
||||
|
|
|
@ -51,6 +51,9 @@
|
|||
{{- if .Values.controller.watchIngressWithoutClass }}
|
||||
- --watch-ingress-without-class=true
|
||||
{{- end }}
|
||||
{{- if .Values.controller.enableTopologyAwareRouting }}
|
||||
- --enable-topology-aware-routing=true
|
||||
{{- end }}
|
||||
{{- range $key, $value := .Values.controller.extraArgs }}
|
||||
{{- /* Accept keys without values or with false as value */}}
|
||||
{{- if eq ($value | quote | len) 2 }}
|
||||
|
|
|
@ -14,6 +14,7 @@ metadata:
|
|||
namespace: {{ .Release.Namespace }}
|
||||
data:
|
||||
allow-snippet-annotations: "{{ .Values.controller.allowSnippetAnnotations }}"
|
||||
disable-pathtype-validation: "{{ .Values.controller.disablePathTypeValidation }}"
|
||||
{{- if .Values.controller.addHeaders }}
|
||||
add-headers: {{ .Release.Namespace }}/{{ include "ingress-nginx.fullname" . }}-custom-add-headers
|
||||
{{- end }}
|
||||
|
|
|
@ -77,12 +77,21 @@ controller:
|
|||
# -- Process IngressClass per name (additionally as per spec.controller).
|
||||
ingressClassByName: false
|
||||
|
||||
# -- This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-aware-hints="auto"
|
||||
# Defaults to false
|
||||
enableTopologyAwareRouting: false
|
||||
|
||||
# -- This configuration defines if Ingress Controller should allow users to set
|
||||
# their own *-snippet annotations, otherwise this is forbidden / dropped
|
||||
# when users add those annotations.
|
||||
# Global snippets in ConfigMap are still respected
|
||||
allowSnippetAnnotations: true
|
||||
|
||||
# -- This configuration defines if Ingress Controller should validate pathType.
|
||||
# If this is true, special characters will be allowed on paths of any pathType. If
|
||||
# false, special characters are only allowed on paths with pathType = ImplementationSpecific
|
||||
disablePathTypeValidation: false
|
||||
|
||||
# -- Required for use with CNI based kubernetes installations (such as ones set up by kubeadm),
|
||||
# since CNI and hostport don't mix yet. Can be deprecated once https://github.com/kubernetes/kubernetes/issues/23920
|
||||
# is merged
|
||||
|
@ -700,6 +709,8 @@ controller:
|
|||
annotations: {}
|
||||
# prometheus.io/scrape: "true"
|
||||
# prometheus.io/port: "10254"
|
||||
# -- Labels to be added to the metrics service resource
|
||||
labels: {}
|
||||
|
||||
# clusterIP: ""
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ They are set in the container spec of the `ingress-nginx-controller` Deployment
|
|||
| `--enable-metrics` | Enables the collection of NGINX metrics. (default true) |
|
||||
| `--enable-ssl-chain-completion` | Autocomplete SSL certificate chains with missing intermediate CA certificates. Certificates uploaded to Kubernetes must have the "Authority Information Access" X.509 v3 extension for this to succeed. (default false)|
|
||||
| `--enable-ssl-passthrough` | Enable SSL Passthrough. (default false) |
|
||||
| `--enable-topology-aware-routing` | Enable topology aware hints feature, needs service object annotation service.kubernetes.io/topology-aware-hints sets to auto. (default false) |
|
||||
| `--health-check-path` | URL path of the health check endpoint. Configured inside the NGINX status server. All requests received on the port defined by the healthz-port parameter are forwarded internally to this path. (default "/healthz") |
|
||||
| `--health-check-timeout` | Time limit, in seconds, for a probe to health-check-path to succeed. (default 10) |
|
||||
| `--healthz-port` | Port to use for the healthz endpoint. (default 10254) |
|
||||
|
|
|
@ -355,56 +355,40 @@ Prometheus metrics are exposed on port 10254.
|
|||
|
||||
### Request metrics
|
||||
|
||||
* `nginx_ingress_controller_request_duration_seconds` Histogram
|
||||
|
||||
The request processing time in seconds (affected by client speed)
|
||||
|
||||
* `nginx_ingress_controller_request_duration_seconds` Histogram\
|
||||
The request processing (time elapsed between the first bytes were read from the client and the log write after the last bytes were sent to the client) time in seconds (affected by client speed).\
|
||||
nginx var: `request_time`
|
||||
|
||||
* `nginx_ingress_controller_response_duration_seconds` Histogram
|
||||
|
||||
The time spent on receiving the response from the upstream server (affected by client speed)
|
||||
|
||||
* `nginx_ingress_controller_response_duration_seconds` Histogram\
|
||||
The time spent on receiving the response from the upstream server in seconds (affected by client speed when the response is bigger than proxy buffers).\
|
||||
Note: can be up to several millis bigger than the `nginx_ingress_controller_request_duration_seconds` because of the different measuring method.
|
||||
nginx var: `upstream_response_time`
|
||||
|
||||
* `nginx_ingress_controller_header_duration_seconds` Histogram
|
||||
|
||||
The time spent on receiving first header from the upstream server
|
||||
|
||||
* `nginx_ingress_controller_header_duration_seconds` Histogram\
|
||||
The time spent on receiving first header from the upstream server\
|
||||
nginx var: `upstream_header_time`
|
||||
|
||||
* `nginx_ingress_controller_connect_duration_seconds` Histogram
|
||||
|
||||
The time spent on establishing a connection with the upstream server
|
||||
|
||||
* `nginx_ingress_controller_connect_duration_seconds` Histogram\
|
||||
The time spent on establishing a connection with the upstream server\
|
||||
nginx var: `upstream_connect_time`
|
||||
|
||||
* `nginx_ingress_controller_response_size` Histogram
|
||||
|
||||
The response length (including request line, header, and request body)
|
||||
|
||||
* `nginx_ingress_controller_response_size` Histogram\
|
||||
The response length (including request line, header, and request body)\
|
||||
nginx var: `bytes_sent`
|
||||
|
||||
* `nginx_ingress_controller_request_size` Histogram
|
||||
|
||||
The request length (including request line, header, and request body)
|
||||
|
||||
* `nginx_ingress_controller_request_size` Histogram\
|
||||
The request length (including request line, header, and request body)\
|
||||
nginx var: `request_length`
|
||||
|
||||
* `nginx_ingress_controller_requests` Counter
|
||||
|
||||
* `nginx_ingress_controller_requests` Counter\
|
||||
The total number of client requests
|
||||
|
||||
* `nginx_ingress_controller_bytes_sent` Histogram
|
||||
|
||||
The number of bytes sent to a client. **Deprecated**, use `nginx_ingress_controller_response_size`
|
||||
|
||||
* `nginx_ingress_controller_bytes_sent` Histogram\
|
||||
The number of bytes sent to a client. **Deprecated**, use `nginx_ingress_controller_response_size`\
|
||||
nginx var: `bytes_sent`
|
||||
|
||||
* `nginx_ingress_controller_ingress_upstream_latency_seconds` Summary
|
||||
|
||||
Upstream service latency per Ingress. **Deprecated**, use `nginx_ingress_controller_connect_duration_seconds`
|
||||
|
||||
* `nginx_ingress_controller_ingress_upstream_latency_seconds` Summary\
|
||||
Upstream service latency per Ingress. **Deprecated**, use `nginx_ingress_controller_connect_duration_seconds`\
|
||||
nginx var: `upstream_connect_time`
|
||||
|
||||
```
|
||||
|
@ -469,6 +453,8 @@ Prometheus metrics are exposed on port 10254.
|
|||
# TYPE nginx_ingress_controller_ssl_certificate_info gauge
|
||||
# HELP nginx_ingress_controller_success Cumulative number of Ingress controller reload operations
|
||||
# TYPE nginx_ingress_controller_success counter
|
||||
# HELP nginx_ingress_controller_orphan_ingress Gauge reporting status of ingress orphanity, 1 indicates orphaned ingress. 'namespace' is the string used to identify namespace of ingress, 'ingress' for ingress name and 'type' for 'no-service' or 'no-endpoint' of orphanity
|
||||
# TYPE nginx_ingress_controller_orphan_ingress gauge
|
||||
```
|
||||
|
||||
### Admission metrics
|
||||
|
|
|
@ -62,7 +62,7 @@ The following table shows a configuration option's name, type, and the default v
|
|||
|[hsts-max-age](#hsts-max-age)|string|"15724800"|
|
||||
|[hsts-preload](#hsts-preload)|bool|"false"|
|
||||
|[keep-alive](#keep-alive)|int|75|
|
||||
|[keep-alive-requests](#keep-alive-requests)|int|100|
|
||||
|[keep-alive-requests](#keep-alive-requests)|int|1000|
|
||||
|[large-client-header-buffers](#large-client-header-buffers)|string|"4 8k"|
|
||||
|[log-format-escape-none](#log-format-escape-none)|bool|"false"|
|
||||
|[log-format-escape-json](#log-format-escape-json)|bool|"false"|
|
||||
|
@ -103,7 +103,9 @@ The following table shows a configuration option's name, type, and the default v
|
|||
|[brotli-min-length](#brotli-min-length)|int|20|
|
||||
|[brotli-types](#brotli-types)|string|"application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/javascript text/plain text/x-component"|
|
||||
|[use-http2](#use-http2)|bool|"true"|
|
||||
|[gzip-disable](#gzip-disable)|string|""|
|
||||
|[gzip-level](#gzip-level)|int|1|
|
||||
|[gzip-min-length](#gzip-min-length)|int|256|
|
||||
|[gzip-types](#gzip-types)|string|"application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/javascript text/plain text/x-component"|
|
||||
|[worker-processes](#worker-processes)|string|`<Number of CPUs>`|
|
||||
|[worker-cpu-affinity](#worker-cpu-affinity)|string|""|
|
||||
|
@ -215,6 +217,8 @@ The following table shows a configuration option's name, type, and the default v
|
|||
|[service-upstream](#service-upstream)|bool|"false"|
|
||||
|[ssl-reject-handshake](#ssl-reject-handshake)|bool|"false"|
|
||||
|[debug-connections](#debug-connections)|[]string|"127.0.0.1,1.1.1.1/24"|
|
||||
|[disable-pathtype-validation](#disable-pathtype-validation)|bool|"false"|
|
||||
|[path-additional-allowed-chars](#path-additional-allowed-chars)|string|"^%$[](){}*+?"|
|
||||
|
||||
## add-headers
|
||||
|
||||
|
@ -694,7 +698,8 @@ _**default:**_ false
|
|||
## enable-brotli
|
||||
|
||||
Enables or disables compression of HTTP responses using the ["brotli" module](https://github.com/google/ngx_brotli).
|
||||
The default mime type list to compress is: `application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component`. _**default:**_ is disabled
|
||||
The default mime type list to compress is: `application/xml+rss application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component`.
|
||||
_**default:**_ false
|
||||
|
||||
> __Note:__ Brotli does not works in Safari < 11. For more information see [https://caniuse.com/#feat=brotli](https://caniuse.com/#feat=brotli)
|
||||
|
||||
|
@ -715,6 +720,10 @@ _**default:**_ `application/xml+rss application/atom+xml application/javascript
|
|||
|
||||
Enables or disables [HTTP/2](https://nginx.org/en/docs/http/ngx_http_v2_module.html) support in secure connections.
|
||||
|
||||
## gzip-disable
|
||||
|
||||
Disables [gzipping](http://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_disable) of responses for requests with "User-Agent" header fields matching any of the specified regular expressions.
|
||||
|
||||
## gzip-level
|
||||
|
||||
Sets the gzip Compression Level that will be used. _**default:**_ 1
|
||||
|
@ -1326,3 +1335,24 @@ _**default:**_ ""
|
|||
|
||||
_References:_
|
||||
[http://nginx.org/en/docs/ngx_core_module.html#debug_connection](http://nginx.org/en/docs/ngx_core_module.html#debug_connection)
|
||||
|
||||
## disable-pathtype-validation
|
||||
Ingress Controller validates the pathType, and only allows special characters on "path" if pathType is
|
||||
ImplementationSpecific.
|
||||
|
||||
The only characters allowed on ingresses with pathType not ImplementationSpecific
|
||||
will be 0-9, a-z, A-Z, "-", ".", "_", "~", "/".
|
||||
|
||||
If the validation is disabled, the [#path-additional-allowed-chars](#path-additional-allowed-chars) will
|
||||
be allowed on any pathType.
|
||||
|
||||
This behavior can be disabled, so special characters are accepted regardless of pathType
|
||||
_**default:**_ "false"
|
||||
|
||||
## path-additional-allowed-chars
|
||||
When validating path on Ingress resources, defines the additional set of special characters that
|
||||
will be allowed.
|
||||
|
||||
See also [#disable-pathtype-validation](#disable-pathtype-validation).
|
||||
|
||||
_**default:**_ "^%$[](){}*+?|"
|
||||
|
|
35
go.mod
35
go.mod
|
@ -30,14 +30,14 @@ require (
|
|||
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7
|
||||
gopkg.in/go-playground/pool.v3 v3.1.1
|
||||
gopkg.in/mcuadros/go-syslog.v2 v2.3.0
|
||||
k8s.io/api v0.25.4
|
||||
k8s.io/apiextensions-apiserver v0.25.0
|
||||
k8s.io/apimachinery v0.25.4
|
||||
k8s.io/apiserver v0.25.0
|
||||
k8s.io/cli-runtime v0.25.0
|
||||
k8s.io/client-go v0.25.4
|
||||
k8s.io/code-generator v0.25.0
|
||||
k8s.io/component-base v0.25.4
|
||||
k8s.io/api v0.26.0
|
||||
k8s.io/apiextensions-apiserver v0.26.0
|
||||
k8s.io/apimachinery v0.26.0
|
||||
k8s.io/apiserver v0.26.0
|
||||
k8s.io/cli-runtime v0.26.0
|
||||
k8s.io/client-go v0.26.0
|
||||
k8s.io/code-generator v0.26.0
|
||||
k8s.io/component-base v0.26.0
|
||||
k8s.io/klog/v2 v2.80.1
|
||||
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732
|
||||
sigs.k8s.io/controller-runtime v0.13.1
|
||||
|
@ -45,17 +45,7 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.12.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.27 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/BurntSushi/toml v1.0.0 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
|
@ -70,11 +60,10 @@ require (
|
|||
github.com/go-errors/errors v1.0.1 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/godbus/dbus/v5 v5.0.6 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/gomarkdown/markdown v0.0.0-20210514010506-3b9f47219fe7 // indirect
|
||||
|
@ -123,9 +112,9 @@ require (
|
|||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect
|
||||
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect
|
||||
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
|
||||
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.12.1 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect
|
||||
|
|
83
go.sum
83
go.sum
|
@ -19,10 +19,6 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf
|
|||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/compute v1.12.1 h1:gKVJMEyqV5c/UnpzjjQbo3Rjvvqpr9B1DFSbJC4OXr0=
|
||||
cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=
|
||||
cloud.google.com/go/compute/metadata v0.2.1 h1:efOwf5ymceDhK6PKMnnrTHP4pppY5L22mle96M1yP48=
|
||||
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
|
@ -35,30 +31,10 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
|||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest/autorest v0.11.27 h1:F3R3q42aWytozkV8ihzcgMO4OA4cuqr3bNlsEuF6//A=
|
||||
github.com/Azure/go-autorest/autorest v0.11.27/go.mod h1:7l8ybrIdUmGqZMTD0sRtAr8NvbHjfofbf8RSP2q7w7U=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.20 h1:gJ3E98kMpFB1MFqQCvA1yFab8vthOeD4VlFRQULxahg=
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.20/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw=
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU=
|
||||
github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
|
||||
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
|
||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU=
|
||||
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
|
@ -126,7 +102,6 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb
|
|||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
|
@ -135,8 +110,8 @@ github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
|
|||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM=
|
||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
|
||||
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
|
@ -147,9 +122,6 @@ github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
|
|||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
|
@ -362,7 +334,6 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
|
|||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
|
||||
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
|
@ -421,8 +392,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
|
||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
@ -471,7 +440,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
|
@ -490,7 +458,6 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
|||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
@ -511,7 +478,6 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -750,32 +716,31 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.25.4 h1:3YO8J4RtmG7elEgaWMb4HgmpS2CfY1QlaOz9nwB+ZSs=
|
||||
k8s.io/api v0.25.4/go.mod h1:IG2+RzyPQLllQxnhzD8KQNEu4c4YvyDTpSMztf4A0OQ=
|
||||
k8s.io/apiextensions-apiserver v0.25.0 h1:CJ9zlyXAbq0FIW8CD7HHyozCMBpDSiH7EdrSTCZcZFY=
|
||||
k8s.io/apiextensions-apiserver v0.25.0/go.mod h1:3pAjZiN4zw7R8aZC5gR0y3/vCkGlAjCazcg1me8iB/E=
|
||||
k8s.io/apimachinery v0.25.4 h1:CtXsuaitMESSu339tfhVXhQrPET+EiWnIY1rcurKnAc=
|
||||
k8s.io/apimachinery v0.25.4/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo=
|
||||
k8s.io/apiserver v0.25.0 h1:8kl2ifbNffD440MyvHtPaIz1mw4mGKVgWqM0nL+oyu4=
|
||||
k8s.io/apiserver v0.25.0/go.mod h1:BKwsE+PTC+aZK+6OJQDPr0v6uS91/HWxX7evElAH6xo=
|
||||
k8s.io/cli-runtime v0.25.0 h1:XBnTc2Fi+w818jcJGzhiJKQuXl8479sZ4FhtV5hVJ1Q=
|
||||
k8s.io/cli-runtime v0.25.0/go.mod h1:bHOI5ZZInRHhbq12OdUiYZQN8ml8aKZLwQgt9QlLINw=
|
||||
k8s.io/client-go v0.25.4 h1:3RNRDffAkNU56M/a7gUfXaEzdhZlYhoW8dgViGy5fn8=
|
||||
k8s.io/client-go v0.25.4/go.mod h1:8trHCAC83XKY0wsBIpbirZU4NTUpbuhc2JnI7OruGZw=
|
||||
k8s.io/code-generator v0.25.0 h1:QP8fJuXu882ztf6dsqJsso/Btm94pMd68TAZC1rE6KI=
|
||||
k8s.io/code-generator v0.25.0/go.mod h1:B6jZgI3DvDFAualltPitbYMQ74NjaCFxum3YeKZZ+3w=
|
||||
k8s.io/component-base v0.25.4 h1:n1bjg9Yt+G1C0WnIDJmg2fo6wbEU1UGMRiQSjmj7hNQ=
|
||||
k8s.io/component-base v0.25.4/go.mod h1:nnZJU8OP13PJEm6/p5V2ztgX2oyteIaAGKGMYb2L2cY=
|
||||
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185 h1:TT1WdmqqXareKxZ/oNXEUSwKlLiHzPMyB0t8BaFeBYI=
|
||||
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/api v0.26.0 h1:IpPlZnxBpV1xl7TGk/X6lFtpgjgntCg8PJ+qrPHAC7I=
|
||||
k8s.io/api v0.26.0/go.mod h1:k6HDTaIFC8yn1i6pSClSqIwLABIcLV9l5Q4EcngKnQg=
|
||||
k8s.io/apiextensions-apiserver v0.26.0 h1:Gy93Xo1eg2ZIkNX/8vy5xviVSxwQulsnUdQ00nEdpDo=
|
||||
k8s.io/apiextensions-apiserver v0.26.0/go.mod h1:7ez0LTiyW5nq3vADtK6C3kMESxadD51Bh6uz3JOlqWQ=
|
||||
k8s.io/apimachinery v0.26.0 h1:1feANjElT7MvPqp0JT6F3Ss6TWDwmcjLypwoPpEf7zg=
|
||||
k8s.io/apimachinery v0.26.0/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74=
|
||||
k8s.io/apiserver v0.26.0 h1:q+LqIK5EZwdznGZb8bq0+a+vCqdeEEe4Ux3zsOjbc4o=
|
||||
k8s.io/apiserver v0.26.0/go.mod h1:aWhlLD+mU+xRo+zhkvP/gFNbShI4wBDHS33o0+JGI84=
|
||||
k8s.io/cli-runtime v0.26.0 h1:aQHa1SyUhpqxAw1fY21x2z2OS5RLtMJOCj7tN4oq8mw=
|
||||
k8s.io/cli-runtime v0.26.0/go.mod h1:o+4KmwHzO/UK0wepE1qpRk6l3o60/txUZ1fEXWGIKTY=
|
||||
k8s.io/client-go v0.26.0 h1:lT1D3OfO+wIi9UFolCrifbjUUgu7CpLca0AD8ghRLI8=
|
||||
k8s.io/client-go v0.26.0/go.mod h1:I2Sh57A79EQsDmn7F7ASpmru1cceh3ocVT9KlX2jEZg=
|
||||
k8s.io/code-generator v0.26.0 h1:ZDY+7Gic9p/lACgD1G72gQg2CvNGeAYZTPIncv+iALM=
|
||||
k8s.io/code-generator v0.26.0/go.mod h1:OMoJ5Dqx1wgaQzKgc+ZWaZPfGjdRq/Y3WubFrZmeI3I=
|
||||
k8s.io/component-base v0.26.0 h1:0IkChOCohtDHttmKuz+EP3j3+qKmV55rM9gIFTXA7Vs=
|
||||
k8s.io/component-base v0.26.0/go.mod h1:lqHwlfV1/haa14F/Z5Zizk5QmzaVf23nQzCwVOQpfC8=
|
||||
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d h1:U9tB195lKdzwqicbJvyJeOXV7Klv+wNAWENRnXEGi08=
|
||||
k8s.io/gengo v0.0.0-20220902162205-c0856e24416d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4=
|
||||
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkIFQtZShWqoha7snGixVgEA=
|
||||
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU=
|
||||
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4=
|
||||
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E=
|
||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
|
||||
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs=
|
||||
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732 h1:SAElp8THCfmBdM+4lmWX5gebiSSkEr7PAYDVF91qpfg=
|
||||
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732/go.mod h1:lpvCfhqEHNJSSpG5R5A2EgsVzG8RTt4RfPoQuRAcDmg=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
|
|
|
@ -438,6 +438,11 @@ type Configuration struct {
|
|||
// Default: true
|
||||
UseHTTP2 bool `json:"use-http2,omitempty"`
|
||||
|
||||
// Disables gzipping of responses for requests with "User-Agent" header fields matching any of
|
||||
// the specified regular expressions.
|
||||
// http://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_disable
|
||||
GzipDisable string `json:"gzip-disable,omitempty"`
|
||||
|
||||
// gzip Compression Level that will be used
|
||||
GzipLevel int `json:"gzip-level,omitempty"`
|
||||
|
||||
|
@ -781,6 +786,17 @@ type Configuration struct {
|
|||
// http://nginx.org/en/docs/ngx_core_module.html#debug_connection
|
||||
// Default: ""
|
||||
DebugConnections []string `json:"debug-connections"`
|
||||
|
||||
// DisablePathTypeValidation allows the admin to disable the pathType validation.
|
||||
// If PathTypeValidation is enabled, the Controller will only allow alphanumeric
|
||||
// characters on path (0-9, a-z, A-Z, "-", ".", "_", "~", "/")
|
||||
DisablePathTypeValidation bool `json:"disable-pathtype-validation"`
|
||||
|
||||
// PathAdditionalAllowedChars allows the admin to specify what are the additional
|
||||
// characters allowed in case of pathType=ImplementationSpecific.
|
||||
// Case disable-pathtype-validation=true, this characters will be allowed on any path.
|
||||
// Defaults to: "^%$[](){}*+?"
|
||||
PathAdditionalAllowedChars string `json:"path-additional-allowed-chars"`
|
||||
}
|
||||
|
||||
// NewDefault returns the default nginx configuration
|
||||
|
@ -798,7 +814,6 @@ func NewDefault() Configuration {
|
|||
defGlobalExternalAuth := GlobalExternalAuth{"", "", "", "", "", append(defResponseHeaders, ""), "", "", "", []string{}, map[string]string{}, false}
|
||||
|
||||
cfg := Configuration{
|
||||
|
||||
AllowSnippetAnnotations: true,
|
||||
AllowBackendServerHeader: false,
|
||||
AnnotationValueWordBlocklist: "",
|
||||
|
@ -817,6 +832,8 @@ func NewDefault() Configuration {
|
|||
ClientHeaderTimeout: 60,
|
||||
ClientBodyBufferSize: "8k",
|
||||
ClientBodyTimeout: 60,
|
||||
DisablePathTypeValidation: false,
|
||||
PathAdditionalAllowedChars: "^%$[](){}*+?|",
|
||||
EnableUnderscoresInHeaders: false,
|
||||
ErrorLogLevel: errorLevel,
|
||||
UseForwardedHeaders: false,
|
||||
|
@ -839,7 +856,7 @@ func NewDefault() Configuration {
|
|||
GzipMinLength: 256,
|
||||
GzipTypes: gzipTypes,
|
||||
KeepAlive: 75,
|
||||
KeepAliveRequests: 100,
|
||||
KeepAliveRequests: 1000,
|
||||
LargeClientHeaderBuffers: "4 8k",
|
||||
LogFormatEscapeJSON: false,
|
||||
LogFormatStream: logFormatStream,
|
||||
|
|
|
@ -50,9 +50,12 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
defUpstreamName = "upstream-default-backend"
|
||||
defServerName = "_"
|
||||
rootLocation = "/"
|
||||
defUpstreamName = "upstream-default-backend"
|
||||
defServerName = "_"
|
||||
rootLocation = "/"
|
||||
emptyZone = ""
|
||||
orphanMetricLabelNoService = "no-service"
|
||||
orphanMetricLabelNoEndpoint = "no-endpoint"
|
||||
)
|
||||
|
||||
// Configuration contains all the settings required by an Ingress controller
|
||||
|
@ -131,6 +134,21 @@ type Configuration struct {
|
|||
DynamicConfigurationRetries int
|
||||
|
||||
DisableSyncEvents bool
|
||||
|
||||
EnableTopologyAwareRouting bool
|
||||
}
|
||||
|
||||
func getIngressPodZone(svc *apiv1.Service) string {
|
||||
svcKey := k8s.MetaNamespaceKey(svc)
|
||||
if svcZoneAnnotation, ok := svc.ObjectMeta.GetAnnotations()[apiv1.AnnotationTopologyAwareHints]; ok {
|
||||
if strings.ToLower(svcZoneAnnotation) == "auto" {
|
||||
if foundZone, ok := k8s.IngressNodeDetails.GetLabels()[apiv1.LabelTopologyZone]; ok {
|
||||
klog.V(3).Infof("Svc has topology aware annotation enabled, try to use zone %q where controller pod is running for Service %q ", foundZone, svcKey)
|
||||
return foundZone
|
||||
}
|
||||
}
|
||||
}
|
||||
return emptyZone
|
||||
}
|
||||
|
||||
// GetPublishService returns the Service used to set the load-balancer status of Ingresses.
|
||||
|
@ -307,6 +325,10 @@ func (n *NGINXController) CheckIngress(ing *networking.Ingress) error {
|
|||
|
||||
k8s.SetDefaultNGINXPathType(ing)
|
||||
|
||||
if err := utilingress.ValidateIngressPath(ing, cfg.DisablePathTypeValidation, cfg.PathAdditionalAllowedChars); err != nil {
|
||||
return fmt.Errorf("ingress contains invalid characters: %s", err)
|
||||
}
|
||||
|
||||
allIngresses := n.store.ListIngresses()
|
||||
|
||||
filter := func(toCheck *ingress.Ingress) bool {
|
||||
|
@ -429,6 +451,13 @@ func (n *NGINXController) getStreamServices(configmapName string, proto apiv1.Pr
|
|||
var endps []ingress.Endpoint
|
||||
/* #nosec */
|
||||
targetPort, err := strconv.Atoi(svcPort) // #nosec
|
||||
var zone string
|
||||
if n.cfg.EnableTopologyAwareRouting {
|
||||
zone = getIngressPodZone(svc)
|
||||
} else {
|
||||
zone = emptyZone
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
// not a port number, fall back to using port name
|
||||
klog.V(3).Infof("Searching Endpoints with %v port name %q for Service %q", proto, svcPort, nsName)
|
||||
|
@ -436,7 +465,7 @@ func (n *NGINXController) getStreamServices(configmapName string, proto apiv1.Pr
|
|||
sp := svc.Spec.Ports[i]
|
||||
if sp.Name == svcPort {
|
||||
if sp.Protocol == proto {
|
||||
endps = getEndpointsFromSlices(svc, &sp, proto, n.store.GetServiceEndpointsSlices)
|
||||
endps = getEndpointsFromSlices(svc, &sp, proto, zone, n.store.GetServiceEndpointsSlices)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -447,7 +476,7 @@ func (n *NGINXController) getStreamServices(configmapName string, proto apiv1.Pr
|
|||
sp := svc.Spec.Ports[i]
|
||||
if sp.Port == int32(targetPort) {
|
||||
if sp.Protocol == proto {
|
||||
endps = getEndpointsFromSlices(svc, &sp, proto, n.store.GetServiceEndpointsSlices)
|
||||
endps = getEndpointsFromSlices(svc, &sp, proto, zone, n.store.GetServiceEndpointsSlices)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -498,8 +527,13 @@ func (n *NGINXController) getDefaultUpstream() *ingress.Backend {
|
|||
upstream.Endpoints = append(upstream.Endpoints, n.DefaultEndpoint())
|
||||
return upstream
|
||||
}
|
||||
|
||||
endps := getEndpointsFromSlices(svc, &svc.Spec.Ports[0], apiv1.ProtocolTCP, n.store.GetServiceEndpointsSlices)
|
||||
var zone string
|
||||
if n.cfg.EnableTopologyAwareRouting {
|
||||
zone = getIngressPodZone(svc)
|
||||
} else {
|
||||
zone = emptyZone
|
||||
}
|
||||
endps := getEndpointsFromSlices(svc, &svc.Spec.Ports[0], apiv1.ProtocolTCP, zone, n.store.GetServiceEndpointsSlices)
|
||||
if len(endps) == 0 {
|
||||
klog.Warningf("Service %q does not have any active Endpoint", svcKey)
|
||||
endps = []ingress.Endpoint{n.DefaultEndpoint()}
|
||||
|
@ -827,7 +861,13 @@ func (n *NGINXController) getBackendServers(ingresses []*ingress.Ingress) ([]*in
|
|||
}
|
||||
|
||||
sp := location.DefaultBackend.Spec.Ports[0]
|
||||
endps := getEndpointsFromSlices(location.DefaultBackend, &sp, apiv1.ProtocolTCP, n.store.GetServiceEndpointsSlices)
|
||||
var zone string
|
||||
if n.cfg.EnableTopologyAwareRouting {
|
||||
zone = getIngressPodZone(location.DefaultBackend)
|
||||
} else {
|
||||
zone = emptyZone
|
||||
}
|
||||
endps := getEndpointsFromSlices(location.DefaultBackend, &sp, apiv1.ProtocolTCP, zone, n.store.GetServiceEndpointsSlices)
|
||||
// custom backend is valid only if contains at least one endpoint
|
||||
if len(endps) > 0 {
|
||||
name := fmt.Sprintf("custom-default-backend-%v-%v", location.DefaultBackend.GetNamespace(), location.DefaultBackend.GetName())
|
||||
|
@ -1018,8 +1058,16 @@ func (n *NGINXController) createUpstreams(data []*ingress.Ingress, du *ingress.B
|
|||
endp, err := n.serviceEndpoints(svcKey, port.String())
|
||||
if err != nil {
|
||||
klog.Warningf("Error obtaining Endpoints for Service %q: %v", svcKey, err)
|
||||
n.metricCollector.IncOrphanIngress(ing.Namespace, ing.Name, orphanMetricLabelNoService)
|
||||
continue
|
||||
}
|
||||
n.metricCollector.DecOrphanIngress(ing.Namespace, ing.Name, orphanMetricLabelNoService)
|
||||
|
||||
if len(endp) == 0 {
|
||||
n.metricCollector.IncOrphanIngress(ing.Namespace, ing.Name, orphanMetricLabelNoEndpoint)
|
||||
} else {
|
||||
n.metricCollector.DecOrphanIngress(ing.Namespace, ing.Name, orphanMetricLabelNoEndpoint)
|
||||
}
|
||||
upstreams[name].Endpoints = endp
|
||||
}
|
||||
|
||||
|
@ -1083,7 +1131,12 @@ func (n *NGINXController) serviceEndpoints(svcKey, backendPort string) ([]ingres
|
|||
if err != nil {
|
||||
return upstreams, err
|
||||
}
|
||||
|
||||
var zone string
|
||||
if n.cfg.EnableTopologyAwareRouting {
|
||||
zone = getIngressPodZone(svc)
|
||||
} else {
|
||||
zone = emptyZone
|
||||
}
|
||||
klog.V(3).Infof("Obtaining ports information for Service %q", svcKey)
|
||||
// Ingress with an ExternalName Service and no port defined for that Service
|
||||
if svc.Spec.Type == apiv1.ServiceTypeExternalName {
|
||||
|
@ -1092,7 +1145,7 @@ func (n *NGINXController) serviceEndpoints(svcKey, backendPort string) ([]ingres
|
|||
return upstreams, nil
|
||||
}
|
||||
servicePort := externalNamePorts(backendPort, svc)
|
||||
endps := getEndpointsFromSlices(svc, servicePort, apiv1.ProtocolTCP, n.store.GetServiceEndpointsSlices)
|
||||
endps := getEndpointsFromSlices(svc, servicePort, apiv1.ProtocolTCP, zone, n.store.GetServiceEndpointsSlices)
|
||||
if len(endps) == 0 {
|
||||
klog.Warningf("Service %q does not have any active Endpoint.", svcKey)
|
||||
return upstreams, nil
|
||||
|
@ -1109,7 +1162,7 @@ func (n *NGINXController) serviceEndpoints(svcKey, backendPort string) ([]ingres
|
|||
servicePort.TargetPort.String() == backendPort ||
|
||||
servicePort.Name == backendPort {
|
||||
|
||||
endps := getEndpointsFromSlices(svc, &servicePort, apiv1.ProtocolTCP, n.store.GetServiceEndpointsSlices)
|
||||
endps := getEndpointsFromSlices(svc, &servicePort, apiv1.ProtocolTCP, zone, n.store.GetServiceEndpointsSlices)
|
||||
if len(endps) == 0 {
|
||||
klog.Warningf("Service %q does not have any active Endpoint.", svcKey)
|
||||
}
|
||||
|
|
|
@ -201,6 +201,97 @@ func TestCheckIngress(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("when validating pathType", func(t *testing.T) {
|
||||
t.Run("When ingress contains invalid path and pathType validation is not disabled", func(t *testing.T) {
|
||||
nginx.store = fakeIngressStore{
|
||||
ingresses: []*ingress.Ingress{},
|
||||
configuration: ngx_config.Configuration{
|
||||
DisablePathTypeValidation: false,
|
||||
},
|
||||
}
|
||||
nginx.command = testNginxTestCommand{
|
||||
t: t,
|
||||
err: nil,
|
||||
expected: "",
|
||||
}
|
||||
nginx.cfg.IngressClassConfiguration = &ingressclass.IngressClassConfiguration{
|
||||
WatchWithoutClass: true,
|
||||
}
|
||||
ingPath := &networking.Ingress{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-ingress1",
|
||||
Namespace: "user-namespace1",
|
||||
Annotations: map[string]string{
|
||||
"kubernetes.io/ingress.class": "nginx",
|
||||
},
|
||||
},
|
||||
Spec: networking.IngressSpec{
|
||||
Rules: []networking.IngressRule{
|
||||
{
|
||||
Host: "example.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/xpto/(a+)",
|
||||
PathType: &pathTypePrefix,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if nginx.CheckIngress(ingPath) == nil {
|
||||
t.Errorf("invalid path on pathTypePrefix and validation enabled should return an error")
|
||||
}
|
||||
})
|
||||
t.Run("When ingress contains invalid path and pathType validation is disabled", func(t *testing.T) {
|
||||
nginx.store = fakeIngressStore{
|
||||
ingresses: []*ingress.Ingress{},
|
||||
configuration: ngx_config.Configuration{
|
||||
DisablePathTypeValidation: true,
|
||||
PathAdditionalAllowedChars: "^%$[](){}*+?|",
|
||||
},
|
||||
}
|
||||
nginx.command = testNginxTestCommand{
|
||||
t: t,
|
||||
err: nil,
|
||||
expected: "_,example.com",
|
||||
}
|
||||
|
||||
ingPath := &networking.Ingress{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-ingress2",
|
||||
Namespace: "user-namespace2",
|
||||
},
|
||||
Spec: networking.IngressSpec{
|
||||
Rules: []networking.IngressRule{
|
||||
{
|
||||
Host: "example.com",
|
||||
IngressRuleValue: networking.IngressRuleValue{
|
||||
HTTP: &networking.HTTPIngressRuleValue{
|
||||
Paths: []networking.HTTPIngressPath{
|
||||
{
|
||||
Path: "/example(/|$)(.*)",
|
||||
PathType: &pathTypePrefix,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if nginx.CheckIngress(ingPath) != nil {
|
||||
t.Errorf("invalid path on pathTypePrefix and validation disabled should not return an error: %s", nginx.CheckIngress(ingPath))
|
||||
}
|
||||
})
|
||||
})
|
||||
t.Run("when the class is the nginx one", func(t *testing.T) {
|
||||
ing.ObjectMeta.Annotations["kubernetes.io/ingress.class"] = "nginx"
|
||||
nginx.command = testNginxTestCommand{
|
||||
|
@ -2481,8 +2572,9 @@ func newDynamicNginxController(t *testing.T, setConfigMap func(string) *v1.Confi
|
|||
}
|
||||
|
||||
return &NGINXController{
|
||||
store: storer,
|
||||
cfg: config,
|
||||
command: NewNginxCommand(),
|
||||
store: storer,
|
||||
cfg: config,
|
||||
command: NewNginxCommand(),
|
||||
metricCollector: metric.DummyCollector{},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ import (
|
|||
)
|
||||
|
||||
// getEndpoints returns a list of Endpoint structs for a given service/target port combination.
|
||||
func getEndpointsFromSlices(s *corev1.Service, port *corev1.ServicePort, proto corev1.Protocol,
|
||||
func getEndpointsFromSlices(s *corev1.Service, port *corev1.ServicePort, proto corev1.Protocol, zoneForHints string,
|
||||
getServiceEndpointsSlices func(string) ([]*discoveryv1.EndpointSlice, error)) []ingress.Endpoint {
|
||||
|
||||
upsServers := []ingress.Endpoint{}
|
||||
|
@ -49,6 +49,7 @@ func getEndpointsFromSlices(s *corev1.Service, port *corev1.ServicePort, proto c
|
|||
processedUpstreamServers := make(map[string]struct{})
|
||||
|
||||
svcKey := k8s.MetaNamespaceKey(s)
|
||||
var useTopologyHints bool
|
||||
|
||||
// ExternalName services
|
||||
if s.Spec.Type == corev1.ServiceTypeExternalName {
|
||||
|
@ -111,12 +112,38 @@ func getEndpointsFromSlices(s *corev1.Service, port *corev1.ServicePort, proto c
|
|||
ports = append(ports, targetPort)
|
||||
}
|
||||
}
|
||||
useTopologyHints = false
|
||||
if zoneForHints != emptyZone {
|
||||
useTopologyHints = true
|
||||
// check if all endpointslices has zone hints
|
||||
for _, ep := range eps.Endpoints {
|
||||
if ep.Hints == nil || len(ep.Hints.ForZones) == 0 {
|
||||
useTopologyHints = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if useTopologyHints {
|
||||
klog.V(3).Infof("All endpoint slices has zone hint, using zone %q for Service %q", zoneForHints, svcKey)
|
||||
}
|
||||
}
|
||||
|
||||
for _, ep := range eps.Endpoints {
|
||||
if !(*ep.Conditions.Ready) {
|
||||
continue
|
||||
}
|
||||
epHasZone := false
|
||||
if useTopologyHints {
|
||||
for _, epzone := range ep.Hints.ForZones {
|
||||
if epzone.Name == zoneForHints {
|
||||
epHasZone = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ep.Hints
|
||||
if useTopologyHints && !epHasZone {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, epPort := range ports {
|
||||
for _, epAddress := range ep.Addresses {
|
||||
|
|
|
@ -33,6 +33,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
svc *corev1.Service
|
||||
port *corev1.ServicePort
|
||||
proto corev1.Protocol
|
||||
zone string
|
||||
fn func(string) ([]*discoveryv1.EndpointSlice, error)
|
||||
result []ingress.Endpoint
|
||||
}{
|
||||
|
@ -41,6 +42,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
nil,
|
||||
nil,
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return nil, nil
|
||||
},
|
||||
|
@ -51,6 +53,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
&corev1.Service{},
|
||||
nil,
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return nil, nil
|
||||
},
|
||||
|
@ -61,6 +64,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
&corev1.Service{},
|
||||
&corev1.ServicePort{Name: "default"},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{}, nil
|
||||
},
|
||||
|
@ -75,6 +79,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
},
|
||||
&corev1.ServicePort{Name: "default"},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{}, nil
|
||||
},
|
||||
|
@ -99,6 +104,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
TargetPort: intstr.FromInt(80),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{}, nil
|
||||
},
|
||||
|
@ -123,6 +129,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
TargetPort: intstr.FromInt(80),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{}, nil
|
||||
},
|
||||
|
@ -147,6 +154,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
TargetPort: intstr.FromInt(80),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{}, nil
|
||||
},
|
||||
|
@ -176,6 +184,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
TargetPort: intstr.FromInt(80),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{}, nil
|
||||
},
|
||||
|
@ -205,6 +214,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
TargetPort: intstr.FromInt(80),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{}, nil
|
||||
},
|
||||
|
@ -229,6 +239,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
TargetPort: intstr.FromInt(80),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return nil, fmt.Errorf("unexpected error")
|
||||
},
|
||||
|
@ -253,6 +264,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
TargetPort: intstr.FromInt(80),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@ -296,6 +308,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
TargetPort: intstr.FromInt(80),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@ -339,6 +352,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
TargetPort: intstr.FromString("port-1"),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@ -382,6 +396,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
TargetPort: intstr.FromInt(80),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@ -430,6 +445,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
TargetPort: intstr.FromInt(80),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@ -478,6 +494,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
TargetPort: intstr.FromString("port-1"),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{
|
||||
{
|
||||
|
@ -552,6 +569,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
TargetPort: intstr.FromString("port-1"),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{
|
||||
{
|
||||
|
@ -622,6 +640,7 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
TargetPort: intstr.FromString("port-1"),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@ -656,11 +675,251 @@ func TestGetEndpointsFromSlices(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"should return one endpoint which belongs to zone",
|
||||
&corev1.Service{
|
||||
Spec: corev1.ServiceSpec{
|
||||
Type: corev1.ServiceTypeClusterIP,
|
||||
ClusterIP: "1.1.1.1",
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Name: "default",
|
||||
TargetPort: intstr.FromString("port-1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
&corev1.ServicePort{
|
||||
Name: "port-1",
|
||||
TargetPort: intstr.FromString("port-1"),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"eu-west-1b",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{discoveryv1.LabelServiceName: "default"},
|
||||
},
|
||||
Endpoints: []discoveryv1.Endpoint{
|
||||
{
|
||||
Addresses: []string{"1.1.1.1"},
|
||||
Conditions: discoveryv1.EndpointConditions{
|
||||
Ready: &[]bool{true}[0],
|
||||
},
|
||||
Hints: &[]discoveryv1.EndpointHints{{
|
||||
ForZones: []discoveryv1.ForZone{{
|
||||
Name: "eu-west-1b",
|
||||
}},
|
||||
}}[0],
|
||||
},
|
||||
{
|
||||
Addresses: []string{"1.1.1.2"},
|
||||
Conditions: discoveryv1.EndpointConditions{
|
||||
Ready: &[]bool{true}[0],
|
||||
},
|
||||
Hints: &[]discoveryv1.EndpointHints{{
|
||||
ForZones: []discoveryv1.ForZone{{
|
||||
Name: "eu-west-1a",
|
||||
}},
|
||||
}}[0],
|
||||
},
|
||||
{
|
||||
Addresses: []string{"1.1.1.3"},
|
||||
Conditions: discoveryv1.EndpointConditions{
|
||||
Ready: &[]bool{true}[0],
|
||||
},
|
||||
Hints: &[]discoveryv1.EndpointHints{{
|
||||
ForZones: []discoveryv1.ForZone{{
|
||||
Name: "eu-west-1c",
|
||||
}},
|
||||
}}[0],
|
||||
},
|
||||
},
|
||||
Ports: []discoveryv1.EndpointPort{
|
||||
{
|
||||
Protocol: &[]corev1.Protocol{corev1.ProtocolTCP}[0],
|
||||
Port: &[]int32{80}[0],
|
||||
Name: &[]string{"port-1"}[0],
|
||||
},
|
||||
},
|
||||
}}, nil
|
||||
},
|
||||
[]ingress.Endpoint{
|
||||
{
|
||||
Address: "1.1.1.1",
|
||||
Port: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"should return all endpoints because one is missing zone hint",
|
||||
&corev1.Service{
|
||||
Spec: corev1.ServiceSpec{
|
||||
Type: corev1.ServiceTypeClusterIP,
|
||||
ClusterIP: "1.1.1.1",
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Name: "default",
|
||||
TargetPort: intstr.FromString("port-1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
&corev1.ServicePort{
|
||||
Name: "port-1",
|
||||
TargetPort: intstr.FromString("port-1"),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"eu-west-1b",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{discoveryv1.LabelServiceName: "default"},
|
||||
},
|
||||
Endpoints: []discoveryv1.Endpoint{
|
||||
{
|
||||
Addresses: []string{"1.1.1.1"},
|
||||
Conditions: discoveryv1.EndpointConditions{
|
||||
Ready: &[]bool{true}[0],
|
||||
},
|
||||
Hints: &[]discoveryv1.EndpointHints{{
|
||||
ForZones: []discoveryv1.ForZone{{
|
||||
Name: "eu-west-1b",
|
||||
}},
|
||||
}}[0],
|
||||
},
|
||||
{
|
||||
Addresses: []string{"1.1.1.2"},
|
||||
Conditions: discoveryv1.EndpointConditions{
|
||||
Ready: &[]bool{true}[0],
|
||||
},
|
||||
Hints: &[]discoveryv1.EndpointHints{{
|
||||
ForZones: []discoveryv1.ForZone{{
|
||||
Name: "eu-west-1b",
|
||||
}},
|
||||
}}[0],
|
||||
},
|
||||
{
|
||||
Addresses: []string{"1.1.1.3"},
|
||||
Conditions: discoveryv1.EndpointConditions{
|
||||
Ready: &[]bool{true}[0],
|
||||
},
|
||||
Hints: &[]discoveryv1.EndpointHints{{}}[0],
|
||||
},
|
||||
},
|
||||
Ports: []discoveryv1.EndpointPort{
|
||||
{
|
||||
Protocol: &[]corev1.Protocol{corev1.ProtocolTCP}[0],
|
||||
Port: &[]int32{80}[0],
|
||||
Name: &[]string{"port-1"}[0],
|
||||
},
|
||||
},
|
||||
}}, nil
|
||||
},
|
||||
[]ingress.Endpoint{
|
||||
{
|
||||
Address: "1.1.1.1",
|
||||
Port: "80",
|
||||
},
|
||||
{
|
||||
Address: "1.1.1.2",
|
||||
Port: "80",
|
||||
},
|
||||
{
|
||||
Address: "1.1.1.3",
|
||||
Port: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"should return all endpoints because no zone from controller node",
|
||||
&corev1.Service{
|
||||
Spec: corev1.ServiceSpec{
|
||||
Type: corev1.ServiceTypeClusterIP,
|
||||
ClusterIP: "1.1.1.1",
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Name: "default",
|
||||
TargetPort: intstr.FromString("port-1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
&corev1.ServicePort{
|
||||
Name: "port-1",
|
||||
TargetPort: intstr.FromString("port-1"),
|
||||
},
|
||||
corev1.ProtocolTCP,
|
||||
"",
|
||||
func(string) ([]*discoveryv1.EndpointSlice, error) {
|
||||
return []*discoveryv1.EndpointSlice{{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{discoveryv1.LabelServiceName: "default"},
|
||||
},
|
||||
Endpoints: []discoveryv1.Endpoint{
|
||||
{
|
||||
Addresses: []string{"1.1.1.1"},
|
||||
Conditions: discoveryv1.EndpointConditions{
|
||||
Ready: &[]bool{true}[0],
|
||||
},
|
||||
Hints: &[]discoveryv1.EndpointHints{{
|
||||
ForZones: []discoveryv1.ForZone{{
|
||||
Name: "eu-west-1a",
|
||||
}},
|
||||
}}[0],
|
||||
},
|
||||
{
|
||||
Addresses: []string{"1.1.1.2"},
|
||||
Conditions: discoveryv1.EndpointConditions{
|
||||
Ready: &[]bool{true}[0],
|
||||
},
|
||||
Hints: &[]discoveryv1.EndpointHints{{
|
||||
ForZones: []discoveryv1.ForZone{{
|
||||
Name: "eu-west-1b",
|
||||
}},
|
||||
}}[0],
|
||||
},
|
||||
{
|
||||
Addresses: []string{"1.1.1.3"},
|
||||
Conditions: discoveryv1.EndpointConditions{
|
||||
Ready: &[]bool{true}[0],
|
||||
},
|
||||
Hints: &[]discoveryv1.EndpointHints{{
|
||||
ForZones: []discoveryv1.ForZone{{
|
||||
Name: "eu-west-1c",
|
||||
}},
|
||||
}}[0],
|
||||
},
|
||||
},
|
||||
Ports: []discoveryv1.EndpointPort{
|
||||
{
|
||||
Protocol: &[]corev1.Protocol{corev1.ProtocolTCP}[0],
|
||||
Port: &[]int32{80}[0],
|
||||
Name: &[]string{"port-1"}[0],
|
||||
},
|
||||
},
|
||||
}}, nil
|
||||
},
|
||||
[]ingress.Endpoint{
|
||||
{
|
||||
Address: "1.1.1.1",
|
||||
Port: "80",
|
||||
},
|
||||
{
|
||||
Address: "1.1.1.2",
|
||||
Port: "80",
|
||||
},
|
||||
{
|
||||
Address: "1.1.1.3",
|
||||
Port: "80",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range tests {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
result := getEndpointsFromSlices(testCase.svc, testCase.port, testCase.proto, testCase.fn)
|
||||
result := getEndpointsFromSlices(testCase.svc, testCase.port, testCase.proto, testCase.zone, testCase.fn)
|
||||
if len(testCase.result) != len(result) {
|
||||
t.Errorf("Expected %d Endpoints but got %d", len(testCase.result), len(result))
|
||||
}
|
||||
|
|
|
@ -846,6 +846,11 @@ func (s *k8sStore) syncIngress(ing *networkingv1.Ingress) {
|
|||
copyIng := &networkingv1.Ingress{}
|
||||
ing.ObjectMeta.DeepCopyInto(©Ing.ObjectMeta)
|
||||
|
||||
if err := ingressutils.ValidateIngressPath(ing, s.backendConfig.DisablePathTypeValidation, s.backendConfig.PathAdditionalAllowedChars); err != nil {
|
||||
klog.Errorf("ingress %s contains invalid path and will be skipped: %s", key, err)
|
||||
return
|
||||
}
|
||||
|
||||
if s.backendConfig.AnnotationValueWordBlocklist != "" {
|
||||
if err := checkBadAnnotationValue(copyIng.Annotations, s.backendConfig.AnnotationValueWordBlocklist); err != nil {
|
||||
klog.Warningf("skipping ingress %s: %s", key, err)
|
||||
|
@ -865,10 +870,6 @@ func (s *k8sStore) syncIngress(ing *networkingv1.Ingress) {
|
|||
if path.Path == "" {
|
||||
copyIng.Spec.Rules[ri].HTTP.Paths[pi].Path = "/"
|
||||
}
|
||||
if !ingressutils.IsSafePath(copyIng, path.Path) {
|
||||
klog.Warningf("ingress %s contains invalid path %s", key, path.Path)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ func TestMergeConfigMapToStruct(t *testing.T) {
|
|||
"access-log-path": "/var/log/test/access.log",
|
||||
"error-log-path": "/var/log/test/error.log",
|
||||
"use-gzip": "false",
|
||||
"gzip-disable": "msie6",
|
||||
"gzip-level": "9",
|
||||
"gzip-min-length": "1024",
|
||||
"gzip-types": "text/html",
|
||||
|
@ -87,6 +88,7 @@ func TestMergeConfigMapToStruct(t *testing.T) {
|
|||
def.ProxyReadTimeout = 1
|
||||
def.ProxySendTimeout = 2
|
||||
def.UseProxyProtocol = true
|
||||
def.GzipDisable = "msie6"
|
||||
def.GzipLevel = 9
|
||||
def.GzipMinLength = 1024
|
||||
def.GzipTypes = "text/html"
|
||||
|
|
|
@ -32,6 +32,7 @@ var (
|
|||
ingressOperation = []string{"controller_namespace", "controller_class", "controller_pod", "namespace", "ingress"}
|
||||
sslLabelHost = []string{"namespace", "class", "host", "secret_name"}
|
||||
sslInfoLabels = []string{"namespace", "class", "host", "secret_name", "identifier", "issuer_organization", "issuer_common_name", "serial_number", "public_key_algorithm"}
|
||||
orphanityLabels = []string{"controller_namespace", "controller_class", "controller_pod", "namespace", "ingress", "type"}
|
||||
)
|
||||
|
||||
// Controller defines base metrics about the ingress controller
|
||||
|
@ -48,6 +49,7 @@ type Controller struct {
|
|||
checkIngressOperationErrors *prometheus.CounterVec
|
||||
sslExpireTime *prometheus.GaugeVec
|
||||
sslInfo *prometheus.GaugeVec
|
||||
OrphanIngress *prometheus.GaugeVec
|
||||
|
||||
constLabels prometheus.Labels
|
||||
labels prometheus.Labels
|
||||
|
@ -171,6 +173,15 @@ func NewController(pod, namespace, class string) *Controller {
|
|||
},
|
||||
[]string{"name"},
|
||||
),
|
||||
OrphanIngress: prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: PrometheusNamespace,
|
||||
Name: "orphan_ingress",
|
||||
Help: `Gauge reporting status of ingress orphanity, 1 indicates orphaned ingress.
|
||||
'namespace' is the string used to identify namespace of ingress, 'ingress' for ingress name and 'type' for 'no-service' or 'no-endpoint' of orphanity`,
|
||||
},
|
||||
orphanityLabels,
|
||||
),
|
||||
}
|
||||
|
||||
return cm
|
||||
|
@ -214,6 +225,26 @@ func (cm *Controller) IncCheckErrorCount(namespace, name string) {
|
|||
cm.checkIngressOperationErrors.MustCurryWith(cm.constLabels).With(labels).Inc()
|
||||
}
|
||||
|
||||
// IncOrphanIngress sets the the orphaned ingress gauge to one
|
||||
func (cm *Controller) IncOrphanIngress(namespace string, name string, orphanityType string) {
|
||||
labels := prometheus.Labels{
|
||||
"namespace": namespace,
|
||||
"ingress": name,
|
||||
"type": orphanityType,
|
||||
}
|
||||
cm.OrphanIngress.MustCurryWith(cm.constLabels).With(labels).Set(1.0)
|
||||
}
|
||||
|
||||
// DecOrphanIngress sets the the orphaned ingress gauge to zero (all services has their endpoints)
|
||||
func (cm *Controller) DecOrphanIngress(namespace string, name string, orphanityType string) {
|
||||
labels := prometheus.Labels{
|
||||
"namespace": namespace,
|
||||
"ingress": name,
|
||||
"type": orphanityType,
|
||||
}
|
||||
cm.OrphanIngress.MustCurryWith(cm.constLabels).With(labels).Set(0.0)
|
||||
}
|
||||
|
||||
// ConfigSuccess set a boolean flag according to the output of the controller configuration reload
|
||||
func (cm *Controller) ConfigSuccess(hash uint64, success bool) {
|
||||
if success {
|
||||
|
@ -242,6 +273,7 @@ func (cm Controller) Describe(ch chan<- *prometheus.Desc) {
|
|||
cm.sslInfo.Describe(ch)
|
||||
cm.leaderElection.Describe(ch)
|
||||
cm.buildInfo.Describe(ch)
|
||||
cm.OrphanIngress.Describe(ch)
|
||||
}
|
||||
|
||||
// Collect implements the prometheus.Collector interface.
|
||||
|
@ -257,6 +289,7 @@ func (cm Controller) Collect(ch chan<- prometheus.Metric) {
|
|||
cm.sslInfo.Collect(ch)
|
||||
cm.leaderElection.Collect(ch)
|
||||
cm.buildInfo.Collect(ch)
|
||||
cm.OrphanIngress.Collect(ch)
|
||||
}
|
||||
|
||||
// SetSSLExpireTime sets the expiration time of SSL Certificates
|
||||
|
|
|
@ -41,6 +41,12 @@ func (dc DummyCollector) IncReloadCount() {}
|
|||
// IncReloadErrorCount ...
|
||||
func (dc DummyCollector) IncReloadErrorCount() {}
|
||||
|
||||
// IncOrphanIngress ...
|
||||
func (dc DummyCollector) IncOrphanIngress(string, string, string) {}
|
||||
|
||||
// DecOrphanIngress ...
|
||||
func (dc DummyCollector) DecOrphanIngress(string, string, string) {}
|
||||
|
||||
// IncCheckCount ...
|
||||
func (dc DummyCollector) IncCheckCount(string, string) {}
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ type Collector interface {
|
|||
|
||||
IncCheckCount(string, string)
|
||||
IncCheckErrorCount(string, string)
|
||||
IncOrphanIngress(string, string, string)
|
||||
DecOrphanIngress(string, string, string)
|
||||
|
||||
RemoveMetrics(ingresses, endpoints, certificates []string)
|
||||
|
||||
|
@ -181,6 +183,14 @@ func (c *collector) SetSSLInfo(servers []*ingress.Server) {
|
|||
c.ingressController.SetSSLInfo(servers)
|
||||
}
|
||||
|
||||
func (c *collector) IncOrphanIngress(namespace string, name string, orphanityType string) {
|
||||
c.ingressController.IncOrphanIngress(namespace, name, orphanityType)
|
||||
}
|
||||
|
||||
func (c *collector) DecOrphanIngress(namespace string, name string, orphanityType string) {
|
||||
c.ingressController.DecOrphanIngress(namespace, name, orphanityType)
|
||||
}
|
||||
|
||||
func (c *collector) SetHosts(hosts sets.String) {
|
||||
c.socket.SetHosts(hosts)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package status
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
v1 "k8s.io/api/networking/v1"
|
||||
"net"
|
||||
"regexp"
|
||||
"sort"
|
||||
|
@ -128,7 +129,7 @@ func (s statusSync) Shutdown() {
|
|||
}
|
||||
|
||||
klog.InfoS("removing value from ingress status", "address", addrs)
|
||||
s.updateStatus([]apiv1.LoadBalancerIngress{})
|
||||
s.updateStatus([]v1.IngressLoadBalancerIngress{})
|
||||
}
|
||||
|
||||
func (s *statusSync) sync(key interface{}) error {
|
||||
|
@ -160,21 +161,21 @@ func NewStatusSyncer(config Config) Syncer {
|
|||
return st
|
||||
}
|
||||
|
||||
func nameOrIPToLoadBalancerIngress(nameOrIP string) apiv1.LoadBalancerIngress {
|
||||
func nameOrIPToLoadBalancerIngress(nameOrIP string) v1.IngressLoadBalancerIngress {
|
||||
if net.ParseIP(nameOrIP) != nil {
|
||||
return apiv1.LoadBalancerIngress{IP: nameOrIP}
|
||||
return v1.IngressLoadBalancerIngress{IP: nameOrIP}
|
||||
}
|
||||
|
||||
return apiv1.LoadBalancerIngress{Hostname: nameOrIP}
|
||||
return v1.IngressLoadBalancerIngress{Hostname: nameOrIP}
|
||||
}
|
||||
|
||||
// runningAddresses returns a list of IP addresses and/or FQDN where the
|
||||
// ingress controller is currently running
|
||||
func (s *statusSync) runningAddresses() ([]apiv1.LoadBalancerIngress, error) {
|
||||
func (s *statusSync) runningAddresses() ([]v1.IngressLoadBalancerIngress, error) {
|
||||
if s.PublishStatusAddress != "" {
|
||||
re := regexp.MustCompile(`,\s*`)
|
||||
multipleAddrs := re.Split(s.PublishStatusAddress, -1)
|
||||
addrs := make([]apiv1.LoadBalancerIngress, len(multipleAddrs))
|
||||
addrs := make([]v1.IngressLoadBalancerIngress, len(multipleAddrs))
|
||||
for i, addr := range multipleAddrs {
|
||||
addrs[i] = nameOrIPToLoadBalancerIngress(addr)
|
||||
}
|
||||
|
@ -193,7 +194,7 @@ func (s *statusSync) runningAddresses() ([]apiv1.LoadBalancerIngress, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
addrs := make([]apiv1.LoadBalancerIngress, 0)
|
||||
addrs := make([]v1.IngressLoadBalancerIngress, 0)
|
||||
for i := range pods.Items {
|
||||
pod := pods.Items[i]
|
||||
// only Running pods are valid
|
||||
|
@ -250,7 +251,7 @@ func (s *statusSync) isRunningMultiplePods() bool {
|
|||
|
||||
// standardizeLoadBalancerIngresses sorts the list of loadbalancer by
|
||||
// IP
|
||||
func standardizeLoadBalancerIngresses(lbi []apiv1.LoadBalancerIngress) []apiv1.LoadBalancerIngress {
|
||||
func standardizeLoadBalancerIngresses(lbi []v1.IngressLoadBalancerIngress) []v1.IngressLoadBalancerIngress {
|
||||
sort.SliceStable(lbi, func(a, b int) bool {
|
||||
return lbi[a].IP < lbi[b].IP
|
||||
})
|
||||
|
@ -259,7 +260,7 @@ func standardizeLoadBalancerIngresses(lbi []apiv1.LoadBalancerIngress) []apiv1.L
|
|||
}
|
||||
|
||||
// updateStatus changes the status information of Ingress rules
|
||||
func (s *statusSync) updateStatus(newIngressPoint []apiv1.LoadBalancerIngress) {
|
||||
func (s *statusSync) updateStatus(newIngressPoint []v1.IngressLoadBalancerIngress) {
|
||||
ings := s.IngressLister.ListIngresses()
|
||||
|
||||
p := pool.NewLimited(10)
|
||||
|
@ -283,7 +284,7 @@ func (s *statusSync) updateStatus(newIngressPoint []apiv1.LoadBalancerIngress) {
|
|||
batch.WaitAll()
|
||||
}
|
||||
|
||||
func runUpdate(ing *ingress.Ingress, status []apiv1.LoadBalancerIngress,
|
||||
func runUpdate(ing *ingress.Ingress, status []v1.IngressLoadBalancerIngress,
|
||||
client clientset.Interface) pool.WorkFunc {
|
||||
return func(wu pool.WorkUnit) (interface{}, error) {
|
||||
if wu.IsCancelled() {
|
||||
|
@ -307,7 +308,7 @@ func runUpdate(ing *ingress.Ingress, status []apiv1.LoadBalancerIngress,
|
|||
}
|
||||
}
|
||||
|
||||
func lessLoadBalancerIngress(addrs []apiv1.LoadBalancerIngress) func(int, int) bool {
|
||||
func lessLoadBalancerIngress(addrs []v1.IngressLoadBalancerIngress) func(int, int) bool {
|
||||
return func(a, b int) bool {
|
||||
switch strings.Compare(addrs[a].Hostname, addrs[b].Hostname) {
|
||||
case -1:
|
||||
|
@ -319,7 +320,7 @@ func lessLoadBalancerIngress(addrs []apiv1.LoadBalancerIngress) func(int, int) b
|
|||
}
|
||||
}
|
||||
|
||||
func ingressSliceEqual(lhs, rhs []apiv1.LoadBalancerIngress) bool {
|
||||
func ingressSliceEqual(lhs, rhs []v1.IngressLoadBalancerIngress) bool {
|
||||
if len(lhs) != len(rhs) {
|
||||
return false
|
||||
}
|
||||
|
@ -336,7 +337,7 @@ func ingressSliceEqual(lhs, rhs []apiv1.LoadBalancerIngress) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func statusAddressFromService(service string, kubeClient clientset.Interface) ([]apiv1.LoadBalancerIngress, error) {
|
||||
func statusAddressFromService(service string, kubeClient clientset.Interface) ([]v1.IngressLoadBalancerIngress, error) {
|
||||
ns, name, _ := k8s.ParseNameNS(service)
|
||||
svc, err := kubeClient.CoreV1().Services(ns).Get(context.TODO(), name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
|
@ -345,28 +346,28 @@ func statusAddressFromService(service string, kubeClient clientset.Interface) ([
|
|||
|
||||
switch svc.Spec.Type {
|
||||
case apiv1.ServiceTypeExternalName:
|
||||
return []apiv1.LoadBalancerIngress{{
|
||||
return []v1.IngressLoadBalancerIngress{{
|
||||
Hostname: svc.Spec.ExternalName,
|
||||
}}, nil
|
||||
case apiv1.ServiceTypeClusterIP:
|
||||
return []apiv1.LoadBalancerIngress{{
|
||||
return []v1.IngressLoadBalancerIngress{{
|
||||
IP: svc.Spec.ClusterIP,
|
||||
}}, nil
|
||||
case apiv1.ServiceTypeNodePort:
|
||||
if svc.Spec.ExternalIPs == nil {
|
||||
return []apiv1.LoadBalancerIngress{{
|
||||
return []v1.IngressLoadBalancerIngress{{
|
||||
IP: svc.Spec.ClusterIP,
|
||||
}}, nil
|
||||
}
|
||||
addrs := make([]apiv1.LoadBalancerIngress, len(svc.Spec.ExternalIPs))
|
||||
addrs := make([]v1.IngressLoadBalancerIngress, len(svc.Spec.ExternalIPs))
|
||||
for i, ip := range svc.Spec.ExternalIPs {
|
||||
addrs[i] = apiv1.LoadBalancerIngress{IP: ip}
|
||||
addrs[i] = v1.IngressLoadBalancerIngress{IP: ip}
|
||||
}
|
||||
return addrs, nil
|
||||
case apiv1.ServiceTypeLoadBalancer:
|
||||
addrs := make([]apiv1.LoadBalancerIngress, len(svc.Status.LoadBalancer.Ingress))
|
||||
addrs := make([]v1.IngressLoadBalancerIngress, len(svc.Status.LoadBalancer.Ingress))
|
||||
for i, ingress := range svc.Status.LoadBalancer.Ingress {
|
||||
addrs[i] = apiv1.LoadBalancerIngress{}
|
||||
addrs[i] = v1.IngressLoadBalancerIngress{}
|
||||
if ingress.Hostname != "" {
|
||||
addrs[i].Hostname = ingress.Hostname
|
||||
}
|
||||
|
@ -376,7 +377,7 @@ func statusAddressFromService(service string, kubeClient clientset.Interface) ([
|
|||
}
|
||||
for _, ip := range svc.Spec.ExternalIPs {
|
||||
if !stringInIngresses(ip, addrs) {
|
||||
addrs = append(addrs, apiv1.LoadBalancerIngress{IP: ip})
|
||||
addrs = append(addrs, v1.IngressLoadBalancerIngress{IP: ip})
|
||||
}
|
||||
}
|
||||
return addrs, nil
|
||||
|
@ -386,7 +387,7 @@ func statusAddressFromService(service string, kubeClient clientset.Interface) ([
|
|||
}
|
||||
|
||||
// stringInSlice returns true if s is in list
|
||||
func stringInIngresses(s string, list []apiv1.LoadBalancerIngress) bool {
|
||||
func stringInIngresses(s string, list []v1.IngressLoadBalancerIngress) bool {
|
||||
for _, v := range list {
|
||||
if v.IP == s || v.Hostname == s {
|
||||
return true
|
||||
|
|
|
@ -34,8 +34,8 @@ import (
|
|||
"k8s.io/ingress-nginx/pkg/apis/ingress"
|
||||
)
|
||||
|
||||
func buildLoadBalancerIngressByIP() []apiv1.LoadBalancerIngress {
|
||||
return []apiv1.LoadBalancerIngress{
|
||||
func buildLoadBalancerIngressByIP() []networking.IngressLoadBalancerIngress {
|
||||
return []networking.IngressLoadBalancerIngress{
|
||||
{
|
||||
IP: "10.0.0.1",
|
||||
Hostname: "foo1",
|
||||
|
@ -123,17 +123,20 @@ func buildSimpleClientSet() *testclient.Clientset {
|
|||
},
|
||||
}},
|
||||
&apiv1.ServiceList{Items: []apiv1.Service{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
Namespace: apiv1.NamespaceDefault,
|
||||
},
|
||||
Status: apiv1.ServiceStatus{
|
||||
LoadBalancer: apiv1.LoadBalancerStatus{
|
||||
Ingress: buildLoadBalancerIngressByIP(),
|
||||
},
|
||||
},
|
||||
},
|
||||
// This is commented out as the ServiceStatus.LoadBalancer field expects a LoadBalancerStatus object
|
||||
// which is incompatible with the current Ingress struct which expects a IngressLoadBalancerStatus object
|
||||
// TODO: update this service when the ServiceStatus struct gets updated
|
||||
//{
|
||||
// ObjectMeta: metav1.ObjectMeta{
|
||||
// Name: "foo",
|
||||
// Namespace: apiv1.NamespaceDefault,
|
||||
// },
|
||||
// Status: apiv1.ServiceStatus{
|
||||
// LoadBalancer: apiv1.LoadBalancerStatus{
|
||||
// Ingress: buildLoadBalancerIngressByIP(),
|
||||
// },
|
||||
// },
|
||||
//},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo_non_exist",
|
||||
|
@ -199,8 +202,8 @@ func buildExtensionsIngresses() []networking.Ingress {
|
|||
Namespace: apiv1.NamespaceDefault,
|
||||
},
|
||||
Status: networking.IngressStatus{
|
||||
LoadBalancer: apiv1.LoadBalancerStatus{
|
||||
Ingress: []apiv1.LoadBalancerIngress{
|
||||
LoadBalancer: networking.IngressLoadBalancerStatus{
|
||||
Ingress: []networking.IngressLoadBalancerIngress{
|
||||
{
|
||||
IP: "10.0.0.1",
|
||||
Hostname: "foo1",
|
||||
|
@ -218,8 +221,8 @@ func buildExtensionsIngresses() []networking.Ingress {
|
|||
},
|
||||
},
|
||||
Status: networking.IngressStatus{
|
||||
LoadBalancer: apiv1.LoadBalancerStatus{
|
||||
Ingress: []apiv1.LoadBalancerIngress{
|
||||
LoadBalancer: networking.IngressLoadBalancerStatus{
|
||||
Ingress: []networking.IngressLoadBalancerIngress{
|
||||
{
|
||||
IP: "0.0.0.0",
|
||||
Hostname: "foo.bar.com",
|
||||
|
@ -234,8 +237,8 @@ func buildExtensionsIngresses() []networking.Ingress {
|
|||
Namespace: apiv1.NamespaceDefault,
|
||||
},
|
||||
Status: networking.IngressStatus{
|
||||
LoadBalancer: apiv1.LoadBalancerStatus{
|
||||
Ingress: []apiv1.LoadBalancerIngress{},
|
||||
LoadBalancer: networking.IngressLoadBalancerStatus{
|
||||
Ingress: []networking.IngressLoadBalancerIngress{},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -261,7 +264,7 @@ func (til *testIngressLister) ListIngresses() []*ingress.Ingress {
|
|||
Namespace: apiv1.NamespaceDefault,
|
||||
},
|
||||
Status: networking.IngressStatus{
|
||||
LoadBalancer: apiv1.LoadBalancerStatus{
|
||||
LoadBalancer: networking.IngressLoadBalancerStatus{
|
||||
Ingress: buildLoadBalancerIngressByIP(),
|
||||
},
|
||||
},
|
||||
|
@ -325,7 +328,7 @@ func TestStatusActions(t *testing.T) {
|
|||
fk.sync("just-test")
|
||||
// PublishService is empty, so the running address is: ["11.0.0.2"]
|
||||
// after updated, the ingress's ip should only be "11.0.0.2"
|
||||
newIPs := []apiv1.LoadBalancerIngress{{
|
||||
newIPs := []networking.IngressLoadBalancerIngress{{
|
||||
IP: "11.0.0.2",
|
||||
}}
|
||||
fooIngress1, err1 := fk.Client.NetworkingV1().Ingresses(apiv1.NamespaceDefault).Get(context.TODO(), "foo_ingress_1", metav1.GetOptions{})
|
||||
|
@ -342,7 +345,7 @@ func TestStatusActions(t *testing.T) {
|
|||
// execute shutdown
|
||||
fk.Shutdown()
|
||||
// ingress should be empty
|
||||
newIPs2 := []apiv1.LoadBalancerIngress{}
|
||||
var newIPs2 []networking.IngressLoadBalancerIngress
|
||||
fooIngress2, err2 := fk.Client.NetworkingV1().Ingresses(apiv1.NamespaceDefault).Get(context.TODO(), "foo_ingress_1", metav1.GetOptions{})
|
||||
if err2 != nil {
|
||||
t.Fatalf("unexpected error")
|
||||
|
@ -382,7 +385,7 @@ func TestKeyfunc(t *testing.T) {
|
|||
func TestRunningAddressesWithPublishService(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
fakeClient *testclient.Clientset
|
||||
expected []apiv1.LoadBalancerIngress
|
||||
expected []networking.IngressLoadBalancerIngress
|
||||
errExpected bool
|
||||
}{
|
||||
"service type ClusterIP": {
|
||||
|
@ -416,7 +419,7 @@ func TestRunningAddressesWithPublishService(t *testing.T) {
|
|||
},
|
||||
},
|
||||
),
|
||||
[]apiv1.LoadBalancerIngress{
|
||||
[]networking.IngressLoadBalancerIngress{
|
||||
{IP: "1.1.1.1"},
|
||||
},
|
||||
false,
|
||||
|
@ -437,7 +440,7 @@ func TestRunningAddressesWithPublishService(t *testing.T) {
|
|||
},
|
||||
},
|
||||
),
|
||||
[]apiv1.LoadBalancerIngress{
|
||||
[]networking.IngressLoadBalancerIngress{
|
||||
{IP: "1.1.1.1"},
|
||||
},
|
||||
false,
|
||||
|
@ -458,7 +461,7 @@ func TestRunningAddressesWithPublishService(t *testing.T) {
|
|||
},
|
||||
},
|
||||
),
|
||||
[]apiv1.LoadBalancerIngress{
|
||||
[]networking.IngressLoadBalancerIngress{
|
||||
{Hostname: "foo.bar"},
|
||||
},
|
||||
false,
|
||||
|
@ -495,7 +498,7 @@ func TestRunningAddressesWithPublishService(t *testing.T) {
|
|||
},
|
||||
},
|
||||
),
|
||||
[]apiv1.LoadBalancerIngress{
|
||||
[]networking.IngressLoadBalancerIngress{
|
||||
{IP: "10.0.0.1"},
|
||||
{Hostname: "foo"},
|
||||
{
|
||||
|
@ -530,7 +533,7 @@ func TestRunningAddressesWithPublishService(t *testing.T) {
|
|||
},
|
||||
},
|
||||
),
|
||||
[]apiv1.LoadBalancerIngress{
|
||||
[]networking.IngressLoadBalancerIngress{
|
||||
{IP: "10.0.0.1"},
|
||||
},
|
||||
false,
|
||||
|
@ -568,7 +571,7 @@ func TestRunningAddressesWithPublishService(t *testing.T) {
|
|||
}
|
||||
|
||||
if ra == nil {
|
||||
t.Fatalf("returned nil but expected valid []apiv1.LoadBalancerIngress")
|
||||
t.Fatalf("returned nil but expected valid []networking.IngressLoadBalancerIngress")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tc.expected, ra) {
|
||||
|
@ -584,7 +587,7 @@ func TestRunningAddressesWithPods(t *testing.T) {
|
|||
|
||||
r, _ := fk.runningAddresses()
|
||||
if r == nil {
|
||||
t.Fatalf("returned nil but expected valid []apiv1.LoadBalancerIngress")
|
||||
t.Fatalf("returned nil but expected valid []networking.IngressLoadBalancerIngress")
|
||||
}
|
||||
rl := len(r)
|
||||
if len(r) != 1 {
|
||||
|
@ -592,7 +595,7 @@ func TestRunningAddressesWithPods(t *testing.T) {
|
|||
}
|
||||
rv := r[0]
|
||||
if rv.IP != "11.0.0.2" {
|
||||
t.Errorf("returned %v but expected %v", rv, apiv1.LoadBalancerIngress{IP: "11.0.0.2"})
|
||||
t.Errorf("returned %v but expected %v", rv, networking.IngressLoadBalancerIngress{IP: "11.0.0.2"})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -602,7 +605,7 @@ func TestRunningAddressesWithPublishStatusAddress(t *testing.T) {
|
|||
|
||||
ra, _ := fk.runningAddresses()
|
||||
if ra == nil {
|
||||
t.Fatalf("returned nil but expected valid []apiv1.LoadBalancerIngress")
|
||||
t.Fatalf("returned nil but expected valid []networking.IngressLoadBalancerIngress")
|
||||
}
|
||||
rl := len(ra)
|
||||
if len(ra) != 1 {
|
||||
|
@ -610,7 +613,7 @@ func TestRunningAddressesWithPublishStatusAddress(t *testing.T) {
|
|||
}
|
||||
rv := ra[0]
|
||||
if rv.IP != "127.0.0.1" {
|
||||
t.Errorf("returned %v but expected %v", rv, apiv1.LoadBalancerIngress{IP: "127.0.0.1"})
|
||||
t.Errorf("returned %v but expected %v", rv, networking.IngressLoadBalancerIngress{IP: "127.0.0.1"})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -620,7 +623,7 @@ func TestRunningAddressesWithPublishStatusAddresses(t *testing.T) {
|
|||
|
||||
ra, _ := fk.runningAddresses()
|
||||
if ra == nil {
|
||||
t.Fatalf("returned nil but expected valid []apiv1.LoadBalancerIngress")
|
||||
t.Fatalf("returned nil but expected valid []networking.IngressLoadBalancerIngress")
|
||||
}
|
||||
rl := len(ra)
|
||||
if len(ra) != 2 {
|
||||
|
@ -629,10 +632,10 @@ func TestRunningAddressesWithPublishStatusAddresses(t *testing.T) {
|
|||
rv := ra[0]
|
||||
rv2 := ra[1]
|
||||
if rv.IP != "127.0.0.1" {
|
||||
t.Errorf("returned %v but expected %v", rv, apiv1.LoadBalancerIngress{IP: "127.0.0.1"})
|
||||
t.Errorf("returned %v but expected %v", rv, networking.IngressLoadBalancerIngress{IP: "127.0.0.1"})
|
||||
}
|
||||
if rv2.IP != "1.1.1.1" {
|
||||
t.Errorf("returned %v but expected %v", rv2, apiv1.LoadBalancerIngress{IP: "1.1.1.1"})
|
||||
t.Errorf("returned %v but expected %v", rv2, networking.IngressLoadBalancerIngress{IP: "1.1.1.1"})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -642,7 +645,7 @@ func TestRunningAddressesWithPublishStatusAddressesAndSpaces(t *testing.T) {
|
|||
|
||||
ra, _ := fk.runningAddresses()
|
||||
if ra == nil {
|
||||
t.Fatalf("returned nil but expected valid []apiv1.LoadBalancerIngresst")
|
||||
t.Fatalf("returned nil but expected valid []networking.IngressLoadBalancerIngresst")
|
||||
}
|
||||
rl := len(ra)
|
||||
if len(ra) != 2 {
|
||||
|
@ -651,15 +654,15 @@ func TestRunningAddressesWithPublishStatusAddressesAndSpaces(t *testing.T) {
|
|||
rv := ra[0]
|
||||
rv2 := ra[1]
|
||||
if rv.IP != "127.0.0.1" {
|
||||
t.Errorf("returned %v but expected %v", rv, apiv1.LoadBalancerIngress{IP: "127.0.0.1"})
|
||||
t.Errorf("returned %v but expected %v", rv, networking.IngressLoadBalancerIngress{IP: "127.0.0.1"})
|
||||
}
|
||||
if rv2.IP != "1.1.1.1" {
|
||||
t.Errorf("returned %v but expected %v", rv2, apiv1.LoadBalancerIngress{IP: "1.1.1.1"})
|
||||
t.Errorf("returned %v but expected %v", rv2, networking.IngressLoadBalancerIngress{IP: "1.1.1.1"})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStandardizeLoadBalancerIngresses(t *testing.T) {
|
||||
fkEndpoints := []apiv1.LoadBalancerIngress{
|
||||
fkEndpoints := []networking.IngressLoadBalancerIngress{
|
||||
{IP: "2001:db8::68"},
|
||||
{IP: "10.0.0.1"},
|
||||
{Hostname: "opensource-k8s-ingress"},
|
||||
|
@ -668,7 +671,7 @@ func TestStandardizeLoadBalancerIngresses(t *testing.T) {
|
|||
r := standardizeLoadBalancerIngresses(fkEndpoints)
|
||||
|
||||
if r == nil {
|
||||
t.Fatalf("returned nil but expected a valid []apiv1.LoadBalancerIngress")
|
||||
t.Fatalf("returned nil but expected a valid []networking.IngressLoadBalancerIngress")
|
||||
}
|
||||
rl := len(r)
|
||||
if rl != 3 {
|
||||
|
@ -676,21 +679,21 @@ func TestStandardizeLoadBalancerIngresses(t *testing.T) {
|
|||
}
|
||||
re1 := r[0]
|
||||
if re1.Hostname != "opensource-k8s-ingress" {
|
||||
t.Fatalf("returned %v but expected %v", re1, apiv1.LoadBalancerIngress{Hostname: "opensource-k8s-ingress"})
|
||||
t.Fatalf("returned %v but expected %v", re1, networking.IngressLoadBalancerIngress{Hostname: "opensource-k8s-ingress"})
|
||||
}
|
||||
re2 := r[1]
|
||||
if re2.IP != "10.0.0.1" {
|
||||
t.Fatalf("returned %v but expected %v", re2, apiv1.LoadBalancerIngress{IP: "10.0.0.1"})
|
||||
t.Fatalf("returned %v but expected %v", re2, networking.IngressLoadBalancerIngress{IP: "10.0.0.1"})
|
||||
}
|
||||
re3 := r[2]
|
||||
if re3.IP != "2001:db8::68" {
|
||||
t.Fatalf("returned %v but expected %v", re3, apiv1.LoadBalancerIngress{IP: "2001:db8::68"})
|
||||
t.Fatalf("returned %v but expected %v", re3, networking.IngressLoadBalancerIngress{IP: "2001:db8::68"})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIngressSliceEqual(t *testing.T) {
|
||||
fk1 := buildLoadBalancerIngressByIP()
|
||||
fk2 := append(buildLoadBalancerIngressByIP(), apiv1.LoadBalancerIngress{
|
||||
fk2 := append(buildLoadBalancerIngressByIP(), networking.IngressLoadBalancerIngress{
|
||||
IP: "10.0.0.5",
|
||||
Hostname: "foo5",
|
||||
})
|
||||
|
@ -700,8 +703,8 @@ func TestIngressSliceEqual(t *testing.T) {
|
|||
fk4[2].IP = "11.0.0.3"
|
||||
|
||||
fooTests := []struct {
|
||||
lhs []apiv1.LoadBalancerIngress
|
||||
rhs []apiv1.LoadBalancerIngress
|
||||
lhs []networking.IngressLoadBalancerIngress
|
||||
rhs []networking.IngressLoadBalancerIngress
|
||||
er bool
|
||||
}{
|
||||
{fk1, fk1, true},
|
||||
|
@ -710,7 +713,7 @@ func TestIngressSliceEqual(t *testing.T) {
|
|||
{fk4, fk1, false},
|
||||
{fk1, nil, false},
|
||||
{nil, nil, true},
|
||||
{[]apiv1.LoadBalancerIngress{}, []apiv1.LoadBalancerIngress{}, true},
|
||||
{[]networking.IngressLoadBalancerIngress{}, []networking.IngressLoadBalancerIngress{}, true},
|
||||
}
|
||||
|
||||
for _, fooTest := range fooTests {
|
||||
|
|
|
@ -78,6 +78,8 @@ func GetNodeIPOrName(kubeClient clientset.Interface, name string, useInternalIP
|
|||
var (
|
||||
// IngressPodDetails hold information about the ingress-nginx pod
|
||||
IngressPodDetails *PodInfo
|
||||
// IngressNodeDetails old information about the node running ingress-nginx pod
|
||||
IngressNodeDetails *NodeInfo
|
||||
)
|
||||
|
||||
// PodInfo contains runtime information about the pod running the Ingres controller
|
||||
|
@ -87,6 +89,12 @@ type PodInfo struct {
|
|||
metav1.ObjectMeta
|
||||
}
|
||||
|
||||
// NodeInfo contains runtime information about the node pod running the Ingres controller, eg. zone where pod is running
|
||||
type NodeInfo struct {
|
||||
metav1.TypeMeta
|
||||
metav1.ObjectMeta
|
||||
}
|
||||
|
||||
// GetIngressPod load the ingress-nginx pod
|
||||
func GetIngressPod(kubeClient clientset.Interface) error {
|
||||
podName := os.Getenv("POD_NAME")
|
||||
|
@ -108,6 +116,18 @@ func GetIngressPod(kubeClient clientset.Interface) error {
|
|||
pod.ObjectMeta.DeepCopyInto(&IngressPodDetails.ObjectMeta)
|
||||
IngressPodDetails.SetLabels(pod.GetLabels())
|
||||
|
||||
IngressNodeDetails = &NodeInfo{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Node"},
|
||||
}
|
||||
// Try to get node info/labels to determine topology zone where pod is running
|
||||
node, err := kubeClient.CoreV1().Nodes().Get(context.TODO(), pod.Spec.NodeName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
klog.Warningf("Unable to get NODE information: %v", err)
|
||||
} else {
|
||||
node.ObjectMeta.DeepCopyInto(&IngressNodeDetails.ObjectMeta)
|
||||
IngressNodeDetails.SetLabels(node.GetLabels())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -160,9 +180,6 @@ func SetDefaultNGINXPathType(ing *networkingv1.Ingress) {
|
|||
p.PathType = &defaultPathType
|
||||
}
|
||||
|
||||
if *p.PathType == networkingv1.PathTypeImplementationSpecific {
|
||||
p.PathType = &defaultPathType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,6 +216,8 @@ Takes the form "<host>:port". If not provided, no admission controller is starte
|
|||
dynamicConfigurationRetries = flags.Int("dynamic-configuration-retries", 15, "Number of times to retry failed dynamic configuration before failing to sync an ingress.")
|
||||
|
||||
disableSyncEvents = flags.Bool("disable-sync-events", false, "Disables the creation of 'Sync' event resources")
|
||||
|
||||
enableTopologyAwareRouting = flags.Bool("enable-topology-aware-routing", false, "Enable topology aware hints feature, needs service object annotation service.kubernetes.io/topology-aware-hints sets to auto.")
|
||||
)
|
||||
|
||||
flags.StringVar(&nginx.MaxmindMirror, "maxmind-mirror", "", `Maxmind mirror url (example: http://geoip.local/databases.`)
|
||||
|
@ -348,6 +350,7 @@ https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-g
|
|||
SyncRateLimit: *syncRateLimit,
|
||||
HealthCheckHost: *healthzHost,
|
||||
DynamicConfigurationRetries: *dynamicConfigurationRetries,
|
||||
EnableTopologyAwareRouting: *enableTopologyAwareRouting,
|
||||
ListenPorts: &ngx_config.ListenPorts{
|
||||
Default: *defServerPort,
|
||||
Health: *healthzPort,
|
||||
|
|
|
@ -23,7 +23,6 @@ import (
|
|||
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/internal/k8s"
|
||||
"k8s.io/ingress-nginx/internal/net/ssl"
|
||||
"k8s.io/ingress-nginx/pkg/apis/ingress"
|
||||
|
@ -31,15 +30,15 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
alphaNumericChars = `\-\.\_\~a-zA-Z0-9/`
|
||||
regexEnabledChars = `\^\$\[\]\(\)\{\}\*\+`
|
||||
alphaNumericChars = `A-Za-z0-9\-\.\_\~\/` // This is the default allowed set on paths
|
||||
)
|
||||
|
||||
var (
|
||||
// pathAlphaNumeric is a regex validation of something like "^/[a-zA-Z]+$" on path
|
||||
pathAlphaNumeric = regexp.MustCompile("^/[" + alphaNumericChars + "]*$").MatchString
|
||||
// pathRegexEnabled is a regex validation of paths that may contain regex.
|
||||
pathRegexEnabled = regexp.MustCompile("^/[" + alphaNumericChars + regexEnabledChars + "]*$").MatchString
|
||||
// pathAlphaNumeric is a regex validation that allows only (0-9, a-z, A-Z, "-", ".", "_", "~", "/")
|
||||
pathAlphaNumericRegex = regexp.MustCompile("^[" + alphaNumericChars + "]*$").MatchString
|
||||
|
||||
// default path type is Prefix to not break existing definitions
|
||||
defaultPathType = networkingv1.PathTypePrefix
|
||||
)
|
||||
|
||||
func GetRemovedHosts(rucfg, newcfg *ingress.Configuration) []string {
|
||||
|
@ -247,12 +246,45 @@ func BuildRedirects(servers []*ingress.Server) []*redirect {
|
|||
return redirectServers
|
||||
}
|
||||
|
||||
// IsSafePath verifies if the path used in ingress object contains only valid characters.
|
||||
// It will behave differently if regex is enabled or not
|
||||
func IsSafePath(copyIng *networkingv1.Ingress, path string) bool {
|
||||
isRegex, _ := parser.GetBoolAnnotation("use-regex", copyIng)
|
||||
if isRegex {
|
||||
return pathRegexEnabled(path)
|
||||
func ValidateIngressPath(copyIng *networkingv1.Ingress, disablePathTypeValidation bool, additionalChars string) error {
|
||||
|
||||
if copyIng == nil {
|
||||
return nil
|
||||
}
|
||||
return pathAlphaNumeric(path)
|
||||
|
||||
escapedAdditionalChars := regexp.QuoteMeta(additionalChars)
|
||||
regexPath, err := regexp.Compile("^[" + alphaNumericChars + escapedAdditionalChars + "]*$")
|
||||
if err != nil {
|
||||
return fmt.Errorf("ingress has misconfigured validation regex on configmap: %s - %w", additionalChars, err)
|
||||
}
|
||||
|
||||
for _, rule := range copyIng.Spec.Rules {
|
||||
if rule.HTTP == nil {
|
||||
continue
|
||||
}
|
||||
if err := checkPath(rule.HTTP.Paths, disablePathTypeValidation, regexPath); err != nil {
|
||||
return fmt.Errorf("error validating ingressPath: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkPath(paths []networkingv1.HTTPIngressPath, disablePathTypeValidation bool, regexSpecificChars *regexp.Regexp) error {
|
||||
for _, path := range paths {
|
||||
if path.PathType == nil {
|
||||
path.PathType = &defaultPathType
|
||||
}
|
||||
|
||||
if disablePathTypeValidation || *path.PathType == networkingv1.PathTypeImplementationSpecific {
|
||||
if !regexSpecificChars.MatchString(path.Path) {
|
||||
return fmt.Errorf("path %s of type %s contains invalid characters", path.Path, *path.PathType)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if !pathAlphaNumericRegex(path.Path) {
|
||||
return fmt.Errorf("path %s of type %s contains invalid characters", path.Path, *path.PathType)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -17,13 +17,10 @@ limitations under the License.
|
|||
package ingress
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/ingress-nginx/pkg/apis/ingress"
|
||||
)
|
||||
|
||||
|
@ -136,81 +133,168 @@ func TestIsDynamicConfigurationEnough(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func generateDumbIngressforPathTest(regexEnabled bool) *networkingv1.Ingress {
|
||||
var annotations = make(map[string]string)
|
||||
regexAnnotation := fmt.Sprintf("%s/use-regex", parser.AnnotationsPrefix)
|
||||
if regexEnabled {
|
||||
annotations[regexAnnotation] = "true"
|
||||
}
|
||||
func generateDumbIngressforPathTest(pathType *networkingv1.PathType, path string) *networkingv1.Ingress {
|
||||
return &networkingv1.Ingress{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "dumb",
|
||||
Namespace: "default",
|
||||
Annotations: annotations,
|
||||
Name: "dumb",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: networkingv1.IngressSpec{
|
||||
Rules: []networkingv1.IngressRule{
|
||||
{
|
||||
Host: "test.com",
|
||||
IngressRuleValue: networkingv1.IngressRuleValue{
|
||||
HTTP: &networkingv1.HTTPIngressRuleValue{
|
||||
Paths: []networkingv1.HTTPIngressPath{
|
||||
{
|
||||
PathType: pathType,
|
||||
Path: path,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsSafePath(t *testing.T) {
|
||||
func generateComplexIngress(ing *networkingv1.Ingress) *networkingv1.Ingress {
|
||||
|
||||
oldRules := ing.Spec.DeepCopy().Rules
|
||||
ing.Spec.Rules = []networkingv1.IngressRule{
|
||||
{
|
||||
Host: "test1.com",
|
||||
IngressRuleValue: networkingv1.IngressRuleValue{
|
||||
HTTP: &networkingv1.HTTPIngressRuleValue{
|
||||
Paths: []networkingv1.HTTPIngressPath{
|
||||
{
|
||||
PathType: &pathTypeExact,
|
||||
Path: "/xpto",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Host: "test2.com",
|
||||
IngressRuleValue: networkingv1.IngressRuleValue{
|
||||
HTTP: &networkingv1.HTTPIngressRuleValue{
|
||||
Paths: []networkingv1.HTTPIngressPath{
|
||||
{
|
||||
PathType: &pathTypeExact,
|
||||
Path: "/someotherpath",
|
||||
},
|
||||
{
|
||||
PathType: &pathTypePrefix,
|
||||
Path: "/someprefix/~xpto/lala123",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
// we want to invert the order to test better :)
|
||||
ing.Spec.Rules = append(ing.Spec.Rules, oldRules...)
|
||||
|
||||
return ing
|
||||
}
|
||||
|
||||
var (
|
||||
pathTypeExact = networkingv1.PathTypeExact
|
||||
pathTypePrefix = networkingv1.PathTypePrefix
|
||||
pathTypeImplSpecific = networkingv1.PathTypeImplementationSpecific
|
||||
)
|
||||
|
||||
const (
|
||||
defaultAdditionalChars = "^%$[](){}*+?"
|
||||
)
|
||||
|
||||
func TestValidateIngressPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
copyIng *networkingv1.Ingress
|
||||
path string
|
||||
want bool
|
||||
name string
|
||||
copyIng *networkingv1.Ingress
|
||||
disablePathTypeValidation bool
|
||||
additionalChars string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "should accept valid path with regex disabled",
|
||||
want: true,
|
||||
copyIng: generateDumbIngressforPathTest(false),
|
||||
path: "/xpto/~user/t-e_st.exe",
|
||||
name: "should return nil when ingress = nil",
|
||||
wantErr: false,
|
||||
copyIng: nil,
|
||||
},
|
||||
{
|
||||
name: "should accept valid path / with regex disabled",
|
||||
want: true,
|
||||
copyIng: generateDumbIngressforPathTest(false),
|
||||
path: "/",
|
||||
name: "should accept valid path on pathType Exact",
|
||||
wantErr: false,
|
||||
copyIng: generateDumbIngressforPathTest(&pathTypeExact, "/xpto/~user9/t-e_st.exe"),
|
||||
},
|
||||
{
|
||||
name: "should reject invalid path with invalid chars",
|
||||
want: false,
|
||||
copyIng: generateDumbIngressforPathTest(false),
|
||||
path: "/foo/bar/;xpto",
|
||||
name: "should accept valid path on pathType Prefix",
|
||||
wantErr: false,
|
||||
copyIng: generateDumbIngressforPathTest(&pathTypePrefix, "/xpto/~user9/t-e_st.exe"),
|
||||
},
|
||||
{
|
||||
name: "should reject regex path when regex is disabled",
|
||||
want: false,
|
||||
copyIng: generateDumbIngressforPathTest(false),
|
||||
path: "/foo/bar/(.+)",
|
||||
name: "should accept valid simple path on pathType Impl Specific",
|
||||
wantErr: false,
|
||||
copyIng: generateDumbIngressforPathTest(&pathTypeImplSpecific, "/xpto/~user9/t-e_st.exe"),
|
||||
},
|
||||
{
|
||||
name: "should accept valid path / with regex enabled",
|
||||
want: true,
|
||||
copyIng: generateDumbIngressforPathTest(true),
|
||||
path: "/",
|
||||
name: "should accept valid path on pathType nil",
|
||||
wantErr: false,
|
||||
copyIng: generateDumbIngressforPathTest(nil, "/xpto/~user/t-e_st.exe"),
|
||||
},
|
||||
{
|
||||
name: "should accept regex path when regex is enabled",
|
||||
want: true,
|
||||
copyIng: generateDumbIngressforPathTest(true),
|
||||
path: "/foo/bar/(.+)",
|
||||
name: "should accept empty path",
|
||||
wantErr: false,
|
||||
copyIng: generateDumbIngressforPathTest(&pathTypePrefix, ""),
|
||||
},
|
||||
{
|
||||
name: "should reject regex path when regex is enabled but the path is invalid",
|
||||
want: false,
|
||||
copyIng: generateDumbIngressforPathTest(true),
|
||||
path: "/foo/bar/;xpto",
|
||||
name: "should deny path with bad characters and pathType not implementationSpecific",
|
||||
wantErr: true,
|
||||
additionalChars: defaultAdditionalChars,
|
||||
copyIng: generateDumbIngressforPathTest(&pathTypeExact, "/foo/bar/(.+)"),
|
||||
},
|
||||
{
|
||||
name: "should reject regex path when regex is enabled but the path is invalid",
|
||||
want: false,
|
||||
copyIng: generateDumbIngressforPathTest(true),
|
||||
path: ";xpto",
|
||||
name: "should accept path with regex characters and pathType implementationSpecific",
|
||||
wantErr: false,
|
||||
additionalChars: defaultAdditionalChars,
|
||||
copyIng: generateDumbIngressforPathTest(&pathTypeImplSpecific, "/foo/bar/(.+)"),
|
||||
},
|
||||
{
|
||||
name: "should accept path with regex characters and pathType exact, but pathType validation disabled",
|
||||
wantErr: false,
|
||||
additionalChars: defaultAdditionalChars,
|
||||
disablePathTypeValidation: true,
|
||||
copyIng: generateDumbIngressforPathTest(&pathTypeImplSpecific, "/foo/bar/(.+)"),
|
||||
},
|
||||
{
|
||||
name: "should reject path when the allowed additional set does not match",
|
||||
wantErr: true,
|
||||
additionalChars: "().?",
|
||||
disablePathTypeValidation: false,
|
||||
copyIng: generateDumbIngressforPathTest(&pathTypeImplSpecific, "/foo/bar/(.+)"),
|
||||
},
|
||||
{
|
||||
name: "should accept path when the allowed additional set does match",
|
||||
wantErr: false,
|
||||
additionalChars: "().?",
|
||||
copyIng: generateDumbIngressforPathTest(&pathTypeImplSpecific, "/foo/bar/(.?)"),
|
||||
},
|
||||
{
|
||||
name: "should block if at least one path is bad",
|
||||
wantErr: true,
|
||||
copyIng: generateComplexIngress(generateDumbIngressforPathTest(&pathTypeExact, "/foo/bar/(.?)")),
|
||||
},
|
||||
{
|
||||
name: "should block if at least one path is bad",
|
||||
wantErr: true,
|
||||
copyIng: generateComplexIngress(generateDumbIngressforPathTest(&pathTypeImplSpecific, "/foo/bar/(.?)")),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := IsSafePath(tt.copyIng, tt.path); got != tt.want {
|
||||
t.Errorf("IsSafePath() = %v, want %v", got, tt.want)
|
||||
if err := ValidateIngressPath(tt.copyIng, tt.disablePathTypeValidation, tt.additionalChars); (err != nil) != tt.wantErr {
|
||||
t.Errorf("ValidateIngressPath() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -336,6 +336,9 @@ http {
|
|||
{{ if $cfg.UseGzip }}
|
||||
gzip on;
|
||||
gzip_comp_level {{ $cfg.GzipLevel }};
|
||||
{{- if $cfg.GzipDisable }}
|
||||
gzip_disable "{{ $cfg.GzipDisable }}";
|
||||
{{- end }}
|
||||
gzip_http_version 1.1;
|
||||
gzip_min_length {{ $cfg.GzipMinLength}};
|
||||
gzip_types {{ $cfg.GzipTypes }};
|
||||
|
|
|
@ -41,12 +41,22 @@ reportFileNamePrefix="report-e2e-test-suite"
|
|||
echo -e "${BGREEN}Running e2e test suite (FOCUS=${FOCUS})...${NC}"
|
||||
ginkgo "${ginkgo_args[@]}" \
|
||||
-focus="${FOCUS}" \
|
||||
-skip="\[Serial\]|\[MemoryLeak\]" \
|
||||
-skip="\[Serial\]|\[MemoryLeak\]|\[TopologyHints\]" \
|
||||
-nodes="${E2E_NODES}" \
|
||||
--junit-report=$reportFileNamePrefix.xml \
|
||||
/e2e.test
|
||||
# Create configMap out of a compressed report file for extraction later
|
||||
|
||||
# Must be isolated, there is a collision if multiple helms tries to install same clusterRole at same time
|
||||
echo -e "${BGREEN}Running e2e test for topology aware hints...${NC}"
|
||||
ginkgo "${ginkgo_args[@]}" \
|
||||
-focus="\[TopologyHints\]" \
|
||||
-skip="\[Serial\]|\[MemoryLeak\]]" \
|
||||
-nodes="${E2E_NODES}" \
|
||||
--junit-report=$reportFileNamePrefix-topology.xml \
|
||||
/e2e.test
|
||||
# Create configMap out of a compressed report file for extraction later
|
||||
|
||||
echo -e "${BGREEN}Running e2e test suite with tests that require serial execution...${NC}"
|
||||
ginkgo "${ginkgo_args[@]}" \
|
||||
-focus="\[Serial\]" \
|
||||
|
|
51
test/e2e-image/namespace-overlays/topology/values.yaml
Normal file
51
test/e2e-image/namespace-overlays/topology/values.yaml
Normal file
|
@ -0,0 +1,51 @@
|
|||
# TODO: remove the need to use fullnameOverride
|
||||
fullnameOverride: nginx-ingress
|
||||
controller:
|
||||
image:
|
||||
repository: ingress-controller/controller
|
||||
chroot: true
|
||||
tag: 1.0.0-dev
|
||||
digest:
|
||||
digestChroot:
|
||||
scope:
|
||||
enabled: false
|
||||
config:
|
||||
worker-processes: "1"
|
||||
readinessProbe:
|
||||
initialDelaySeconds: 3
|
||||
periodSeconds: 1
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 3
|
||||
periodSeconds: 1
|
||||
service:
|
||||
type: NodePort
|
||||
electionID: ingress-controller-leader
|
||||
ingressClassResource:
|
||||
# We will create and remove each IC/ClusterRole/ClusterRoleBinding per test so there's no conflict
|
||||
enabled: false
|
||||
extraArgs:
|
||||
tcp-services-configmap: $NAMESPACE/tcp-services
|
||||
# e2e tests do not require information about ingress status
|
||||
update-status: "false"
|
||||
terminationGracePeriodSeconds: 1
|
||||
admissionWebhooks:
|
||||
enabled: false
|
||||
|
||||
enableTopologyAwareRouting: true
|
||||
|
||||
# ulimit -c unlimited
|
||||
# mkdir -p /tmp/coredump
|
||||
# chmod a+rwx /tmp/coredump
|
||||
# echo "/tmp/coredump/core.%e.%p.%h.%t" > /proc/sys/kernel/core_pattern
|
||||
extraVolumeMounts:
|
||||
- name: coredump
|
||||
mountPath: /tmp/coredump
|
||||
|
||||
extraVolumes:
|
||||
- name: coredump
|
||||
hostPath:
|
||||
path: /tmp/coredump
|
||||
|
||||
rbac:
|
||||
create: true
|
||||
scope: false
|
|
@ -30,6 +30,14 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"k8s.io/ingress-nginx/test/e2e/framework"
|
||||
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
)
|
||||
|
||||
var (
|
||||
pathExact = networkingv1.PathTypeExact
|
||||
pathPrefix = networkingv1.PathTypePrefix
|
||||
pathImplSpecific = networkingv1.PathTypeImplementationSpecific
|
||||
)
|
||||
|
||||
var _ = framework.IngressNginxDescribe("[Serial] admission controller", func() {
|
||||
|
@ -152,6 +160,32 @@ var _ = framework.IngressNginxDescribe("[Serial] admission controller", func() {
|
|||
assert.NotNil(ginkgo.GinkgoT(), err, "creating an ingress with invalid annotation value should return an error")
|
||||
})
|
||||
|
||||
ginkgo.It("should reject ingress with bad characters and pathType != ImplementationSpecific", func() {
|
||||
host := "admission-test"
|
||||
|
||||
firstIngress := framework.NewSingleIngress("first-ingress", "/xpto*", host, f.Namespace, framework.EchoService, 80, nil)
|
||||
firstIngress.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].PathType = &pathPrefix
|
||||
_, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), firstIngress, metav1.CreateOptions{})
|
||||
assert.NotNil(ginkgo.GinkgoT(), err, "creating an ingress with invalid path value should return an error")
|
||||
|
||||
secondIngress := framework.NewSingleIngress("second-ingress", "/abc123*", host, f.Namespace, framework.EchoService, 80, nil)
|
||||
secondIngress.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].PathType = &pathImplSpecific
|
||||
_, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), secondIngress, metav1.CreateOptions{})
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "creating an ingress with regex on path and pathType ImplementationSpecific should not return an error")
|
||||
|
||||
})
|
||||
|
||||
ginkgo.It("should not validate characters on ingress when validation of pathType is disabled", func() {
|
||||
host := "admission-test"
|
||||
|
||||
f.UpdateNginxConfigMapData("disable-pathtype-validation", "true")
|
||||
|
||||
firstIngress := framework.NewSingleIngress("first-ingress", "/xpto*", host, f.Namespace, framework.EchoService, 80, nil)
|
||||
firstIngress.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].PathType = &pathPrefix
|
||||
_, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), firstIngress, metav1.CreateOptions{})
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "creating an ingress with regex chars on path and pathType validation disabled should be accepted")
|
||||
})
|
||||
|
||||
ginkgo.It("should return an error if there is a forbidden value in some annotation", func() {
|
||||
host := "admission-test"
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@ import (
|
|||
var _ = framework.DescribeAnnotation("affinity session-cookie-name", func() {
|
||||
f := framework.NewDefaultFramework("affinity")
|
||||
|
||||
pathImpl := networking.PathTypeImplementationSpecific
|
||||
|
||||
ginkgo.BeforeEach(func() {
|
||||
f.NewEchoDeployment(framework.WithDeploymentReplicas(2))
|
||||
})
|
||||
|
@ -276,6 +278,8 @@ var _ = framework.DescribeAnnotation("affinity session-cookie-name", func() {
|
|||
annotations["nginx.ingress.kubernetes.io/session-cookie-path"] = "/foo/bar"
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/foo/.*", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
ing.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].PathType = &pathImpl
|
||||
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
|
@ -299,6 +303,8 @@ var _ = framework.DescribeAnnotation("affinity session-cookie-name", func() {
|
|||
annotations["nginx.ingress.kubernetes.io/use-regex"] = "true"
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/foo/.*", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
ing.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].PathType = &pathImpl
|
||||
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
|
|
|
@ -24,12 +24,15 @@ import (
|
|||
"github.com/onsi/ginkgo/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
networking "k8s.io/api/networking/v1"
|
||||
"k8s.io/ingress-nginx/test/e2e/framework"
|
||||
)
|
||||
|
||||
var _ = framework.DescribeAnnotation("rewrite-target use-regex enable-rewrite-log", func() {
|
||||
f := framework.NewDefaultFramework("rewrite")
|
||||
|
||||
pathImpl := networking.PathTypeImplementationSpecific
|
||||
|
||||
ginkgo.BeforeEach(func() {
|
||||
f.NewEchoDeployment()
|
||||
})
|
||||
|
@ -126,6 +129,7 @@ var _ = framework.DescribeAnnotation("rewrite-target use-regex enable-rewrite-lo
|
|||
"nginx.ingress.kubernetes.io/rewrite-target": "/new/backend",
|
||||
}
|
||||
ing = framework.NewSingleIngress("regex", "/foo.+", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
ing.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].PathType = &pathImpl
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
|
@ -168,6 +172,8 @@ var _ = framework.DescribeAnnotation("rewrite-target use-regex enable-rewrite-lo
|
|||
"nginx.ingress.kubernetes.io/rewrite-target": "/new/backend",
|
||||
}
|
||||
ing = framework.NewSingleIngress("regex", "/foo/bar/[a-z]{3}", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
ing.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].PathType = &pathImpl
|
||||
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
|
@ -196,6 +202,8 @@ var _ = framework.DescribeAnnotation("rewrite-target use-regex enable-rewrite-lo
|
|||
"nginx.ingress.kubernetes.io/rewrite-target": "/new/backend/$1",
|
||||
}
|
||||
ing := framework.NewSingleIngress("regex", "/foo/bar/(.+)", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
ing.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].PathType = &pathImpl
|
||||
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
|
|
112
test/e2e/endpointslices/topology.go
Normal file
112
test/e2e/endpointslices/topology.go
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
Copyright 2022 The Kubernetes 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 endpointslices
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/onsi/ginkgo/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/nginx"
|
||||
"k8s.io/ingress-nginx/test/e2e/framework"
|
||||
)
|
||||
|
||||
var _ = framework.IngressNginxDescribe("[TopologyHints] topology aware routing", func() {
|
||||
f := framework.NewDefaultFramework("topology")
|
||||
host := "topology-svc.foo.com"
|
||||
|
||||
ginkgo.BeforeEach(func() {
|
||||
f.NewEchoDeployment(framework.WithDeploymentReplicas(2), framework.WithSvcTopologyAnnotations())
|
||||
})
|
||||
|
||||
ginkgo.AfterEach(func() {
|
||||
// we need to uninstall chart because of clusterRole which is not destroyed with namespace
|
||||
err := uninstallChart(f)
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "uninstalling helm chart")
|
||||
})
|
||||
|
||||
ginkgo.It("should return 200 when service has topology hints", func() {
|
||||
|
||||
annotations := make(map[string]string)
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host, func(server string) bool {
|
||||
return strings.Contains(server, fmt.Sprintf("server_name %s", host))
|
||||
})
|
||||
|
||||
ginkgo.By("checking if the service is reached")
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
|
||||
slices, err := f.KubeClientSet.DiscoveryV1().EndpointSlices(f.Namespace).List(context.TODO(), metav1.ListOptions{
|
||||
LabelSelector: "kubernetes.io/service-name=echo",
|
||||
Limit: 1,
|
||||
})
|
||||
assert.Nil(ginkgo.GinkgoT(), err)
|
||||
|
||||
// check if we have hints, really depends on k8s endpoint slice controller
|
||||
gotHints := true
|
||||
for _, ep := range slices.Items[0].Endpoints {
|
||||
if ep.Hints == nil || len(ep.Hints.ForZones) == 0 {
|
||||
gotHints = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
curlCmd := fmt.Sprintf("curl --fail --silent http://localhost:%v/configuration/backends", nginx.StatusPort)
|
||||
status, err := f.ExecIngressPod(curlCmd)
|
||||
assert.Nil(ginkgo.GinkgoT(), err)
|
||||
var backends []map[string]interface{}
|
||||
json.Unmarshal([]byte(status), &backends)
|
||||
gotBackends := 0
|
||||
for _, bck := range backends {
|
||||
if strings.Contains(bck["name"].(string), "topology") {
|
||||
gotBackends = len(bck["endpoints"].([]interface{}))
|
||||
}
|
||||
}
|
||||
|
||||
if gotHints {
|
||||
//we have 2 replics, if there is just one backend it means that we are routing according slices hints to same zone as controller is
|
||||
assert.Equal(ginkgo.GinkgoT(), 1, gotBackends)
|
||||
} else {
|
||||
// two replicas should have two endpoints without topology hints
|
||||
assert.Equal(ginkgo.GinkgoT(), 2, gotBackends)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
func uninstallChart(f *framework.Framework) error {
|
||||
cmd := exec.Command("helm", "uninstall", "--namespace", f.Namespace, "nginx-ingress")
|
||||
_, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unexpected error uninstalling ingress-nginx release: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -40,10 +40,10 @@ const SlowEchoService = "slow-echo"
|
|||
const HTTPBinService = "httpbin"
|
||||
|
||||
type deploymentOptions struct {
|
||||
namespace string
|
||||
name string
|
||||
replicas int
|
||||
image string
|
||||
namespace string
|
||||
name string
|
||||
replicas int
|
||||
svcAnnotations map[string]string
|
||||
}
|
||||
|
||||
// WithDeploymentNamespace allows configuring the deployment's namespace
|
||||
|
@ -53,6 +53,15 @@ func WithDeploymentNamespace(n string) func(*deploymentOptions) {
|
|||
}
|
||||
}
|
||||
|
||||
// WithSvcTopologyAnnotations create svc with topology aware hints sets to auto
|
||||
func WithSvcTopologyAnnotations() func(*deploymentOptions) {
|
||||
return func(o *deploymentOptions) {
|
||||
o.svcAnnotations = map[string]string{
|
||||
"service.kubernetes.io/topology-aware-hints": "auto",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithDeploymentName allows configuring the deployment's names
|
||||
func WithDeploymentName(n string) func(*deploymentOptions) {
|
||||
return func(o *deploymentOptions) {
|
||||
|
@ -95,8 +104,9 @@ func (f *Framework) NewEchoDeployment(opts ...func(*deploymentOptions)) {
|
|||
|
||||
service := &corev1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: options.name,
|
||||
Namespace: options.namespace,
|
||||
Name: options.name,
|
||||
Namespace: options.namespace,
|
||||
Annotations: options.svcAnnotations,
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
Ports: []corev1.ServicePort{
|
||||
|
|
|
@ -2,8 +2,14 @@ kind: Cluster
|
|||
apiVersion: kind.x-k8s.io/v1alpha4
|
||||
nodes:
|
||||
- role: control-plane
|
||||
labels:
|
||||
topology.kubernetes.io/zone: zone-1
|
||||
- role: worker
|
||||
labels:
|
||||
topology.kubernetes.io/zone: zone-1
|
||||
- role: worker
|
||||
labels:
|
||||
topology.kubernetes.io/zone: zone-2
|
||||
kubeadmConfigPatches:
|
||||
- |
|
||||
kind: ClusterConfiguration
|
||||
|
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
Copyright 2022 The Kubernetes 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 security
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/onsi/ginkgo/v2"
|
||||
|
||||
"k8s.io/ingress-nginx/test/e2e/framework"
|
||||
)
|
||||
|
||||
const (
|
||||
validPath = "/xpto/~user/t-e_st.exe"
|
||||
invalidPath = "/foo/bar/;xpto"
|
||||
regexPath = "/foo/bar/(.+)"
|
||||
host = "securitytest.com"
|
||||
)
|
||||
|
||||
var (
|
||||
annotationRegex = map[string]string{
|
||||
"nginx.ingress.kubernetes.io/use-regex": "true",
|
||||
}
|
||||
)
|
||||
|
||||
var _ = framework.IngressNginxDescribe("[Security] validate path fields", func() {
|
||||
f := framework.NewDefaultFramework("validate-path")
|
||||
|
||||
ginkgo.BeforeEach(func() {
|
||||
f.NewEchoDeployment()
|
||||
})
|
||||
|
||||
ginkgo.It("should accept an ingress with valid path", func() {
|
||||
|
||||
ing := framework.NewSingleIngress(host, validPath, host, f.Namespace, framework.EchoService, 80, nil)
|
||||
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
func(server string) bool {
|
||||
return strings.Contains(server, fmt.Sprintf("server_name %s ;", host))
|
||||
})
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET(validPath).
|
||||
WithHeader("Host", host).
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
})
|
||||
|
||||
ginkgo.It("should drop an ingress with invalid path", func() {
|
||||
|
||||
ing := framework.NewSingleIngress(host, invalidPath, host, f.Namespace, framework.EchoService, 80, nil)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
func(server string) bool {
|
||||
return !strings.Contains(server, fmt.Sprintf("server_name %s ;", host))
|
||||
})
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET(invalidPath).
|
||||
WithHeader("Host", host).
|
||||
Expect().
|
||||
Status(http.StatusNotFound)
|
||||
})
|
||||
|
||||
ginkgo.It("should drop an ingress with regex path and regex disabled", func() {
|
||||
|
||||
ing := framework.NewSingleIngress(host, regexPath, host, f.Namespace, framework.EchoService, 80, nil)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
func(server string) bool {
|
||||
return !strings.Contains(server, fmt.Sprintf("server_name %s ;", host))
|
||||
})
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/foo/bar/lalala").
|
||||
WithHeader("Host", host).
|
||||
Expect().
|
||||
Status(http.StatusNotFound)
|
||||
})
|
||||
|
||||
ginkgo.It("should accept an ingress with regex path and regex enabled", func() {
|
||||
|
||||
ing := framework.NewSingleIngress(host, regexPath, host, f.Namespace, framework.EchoService, 80, annotationRegex)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
func(server string) bool {
|
||||
return strings.Contains(server, fmt.Sprintf("server_name %s ;", host))
|
||||
})
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/foo/bar/lalala").
|
||||
WithHeader("Host", host).
|
||||
Expect().
|
||||
Status(http.StatusOK)
|
||||
})
|
||||
|
||||
ginkgo.It("should reject an ingress with invalid path and regex enabled", func() {
|
||||
|
||||
ing := framework.NewSingleIngress(host, invalidPath, host, f.Namespace, framework.EchoService, 80, annotationRegex)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
func(server string) bool {
|
||||
return !strings.Contains(server, fmt.Sprintf("server_name %s ;", host))
|
||||
})
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET(invalidPath).
|
||||
WithHeader("Host", host).
|
||||
Expect().
|
||||
Status(http.StatusNotFound)
|
||||
})
|
||||
})
|
99
test/e2e/settings/gzip.go
Normal file
99
test/e2e/settings/gzip.go
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
Copyright 2023 The Kubernetes 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 settings
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/onsi/ginkgo/v2"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress/controller/config"
|
||||
"k8s.io/ingress-nginx/test/e2e/framework"
|
||||
)
|
||||
|
||||
var _ = framework.DescribeSetting("gzip", func() {
|
||||
f := framework.NewDefaultFramework("gzip")
|
||||
|
||||
ginkgo.It("should be disabled by default", func() {
|
||||
f.WaitForNginxConfiguration(
|
||||
func(cfg string) bool {
|
||||
return !strings.Contains(cfg, "gzip on;")
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.It("should be enabled with default settings", func() {
|
||||
f.UpdateNginxConfigMapData("use-gzip", "true")
|
||||
|
||||
f.WaitForNginxConfiguration(
|
||||
func(cfg string) bool {
|
||||
defaultCfg := config.NewDefault()
|
||||
return strings.Contains(cfg, "gzip on;") &&
|
||||
strings.Contains(cfg, fmt.Sprintf("gzip_comp_level %d;", defaultCfg.GzipLevel)) &&
|
||||
!strings.Contains(cfg, "gzip_disable") &&
|
||||
strings.Contains(cfg, "gzip_http_version 1.1;") &&
|
||||
strings.Contains(cfg, fmt.Sprintf("gzip_min_length %d;", defaultCfg.GzipMinLength)) &&
|
||||
strings.Contains(cfg, fmt.Sprintf("gzip_types %s;", defaultCfg.GzipTypes)) &&
|
||||
strings.Contains(cfg, "gzip_proxied any;") &&
|
||||
strings.Contains(cfg, "gzip_vary on;")
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.It("should set gzip_comp_level to 4", func() {
|
||||
f.UpdateNginxConfigMapData("use-gzip", "true")
|
||||
f.UpdateNginxConfigMapData("gzip-level", "4")
|
||||
|
||||
f.WaitForNginxConfiguration(
|
||||
func(cfg string) bool {
|
||||
return strings.Contains(cfg, "gzip on;") &&
|
||||
strings.Contains(cfg, "gzip_comp_level 4;")
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.It("should set gzip_disable to msie6", func() {
|
||||
f.UpdateNginxConfigMapData("use-gzip", "true")
|
||||
f.UpdateNginxConfigMapData("gzip-disable", "msie6")
|
||||
|
||||
f.WaitForNginxConfiguration(
|
||||
func(cfg string) bool {
|
||||
return strings.Contains(cfg, "gzip on;") &&
|
||||
strings.Contains(cfg, `gzip_disable "msie6";`)
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.It("should set gzip_min_length to 100", func() {
|
||||
f.UpdateNginxConfigMapData("use-gzip", "true")
|
||||
f.UpdateNginxConfigMapData("gzip-min-length", "100")
|
||||
|
||||
f.WaitForNginxConfiguration(
|
||||
func(cfg string) bool {
|
||||
return strings.Contains(cfg, "gzip on;") &&
|
||||
strings.Contains(cfg, "gzip_min_length 100;")
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.It("should set gzip_types to application/javascript", func() {
|
||||
f.UpdateNginxConfigMapData("use-gzip", "true")
|
||||
f.UpdateNginxConfigMapData("gzip-types", "application/javascript")
|
||||
|
||||
f.WaitForNginxConfiguration(
|
||||
func(cfg string) bool {
|
||||
return strings.Contains(cfg, "gzip on;") &&
|
||||
strings.Contains(cfg, "gzip_types application/javascript;")
|
||||
})
|
||||
})
|
||||
})
|
|
@ -19,6 +19,7 @@ package settings
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
v1 "k8s.io/api/networking/v1"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
|
@ -28,7 +29,6 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
||||
|
@ -87,7 +87,7 @@ var _ = framework.IngressNginxDescribe("[Status] status update", func() {
|
|||
ing, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error getting %s/%v Ingress", f.Namespace, host)
|
||||
|
||||
ing.Status.LoadBalancer.Ingress = []apiv1.LoadBalancerIngress{}
|
||||
ing.Status.LoadBalancer.Ingress = []v1.IngressLoadBalancerIngress{}
|
||||
_, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).UpdateStatus(context.TODO(), ing, metav1.UpdateOptions{})
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error cleaning Ingress status")
|
||||
framework.Sleep(10 * time.Second)
|
||||
|
@ -121,9 +121,9 @@ var _ = framework.IngressNginxDescribe("[Status] status update", func() {
|
|||
return true, nil
|
||||
})
|
||||
assert.Nil(ginkgo.GinkgoT(), err, "unexpected error waiting for ingress status")
|
||||
assert.Equal(ginkgo.GinkgoT(), ing.Status.LoadBalancer.Ingress, ([]apiv1.LoadBalancerIngress{
|
||||
assert.Equal(ginkgo.GinkgoT(), ing.Status.LoadBalancer.Ingress, []v1.IngressLoadBalancerIngress{
|
||||
{IP: "1.1.0.0"},
|
||||
}))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in a new issue