Merge remote-tracking branch 'upstream/main' into otel2
This commit is contained in:
commit
f5f3edb7ad
64 changed files with 3665 additions and 919 deletions
12
.github/workflows/helm.yaml
vendored
12
.github/workflows/helm.yaml
vendored
|
@ -25,6 +25,18 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
|
||||
|
||||
- name: Run Artifact Hub lint
|
||||
run: |
|
||||
wget https://github.com/artifacthub/hub/releases/download/v1.5.0/ah_1.5.0_linux_amd64.tar.gz
|
||||
echo 'ad0e44c6ea058ab6b85dbf582e88bad9fdbc64ded0d1dd4edbac65133e5c87da *ah_1.5.0_linux_amd64.tar.gz' | shasum -c
|
||||
tar -xzvf ah_1.5.0_linux_amd64.tar.gz ah
|
||||
./ah lint -p charts/ingress-nginx || exit 1
|
||||
rm -f ./ah ./ah_1.5.0_linux_amd64.tar.gz
|
||||
|
||||
- name: Lint
|
||||
run: |
|
||||
./build/run-in-docker.sh ./hack/verify-chart-lint.sh
|
||||
|
||||
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1
|
||||
id: filter
|
||||
with:
|
||||
|
|
15
Changelog.md.gotmpl
Normal file
15
Changelog.md.gotmpl
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Changelog
|
||||
|
||||
### {{ .Version }}
|
||||
Images:
|
||||
{{ with .ControllerImages }}
|
||||
{{ range . }} * {{ .Registry }}/{{ .Name }}:{{ .Tag}}@{{ .Digest }}
|
||||
{{ end }} {{ end }}
|
||||
### All Changes:
|
||||
{{ with .Updates }}
|
||||
{{ range . }}* {{ . }}
|
||||
{{ end }}{{ end }}
|
||||
### Dependencies updates: {{ with .DepUpdates }}
|
||||
{{ range . }}* {{ . }}
|
||||
{{ end }} {{ end }}
|
||||
**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/controller-{{ .PreviousControllerVersion }}...controller-{{ .NewControllerVersion }}
|
|
@ -103,7 +103,7 @@ Promoting the images basically means that images, that were pushed to staging co
|
|||
|
||||
- Fork that other project (if you don't have a fork already).
|
||||
|
||||
- Other project to fork [Github repo kubernetes/k8s.io](http://github.com/kubernetes/k8s.io)
|
||||
- Other project to fork [GitHub repo kubernetes/k8s.io](http://github.com/kubernetes/k8s.io)
|
||||
|
||||
- Fetch --all and rebase to upstream if already forked.
|
||||
|
||||
|
@ -111,7 +111,7 @@ Promoting the images basically means that images, that were pushed to staging co
|
|||
|
||||
- In the related branch, of your fork, edit the file /registry.k8s.io/images/k8s-staging-ingress-nginx/images.yaml.
|
||||
|
||||
- For making it easier, you can edit your branch directly in the browser. But be careful about making any mistake.
|
||||
- For making, it easier, you can edit your branch directly in the browser. But be careful about making any mistake.
|
||||
|
||||
- Insert the sha(s) & the tag(s), in a new line, in this file [Project kubernetes/k8s.io Ingress-Nginx-Controller Images](https://github.com/kubernetes/k8s.io/blob/main/k8s.gcr.io/images/k8s-staging-ingress-nginx/images.yaml) Look at this [example PR and the diff](https://github.com/kubernetes/k8s.io/pull/2536) to see how it was done before
|
||||
|
||||
|
@ -132,7 +132,7 @@ Promoting the images basically means that images, that were pushed to staging co
|
|||
|
||||
- Make sure to get the tag and sha of the promoted image from the step before, either from cloudbuild or from [here](https://console.cloud.google.com/gcr/images/k8s-artifacts-prod/us/ingress-nginx/controller).
|
||||
|
||||
- This involves editing of several different files. So carefully follow the steps below and double check all changes with diff/grep etc., repeatedly. Mistakes here impact endusers.
|
||||
- This involves editing of several files. So carefully follow the steps below and double check all changes with diff/grep etc., repeatedly. Mistakes here impact endusers.
|
||||
|
||||
### a. Make sure your git workspace is ready
|
||||
|
||||
|
@ -160,7 +160,7 @@ Promoting the images basically means that images, that were pushed to staging co
|
|||
- [TAG](https://github.com/kubernetes/ingress-nginx/blob/main/TAG#L1)
|
||||
|
||||
### c. Edit the helm Chart
|
||||
- Change the below mentioned [Fields in Chart.yaml](https://github.com/kubernetes/ingress-nginx/blob/main/charts/ingress-nginx/Chart.yaml)
|
||||
- Change the below-mentioned [Fields in Chart.yaml](https://github.com/kubernetes/ingress-nginx/blob/main/charts/ingress-nginx/Chart.yaml)
|
||||
- version
|
||||
- appVersion
|
||||
- kubeVersion (**ONLY if applicable**)
|
||||
|
@ -168,7 +168,7 @@ Promoting the images basically means that images, that were pushed to staging co
|
|||
- artifacthub.io/prerelease: "true"
|
||||
- artifacthub.io/changes: |
|
||||
- Replace this line and other lines under this annotation with the Changelog. One process to generate the Changelog is described below
|
||||
- Install and configure github cli as per the docs of gh-cli https://cli.github.com/,
|
||||
- Install and configure GitHub cli as per the docs of gh-cli https://cli.github.com/,
|
||||
- Change dir to your clone, of your fork, of the ingress-nginx project
|
||||
- Run the below command and save the output to a txt file
|
||||
|
4
Makefile
4
Makefile
|
@ -153,11 +153,11 @@ lua-test: ## Run lua unit tests.
|
|||
|
||||
.PHONY: e2e-test
|
||||
e2e-test: ## Run e2e tests (expects access to a working Kubernetes cluster).
|
||||
@build/run-e2e-suite.sh
|
||||
@test/e2e/run-e2e-suite.sh
|
||||
|
||||
.PHONY: kind-e2e-test
|
||||
kind-e2e-test: ## Run e2e tests using kind.
|
||||
@test/e2e/run.sh
|
||||
@test/e2e/run-kind-e2e.sh
|
||||
|
||||
.PHONY: kind-e2e-chart-tests
|
||||
kind-e2e-chart-tests: ## Run helm chart e2e tests
|
||||
|
|
9
NEW_RELEASE_PROCESS.md
Normal file
9
NEW_RELEASE_PROCESS.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Semi-Automated Release Process
|
||||
|
||||
1. Update TAG
|
||||
2. Cloud Build
|
||||
3. k8s.io PR
|
||||
4. git pull origin main
|
||||
5. git checkout -b $RELEASE_VERSION
|
||||
6. mage release:newrelease $RELEASE_VERSION
|
||||
7. Wait for PR
|
2
TAG
2
TAG
|
@ -1 +1 @@
|
|||
v1.5.1
|
||||
v1.6.2
|
|
@ -3,6 +3,7 @@
|
|||
### 1.5.2
|
||||
Images:
|
||||
|
||||
<<<<<<< HEAD
|
||||
* registry.k8s.io/ingress-nginx/controller:controller-v1.5.2@sha256:3870522ed937c9efb94bfa31a7eb16009831567a0d4cbe01846fc5486d622655
|
||||
* registry.k8s.io/ingress-nginx/controller-chroot:controller-v1.5.2@sha256:84613555694f2c59a8b2551126d226c9aa648544ebf0cde1e0df942f7dbce42b
|
||||
|
||||
|
@ -19,6 +20,24 @@ Images:
|
|||
* update the nginx run container for alpine:3.17.0 (#9430)
|
||||
* cleanup: remove ioutil for new go version (#9427)
|
||||
* start upgrade to golang 1.19.4 and alpine 3.17.0 (#9417)
|
||||
=======
|
||||
* registry.k8s.io/controller:controller-v1.5.2@sha256:c1c091b88a6c936a83bd7g098v62f60a87868d12452529bad0d178fb36143346
|
||||
* registry.k8s.io/controller-chroot:controller-v1.5.2@sha256:c1c091b88a6c936a83bd7b098662760a87868d12452529b350d178fb36147345
|
||||
|
||||
### All Changes:
|
||||
|
||||
<<<<<<< HEAD
|
||||
>>>>>>> f4164ae0b (THE CHANGELOG WORKS)
|
||||
=======
|
||||
* upgrade nginx base image (#9436)
|
||||
* test the new e2e test images (#9444)
|
||||
* avoid builds and tests for non-code changes (#9392)
|
||||
* CI updates (#9440)
|
||||
* HPA: Add `controller.autoscaling.annotations` to `values.yaml`. (#9253)
|
||||
* update the nginx run container for alpine:3.17.0 (#9430)
|
||||
* cleanup: remove ioutil for new go version (#9427)
|
||||
* start upgrade to golang 1.19.4 and alpine 3.17.0 (#9417)
|
||||
>>>>>>> 9ecab7d85 (e2e doc updates work now)
|
||||
* ci: remove setup-helm step (#9404)
|
||||
* ci: remove setup-kind step (#9401)
|
||||
* Add reporter for all tests (#9395)
|
||||
|
@ -54,6 +73,10 @@ Images:
|
|||
* add containerSecurityContext to extraModules init containers (kubernetes#9016) (#9242)
|
||||
|
||||
### Dependencies updates:
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
>>>>>>> 9ecab7d85 (e2e doc updates work now)
|
||||
* Bump golang.org/x/crypto from 0.3.0 to 0.4.0 (#9397)
|
||||
* Bump github.com/onsi/ginkgo/v2 from 2.6.0 to 2.6.1 (#9432)
|
||||
* Bump github.com/onsi/ginkgo/v2 from 2.6.0 to 2.6.1 (#9421)
|
||||
|
@ -62,6 +85,11 @@ Images:
|
|||
* Bump goreleaser/goreleaser-action from 3.2.0 to 4.1.0 (#9426)
|
||||
* Bump actions/dependency-review-action from 3.0.1 to 3.0.2 (#9424)
|
||||
* Bump ossf/scorecard-action from 2.0.6 to 2.1.0 (#9422)
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
>>>>>>> f4164ae0b (THE CHANGELOG WORKS)
|
||||
=======
|
||||
>>>>>>> 9ecab7d85 (e2e doc updates work now)
|
||||
* Bump github.com/prometheus/common from 0.37.0 to 0.39.0 (#9416)
|
||||
* Bump github.com/onsi/ginkgo/v2 from 2.5.1 to 2.6.0 (#9408)
|
||||
* Bump github.com/onsi/ginkgo/v2 from 2.5.1 to 2.6.0 (#9398)
|
||||
|
@ -76,4 +104,12 @@ Images:
|
|||
* Bump actions/dependency-review-action from 2.5.1 to 3.0.0 (#9301)
|
||||
* Bump k8s.io/component-base from 0.25.3 to 0.25.4 (#9300)
|
||||
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/controller-controller-v1.5.1...controller-controller-v1.5.2
|
||||
=======
|
||||
**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/controller-controller-v1.5.2...controller-controller-v1.5.1
|
||||
>>>>>>> f4164ae0b (THE CHANGELOG WORKS)
|
||||
=======
|
||||
**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/controller-controller-v1.5.1...controller-controller-v1.5.2
|
||||
>>>>>>> 9ecab7d85 (e2e doc updates work now)
|
||||
|
|
|
@ -253,6 +253,7 @@ Kubernetes: `>=1.20.0-0`
|
|||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| commonLabels | object | `{}` | |
|
||||
| controller.EnablePathTypeValidation | bool | `false` | This configuration defines if Ingress Controller should validate pathType. If false, special characters will be allowed on paths of any pathType. If true, special characters are only allowed on paths with pathType = ImplementationSpecific |
|
||||
| controller.addHeaders | object | `{}` | Will add custom headers before sending response traffic to the client according to: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#add-headers |
|
||||
| controller.admissionWebhooks.annotations | object | `{}` | |
|
||||
| controller.admissionWebhooks.certManager.admissionCert.duration | string | `""` | |
|
||||
|
@ -315,6 +316,7 @@ Kubernetes: `>=1.20.0-0`
|
|||
| 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"` | |
|
||||
|
|
0
charts/ingress-nginx/changelog/.gitkeep
Normal file
0
charts/ingress-nginx/changelog/.gitkeep
Normal file
12
charts/ingress-nginx/changelog/Changelog-1.5.2.md
Normal file
12
charts/ingress-nginx/changelog/Changelog-1.5.2.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Changelog
|
||||
|
||||
This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
|
||||
|
||||
### 4.4.1
|
||||
|
||||
* ci: remove setup-helm step (#9404)
|
||||
* feat(helm): Optionally use cert-manager instead admission patch (#9279)
|
||||
* run helm release on main only and when the chart/value changes only (#9290)
|
||||
* Update Ingress-Nginx version controller-v1.5.2
|
||||
|
||||
**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.4.1...helm-chart-4.4.1
|
|
@ -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 }}"
|
||||
enable-pathtype-validation: "{{ .Values.controller.EnablePathTypeValidation }}"
|
||||
{{- 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 false, special characters will be allowed on paths of any pathType.
|
||||
# If true, special characters are only allowed on paths with pathType = ImplementationSpecific
|
||||
EnablePathTypeValidation: 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: ""
|
||||
|
||||
|
|
|
@ -1312,7 +1312,7 @@
|
|||
"targets": [
|
||||
{
|
||||
"exemplar": true,
|
||||
"expr": "histogram_quantile(0.80, sum(rate(nginx_ingress_controller_request_duration_seconds_bucket{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\",exported_namespace=\"uat\"}[2m])) by (le))",
|
||||
"expr": "histogram_quantile(0.80, sum(rate(nginx_ingress_controller_request_duration_seconds_bucket{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (le))",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"instant": false,
|
||||
|
@ -1323,7 +1323,7 @@
|
|||
},
|
||||
{
|
||||
"exemplar": true,
|
||||
"expr": "histogram_quantile(0.90, sum(rate(nginx_ingress_controller_request_duration_seconds_bucket{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\",exported_namespace=\"uat\"}[2m])) by (le))",
|
||||
"expr": "histogram_quantile(0.90, sum(rate(nginx_ingress_controller_request_duration_seconds_bucket{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (le))",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"instant": false,
|
||||
|
@ -1335,7 +1335,7 @@
|
|||
{
|
||||
"editorMode": "code",
|
||||
"exemplar": true,
|
||||
"expr": "histogram_quantile(0.99, sum(rate(nginx_ingress_controller_request_duration_seconds_bucket{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\",exported_namespace=\"uat\"}[2m])) by (le))",
|
||||
"expr": "histogram_quantile(0.99, sum(rate(nginx_ingress_controller_request_duration_seconds_bucket{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (le))",
|
||||
"format": "time_series",
|
||||
"hide": false,
|
||||
"instant": false,
|
||||
|
@ -1377,7 +1377,7 @@
|
|||
"targets": [
|
||||
{
|
||||
"exemplar": true,
|
||||
"expr": "sum(increase(nginx_ingress_controller_request_duration_seconds_bucket{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\",exported_namespace=\"uat\"}[2m])) by (le)",
|
||||
"expr": "sum(increase(nginx_ingress_controller_request_duration_seconds_bucket{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (le)",
|
||||
"format": "heatmap",
|
||||
"interval": "",
|
||||
"legendFormat": "{{le}}",
|
||||
|
|
232
docs/index.md
232
docs/index.md
|
@ -11,233 +11,7 @@ You can learn more about using [Ingress](http://kubernetes.io/docs/user-guide/in
|
|||
See [Deployment](./deploy/) for a whirlwind tour that will get you started.
|
||||
|
||||
|
||||
# FAQ - Migration to apiVersion `networking.k8s.io/v1`
|
||||
# FAQ - Kubernetes 1.22 Migration
|
||||
|
||||
If you are using Ingress objects in your cluster (running Kubernetes older than v1.22), and you plan to upgrade to Kubernetes v1.22, this section is relevant to you.
|
||||
|
||||
- Please read this [official blog on deprecated Ingress API versions](https://kubernetes.io/blog/2021/07/26/update-with-ingress-nginx/)
|
||||
|
||||
- Please read this [official documentation on the IngressClass object](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class)
|
||||
|
||||
## What is an IngressClass and why is it important for users of Ingress-NGINX controller now ?
|
||||
|
||||
IngressClass is a Kubernetes resource. See the description below. It's important because until now, a default install of the Ingress-NGINX controller did not require any IngressClass object. From version 1.0.0 of the Ingress-NGINX Controller, an IngressClass object is required.
|
||||
|
||||
On clusters with more than one instance of the Ingress-NGINX controller, all instances of the controllers must be aware of which Ingress objects they serve. The `ingressClassName` field of an Ingress is the way to let the controller know about that.
|
||||
|
||||
```console
|
||||
kubectl explain ingressclass
|
||||
```
|
||||
```
|
||||
KIND: IngressClass
|
||||
VERSION: networking.k8s.io/v1
|
||||
|
||||
DESCRIPTION:
|
||||
IngressClass represents the class of the Ingress, referenced by the Ingress
|
||||
Spec. The `ingressclass.kubernetes.io/is-default-class` annotation can be
|
||||
used to indicate that an IngressClass should be considered default. When a
|
||||
single IngressClass resource has this annotation set to true, new Ingress
|
||||
resources without a class specified will be assigned this default class.
|
||||
|
||||
FIELDS:
|
||||
apiVersion <string>
|
||||
APIVersion defines the versioned schema of this representation of an
|
||||
object. Servers should convert recognized schemas to the latest internal
|
||||
value, and may reject unrecognized values. More info:
|
||||
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
|
||||
kind <string>
|
||||
Kind is a string value representing the REST resource this object
|
||||
represents. Servers may infer this from the endpoint the client submits
|
||||
requests to. Cannot be updated. In CamelCase. More info:
|
||||
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
|
||||
metadata <Object>
|
||||
Standard object's metadata. More info:
|
||||
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
|
||||
|
||||
spec <Object>
|
||||
Spec is the desired state of the IngressClass. More info:
|
||||
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status`
|
||||
|
||||
```
|
||||
|
||||
## What has caused this change in behavior?
|
||||
|
||||
There are 2 reasons primarily.
|
||||
|
||||
### Reason #1
|
||||
|
||||
Until K8s version 1.21, it was possible to create an Ingress resource using deprecated versions of the Ingress API, such as:
|
||||
|
||||
- `extensions/v1beta1`
|
||||
- `networking.k8s.io/v1beta1`
|
||||
|
||||
You would get a message about deprecation, but the Ingress resource would get created.
|
||||
|
||||
From K8s version 1.22 onwards, you can **only** access the Ingress API via the stable, `networking.k8s.io/v1` API. The reason is explained in the [official blog on deprecated ingress API versions](https://kubernetes.io/blog/2021/07/26/update-with-ingress-nginx/).
|
||||
|
||||
### Reason #2
|
||||
|
||||
If you are already using the Ingress-NGINX controller and then upgrade to K8s version v1.22 , there are several scenarios where your existing Ingress objects will not work how you expect. Read this FAQ to check which scenario matches your use case.
|
||||
|
||||
## What is ingressClassName field ?
|
||||
|
||||
`ingressClassName` is a field in the specs of an Ingress object.
|
||||
|
||||
```shell
|
||||
kubectl explain ingress.spec.ingressClassName
|
||||
```
|
||||
```console
|
||||
KIND: Ingress
|
||||
VERSION: networking.k8s.io/v1
|
||||
|
||||
FIELD: ingressClassName <string>
|
||||
|
||||
DESCRIPTION:
|
||||
IngressClassName is the name of the IngressClass cluster resource. The
|
||||
associated IngressClass defines which controller will implement the
|
||||
resource. This replaces the deprecated `kubernetes.io/ingress.class`
|
||||
annotation. For backwards compatibility, when that annotation is set, it
|
||||
must be given precedence over this field. The controller may emit a warning
|
||||
if the field and annotation have different values. Implementations of this
|
||||
API should ignore Ingresses without a class specified. An IngressClass
|
||||
resource may be marked as default, which can be used to set a default value
|
||||
for this field. For more information, refer to the IngressClass
|
||||
documentation.
|
||||
```
|
||||
|
||||
The `.spec.ingressClassName` behavior has precedence over the deprecated `kubernetes.io/ingress.class` annotation.
|
||||
|
||||
|
||||
## I have only one ingress controller in my cluster. What should I do?
|
||||
|
||||
If a single instance of the Ingress-NGINX controller is the sole Ingress controller running in your cluster, you should add the annotation "ingressclass.kubernetes.io/is-default-class" in your IngressClass, so any new Ingress objects will have this one as default IngressClass.
|
||||
|
||||
When using Helm, you can enable this annotation by setting `.controller.ingressClassResource.default: true` in your Helm chart installation's values file.
|
||||
|
||||
If you have any old Ingress objects remaining without an IngressClass set, you can do one or more of the following to make the Ingress-NGINX controller aware of the old objects:
|
||||
|
||||
- You can manually set the [`.spec.ingressClassName`](https://kubernetes.io/docs/reference/kubernetes-api/service-resources/ingress-v1/#IngressSpec) field in the manifest of your own Ingress resources.
|
||||
- You can re-create them after setting the `ingressclass.kubernetes.io/is-default-class` annotation to `true` on the IngressClass
|
||||
- Alternatively you can make the Ingress-NGINX controller watch Ingress objects without the ingressClassName field set by starting your Ingress-NGINX with the flag [--watch-ingress-without-class=true](#what-is-the-flag-watch-ingress-without-class) . When using Helm, you can configure your Helm chart installation's values file with `.controller.watchIngressWithoutClass: true`
|
||||
|
||||
You can configure your Helm chart installation's values file with `.controller.watchIngressWithoutClass: true`.
|
||||
|
||||
We recommend that you create the IngressClass as shown below:
|
||||
```
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: IngressClass
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: controller
|
||||
name: nginx
|
||||
annotations:
|
||||
ingressclass.kubernetes.io/is-default-class: "true"
|
||||
spec:
|
||||
controller: k8s.io/ingress-nginx
|
||||
```
|
||||
|
||||
And add the value `spec.ingressClassName=nginx` in your Ingress objects.
|
||||
|
||||
|
||||
## I have multiple ingress objects in my cluster. What should I do ?
|
||||
- If you have lot of ingress objects without ingressClass configuration, you can run the ingress-controller with the flag `--watch-ingress-without-class=true`.
|
||||
|
||||
|
||||
### What is the flag '--watch-ingress-without-class' ?
|
||||
- Its a flag that is passed,as an argument, to the `nginx-ingress-controller` executable. In the configuration, it looks like this:
|
||||
```
|
||||
...
|
||||
...
|
||||
args:
|
||||
- /nginx-ingress-controller
|
||||
- --watch-ingress-without-class=true
|
||||
- --publish-service=$(POD_NAMESPACE)/ingress-nginx-dev-v1-test-controller
|
||||
- --election-id=ingress-controller-leader
|
||||
- --controller-class=k8s.io/ingress-nginx
|
||||
- --configmap=$(POD_NAMESPACE)/ingress-nginx-dev-v1-test-controller
|
||||
- --validating-webhook=:8443
|
||||
- --validating-webhook-certificate=/usr/local/certificates/cert
|
||||
- --validating-webhook-key=/usr/local/certificates/key
|
||||
...
|
||||
...
|
||||
```
|
||||
|
||||
## I have more than one controller in my cluster and already use the annotation ?
|
||||
|
||||
No problem. This should still keep working, but we highly recommend you to test!
|
||||
|
||||
Even though `kubernetes.io/ingress.class` is deprecated, the Ingress-NGINX controller still understands that annotation.
|
||||
If you want to follow good practice, you should consider migrating to use IngressClass and `.spec.ingressClassName`.
|
||||
|
||||
## I have more than one controller running in my cluster, and I want to use the new API ?
|
||||
|
||||
In this scenario, you need to create multiple IngressClasses (see example one). But be aware that IngressClass works in a very specific way: you will need to change the `.spec.controller` value in your IngressClass and configure the controller to expect the exact same value.
|
||||
|
||||
Let's see some example, supposing that you have three IngressClasses:
|
||||
|
||||
- IngressClass `ingress-nginx-one`, with `.spec.controller` equal to `example.com/ingress-nginx1`
|
||||
- IngressClass `ingress-nginx-two`, with `.spec.controller` equal to `example.com/ingress-nginx2`
|
||||
- IngressClass `ingress-nginx-three`, with `.spec.controller` equal to `example.com/ingress-nginx1`
|
||||
|
||||
(for private use, you can also use a controller name that doesn't contain a `/`; for example: `ingress-nginx1`)
|
||||
|
||||
When deploying your ingress controllers, you will have to change the `--controller-class` field as follows:
|
||||
|
||||
- Ingress-Nginx A, configured to use controller class name `example.com/ingress-nginx1`
|
||||
- Ingress-Nginx B, configured to use controller class name `example.com/ingress-nginx2`
|
||||
|
||||
Then, when you create an Ingress object with its `ingressClassName` set to `ingress-nginx-two`, only controllers looking for the `example.com/ingress-nginx2` controller class pay attention to the new object. Given that Ingress-Nginx B is set up that way, it will serve that object, whereas Ingress-Nginx A ignores the new Ingress.
|
||||
|
||||
Bear in mind that, if you start Ingress-Nginx B with the command line argument `--watch-ingress-without-class=true`, then it will serve:
|
||||
|
||||
1. Ingresses without any `ingressClassName` set
|
||||
2. Ingresses where the deprecated annotation (`kubernetes.io/ingress.class`) matches the value set in the command line argument `--ingress-class`
|
||||
3. Ingresses that refer to any IngressClass that has the same `spec.controller` as configured in `--controller-class`
|
||||
|
||||
If you start Ingress-Nginx B with the command line argument `--watch-ingress-without-class=true` and you run Ingress-Nginx A with the command line argument `--watch-ingress-without-class=false` then this is a supported configuration. If you have two Ingress-NGINX controllers for the same cluster, both running with `--watch-ingress-without-class=true` then there is likely to be a conflict.
|
||||
|
||||
## I am seeing this error message in the logs of the Ingress-NGINX controller: "ingress class annotation is not equal to the expected by Ingress Controller". Why ?
|
||||
|
||||
- It is highly likely that you will also see the name of the ingress resource in the same error message. This error message has been observed on use the deprecated annotation (`kubernetes.io/ingress.class`) in a Ingress resource manifest. It is recommended to use the `.spec.ingressClassName` field of the Ingress resource, to specify the name of the IngressClass of the Ingress you are defining.
|
||||
|
||||
## How to easily install multiple instances of the ingress-NGINX controller in the same cluster ?
|
||||
- Create a new namespace
|
||||
```
|
||||
kubectl create namespace ingress-nginx-2
|
||||
```
|
||||
- Use Helm to install the additional instance of the ingress controller
|
||||
- Ensure you have Helm working (refer to the [Helm documentation](https://helm.sh/docs/))
|
||||
- We have to assume that you have the helm repo for the ingress-NGINX controller already added to your Helm config. But, if you have not added the helm repo then you can do this to add the repo to your helm config;
|
||||
```
|
||||
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
|
||||
```
|
||||
- Make sure you have updated the helm repo data;
|
||||
```
|
||||
helm repo update
|
||||
```
|
||||
- Now, install an additional instance of the ingress-NGINX controller like this:
|
||||
```
|
||||
helm install ingress-nginx-2 ingress-nginx/ingress-nginx \
|
||||
--namespace ingress-nginx-2 \
|
||||
--set controller.ingressClassResource.name=nginx-two \
|
||||
--set controller.ingressClass=nginx-two \
|
||||
--set controller.ingressClassResource.controllerValue="example.com/ingress-nginx-2" \
|
||||
--set controller.ingressClassResource.enabled=true \
|
||||
--set controller.ingressClassByName=true
|
||||
```
|
||||
- If you need to install yet another instance, then repeat the procedure to create a new namespace, change the values such as names & namespaces (for example from "-2" to "-3"), or anything else that meets your needs.
|
||||
- If you need to install all instances in the same namespace, then you need to specify a different **election id**, like this:
|
||||
```
|
||||
helm install ingress-nginx-2 ingress-nginx/ingress-nginx \
|
||||
--namespace kube-system \
|
||||
--set controller.electionID=nginx-two-leader \
|
||||
--set controller.ingressClassResource.name=nginx-two \
|
||||
--set controller.ingressClass=nginx-two \
|
||||
--set controller.ingressClassResource.controllerValue="example.com/ingress-nginx-2" \
|
||||
--set controller.ingressClassResource.enabled=true \
|
||||
--set controller.ingressClassByName=true
|
||||
```
|
||||
- Note, controller.ingressClassResource.name and controller.ingressClass have to be set with the value of the new class as the first is to create the IngressClass object and the other is to modify the deployment of the actuall ingress controller pod.
|
||||
If you are using Ingress objects in your cluster (running Kubernetes older than v1.22),
|
||||
and you plan to upgrade to Kubernetes v1.22, please read [the migration guide here](./user-guide/k8s-122-migration.md).
|
||||
|
|
|
@ -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) |
|
||||
|
|
245
docs/user-guide/k8s-122-migration.md
Normal file
245
docs/user-guide/k8s-122-migration.md
Normal file
|
@ -0,0 +1,245 @@
|
|||
# FAQ - Migration to Kubernetes 1.22 and apiVersion `networking.k8s.io/v1`
|
||||
|
||||
If you are using Ingress objects in your cluster (running Kubernetes older than v1.22),
|
||||
and you plan to upgrade to Kubernetes v1.22, this page is relevant to you.
|
||||
|
||||
- Please read this [official blog on deprecated Ingress API versions](https://kubernetes.io/blog/2021/07/26/update-with-ingress-nginx/)
|
||||
- Please read this [official documentation on the IngressClass object](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class)
|
||||
|
||||
## What is an IngressClass and why is it important for users of ingress-nginx controller now?
|
||||
|
||||
IngressClass is a Kubernetes resource. See the description below.
|
||||
It's important because until now, a default install of the ingress-nginx controller did not require a IngressClass object.
|
||||
From version 1.0.0 of the ingress-nginx controller, an IngressClass object is required.
|
||||
|
||||
On clusters with more than one instance of the ingress-nginx controller, all instances of the controllers must be aware of which Ingress objects they serve.
|
||||
The `ingressClassName` field of an Ingress is the way to let the controller know about that.
|
||||
|
||||
```console
|
||||
kubectl explain ingressclass
|
||||
```
|
||||
|
||||
```
|
||||
KIND: IngressClass
|
||||
VERSION: networking.k8s.io/v1
|
||||
DESCRIPTION:
|
||||
IngressClass represents the class of the Ingress, referenced by the Ingress
|
||||
Spec. The `ingressclass.kubernetes.io/is-default-class` annotation can be
|
||||
used to indicate that an IngressClass should be considered default. When a
|
||||
single IngressClass resource has this annotation set to true, new Ingress
|
||||
resources without a class specified will be assigned this default class.
|
||||
FIELDS:
|
||||
apiVersion <string>
|
||||
APIVersion defines the versioned schema of this representation of an
|
||||
object. Servers should convert recognized schemas to the latest internal
|
||||
value, and may reject unrecognized values. More info:
|
||||
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
kind <string>
|
||||
Kind is a string value representing the REST resource this object
|
||||
represents. Servers may infer this from the endpoint the client submits
|
||||
requests to. Cannot be updated. In CamelCase. More info:
|
||||
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
metadata <Object>
|
||||
Standard object's metadata. More info:
|
||||
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
|
||||
spec <Object>
|
||||
Spec is the desired state of the IngressClass. More info:
|
||||
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status`
|
||||
```
|
||||
|
||||
## What has caused this change in behavior?
|
||||
|
||||
There are 2 primary reasons.
|
||||
|
||||
### Reason 1
|
||||
|
||||
Until K8s version 1.21, it was possible to create an Ingress resource using deprecated versions of the Ingress API, such as:
|
||||
|
||||
- `extensions/v1beta1`
|
||||
- `networking.k8s.io/v1beta1`
|
||||
You would get a message about deprecation, but the Ingress resource would get created.
|
||||
|
||||
From K8s version 1.22 onwards, you can **only** access the Ingress API via the stable, `networking.k8s.io/v1` API.
|
||||
The reason is explained in the [official blog on deprecated ingress API versions](https://kubernetes.io/blog/2021/07/26/update-with-ingress-nginx/).
|
||||
|
||||
### Reason #2
|
||||
|
||||
If you are already using the ingress-nginx controller and then upgrade to Kubernetes 1.22,
|
||||
there are several scenarios where your existing Ingress objects will not work how you expect.
|
||||
|
||||
Read this FAQ to check which scenario matches your use case.
|
||||
|
||||
## What is the `ingressClassName` field?
|
||||
|
||||
`ingressClassName` is a field in the spec of an Ingress object.
|
||||
|
||||
```shell
|
||||
kubectl explain ingress.spec.ingressClassName
|
||||
```
|
||||
|
||||
```console
|
||||
KIND: Ingress
|
||||
VERSION: networking.k8s.io/v1
|
||||
FIELD: ingressClassName <string>
|
||||
DESCRIPTION:
|
||||
IngressClassName is the name of the IngressClass cluster resource. The
|
||||
associated IngressClass defines which controller will implement the
|
||||
resource. This replaces the deprecated `kubernetes.io/ingress.class`
|
||||
annotation. For backwards compatibility, when that annotation is set, it
|
||||
must be given precedence over this field. The controller may emit a warning
|
||||
if the field and annotation have different values. Implementations of this
|
||||
API should ignore Ingresses without a class specified. An IngressClass
|
||||
resource may be marked as default, which can be used to set a default value
|
||||
for this field. For more information, refer to the IngressClass
|
||||
documentation.
|
||||
```
|
||||
|
||||
The `.spec.ingressClassName` behavior has precedence over the deprecated `kubernetes.io/ingress.class` annotation.
|
||||
|
||||
## I have only one ingress controller in my cluster. What should I do?
|
||||
|
||||
If a single instance of the ingress-nginx controller is the sole Ingress controller running in your cluster,
|
||||
you should add the annotation "ingressclass.kubernetes.io/is-default-class" in your IngressClass,
|
||||
so any new Ingress objects will have this one as default IngressClass.
|
||||
|
||||
When using Helm, you can enable this annotation by setting `.controller.ingressClassResource.default: true` in your Helm chart installation's values file.
|
||||
|
||||
If you have any old Ingress objects remaining without an IngressClass set, you can do one or more of the following to make the ingress-nginx controller aware of the old objects:
|
||||
|
||||
- You can manually set the [`.spec.ingressClassName`](https://kubernetes.io/docs/reference/kubernetes-api/service-resources/ingress-v1/#IngressSpec) field in the manifest of your own Ingress resources.
|
||||
- You can re-create them after setting the `ingressclass.kubernetes.io/is-default-class` annotation to `true` on the IngressClass
|
||||
- Alternatively you can make the ingress-nginx controller watch Ingress objects without the ingressClassName field set by starting your ingress-nginx with the flag [--watch-ingress-without-class=true](#what-is-the-flag-watch-ingress-without-class).
|
||||
When using Helm, you can configure your Helm chart installation's values file with `.controller.watchIngressWithoutClass: true`.
|
||||
|
||||
We recommend that you create the IngressClass as shown below:
|
||||
|
||||
```
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: IngressClass
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/component: controller
|
||||
name: nginx
|
||||
annotations:
|
||||
ingressclass.kubernetes.io/is-default-class: "true"
|
||||
spec:
|
||||
controller: k8s.io/ingress-nginx
|
||||
```
|
||||
|
||||
and add the value `spec.ingressClassName=nginx` in your Ingress objects.
|
||||
|
||||
## I have many ingress objects in my cluster. What should I do?
|
||||
|
||||
If you have lot of ingress objects without ingressClass configuration,
|
||||
you can run the ingress controller with the flag `--watch-ingress-without-class=true`.
|
||||
|
||||
### What is the flag `--watch-ingress-without-class`?
|
||||
|
||||
It's a flag that is passed, as an argument, to the `nginx-ingress-controller` executable.
|
||||
In the configuration, it looks like this:
|
||||
|
||||
```yaml
|
||||
# ...
|
||||
args:
|
||||
- /nginx-ingress-controller
|
||||
- --watch-ingress-without-class=true
|
||||
- --controller-class=k8s.io/ingress-nginx
|
||||
# ...
|
||||
# ...
|
||||
```
|
||||
|
||||
## I have more than one controller in my cluster, and I'm already using the annotation
|
||||
|
||||
No problem. This should still keep working, but we highly recommend you to test!
|
||||
Even though `kubernetes.io/ingress.class` is deprecated, the ingress-nginx controller still understands that annotation.
|
||||
If you want to follow good practice, you should consider migrating to use IngressClass and `.spec.ingressClassName`.
|
||||
|
||||
## I have more than one controller running in my cluster, and I want to use the new API
|
||||
|
||||
In this scenario, you need to create multiple IngressClasses (see the example above).
|
||||
|
||||
Be aware that IngressClass works in a very specific way: you will need to change the `.spec.controller` value in your IngressClass and configure the controller to expect the exact same value.
|
||||
|
||||
Let's see an example, supposing that you have three IngressClasses:
|
||||
|
||||
- IngressClass `ingress-nginx-one`, with `.spec.controller` equal to `example.com/ingress-nginx1`
|
||||
- IngressClass `ingress-nginx-two`, with `.spec.controller` equal to `example.com/ingress-nginx2`
|
||||
- IngressClass `ingress-nginx-three`, with `.spec.controller` equal to `example.com/ingress-nginx1`
|
||||
|
||||
For private use, you can also use a controller name that doesn't contain a `/`, e.g. `ingress-nginx1`.
|
||||
|
||||
When deploying your ingress controllers, you will have to change the `--controller-class` field as follows:
|
||||
|
||||
- Ingress-Nginx A, configured to use controller class name `example.com/ingress-nginx1`
|
||||
- Ingress-Nginx B, configured to use controller class name `example.com/ingress-nginx2`
|
||||
|
||||
When you create an Ingress object with its `ingressClassName` set to `ingress-nginx-two`,
|
||||
only controllers looking for the `example.com/ingress-nginx2` controller class pay attention to the new object.
|
||||
|
||||
Given that Ingress-Nginx B is set up that way, it will serve that object, whereas Ingress-Nginx A ignores the new Ingress.
|
||||
|
||||
Bear in mind that if you start Ingress-Nginx B with the command line argument `--watch-ingress-without-class=true`, it will serve:
|
||||
|
||||
1. Ingresses without any `ingressClassName` set
|
||||
2. Ingresses where the deprecated annotation (`kubernetes.io/ingress.class`) matches the value set in the command line argument `--ingress-class`
|
||||
3. Ingresses that refer to any IngressClass that has the same `spec.controller` as configured in `--controller-class`
|
||||
4. If you start Ingress-Nginx B with the command line argument `--watch-ingress-without-class=true` and you run Ingress-Nginx A with the command line argument `--watch-ingress-without-class=false` then this is a supported configuration.
|
||||
If you have two ingress-nginx controllers for the same cluster, both running with `--watch-ingress-without-class=true` then there is likely to be a conflict.
|
||||
|
||||
## Why am I am seeing "ingress class annotation is not equal to the expected by Ingress Controller" in my controller logs?
|
||||
|
||||
It is highly likely that you will also see the name of the ingress resource in the same error message.
|
||||
This error message has been observed on use the deprecated annotation (`kubernetes.io/ingress.class`) in a Ingress resource manifest.
|
||||
It is recommended to use the `.spec.ingressClassName` field of the Ingress resource, to specify the name of the IngressClass of the Ingress you are defining.
|
||||
|
||||
## How can I easily install multiple instances of the ingress-nginx controller in the same cluster?
|
||||
|
||||
You can install them in different namespaces.
|
||||
|
||||
- Create a new namespace
|
||||
```
|
||||
kubectl create namespace ingress-nginx-2
|
||||
```
|
||||
- Use Helm to install the additional instance of the ingress controller
|
||||
- Ensure you have Helm working (refer to the [Helm documentation](https://helm.sh/docs/))
|
||||
- We have to assume that you have the helm repo for the ingress-nginx controller already added to your Helm config.
|
||||
But, if you have not added the helm repo then you can do this to add the repo to your helm config;
|
||||
```
|
||||
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
|
||||
```
|
||||
- Make sure you have updated the helm repo data;
|
||||
```
|
||||
helm repo update
|
||||
```
|
||||
- Now, install an additional instance of the ingress-nginx controller like this:
|
||||
```
|
||||
helm install ingress-nginx-2 ingress-nginx/ingress-nginx \
|
||||
--namespace ingress-nginx-2 \
|
||||
--set controller.ingressClassResource.name=nginx-two \
|
||||
--set controller.ingressClass=nginx-two \
|
||||
--set controller.ingressClassResource.controllerValue="example.com/ingress-nginx-2" \
|
||||
--set controller.ingressClassResource.enabled=true \
|
||||
--set controller.ingressClassByName=true
|
||||
```
|
||||
|
||||
If you need to install yet another instance, then repeat the procedure to create a new namespace,
|
||||
change the values such as names & namespaces (for example from "-2" to "-3"), or anything else that meets your needs.
|
||||
|
||||
Note that `controller.ingressClassResource.name` and `controller.ingressClass` have to be set correctly.
|
||||
The first is to create the IngressClass object and the other is to modify the deployment of the actual ingress controller pod.
|
||||
|
||||
### I can't use multiple namespaces, what should I do?
|
||||
|
||||
If you need to install all instances in the same namespace, then you need to specify a different **election id**, like this:
|
||||
|
||||
```
|
||||
helm install ingress-nginx-2 ingress-nginx/ingress-nginx \
|
||||
--namespace kube-system \
|
||||
--set controller.electionID=nginx-two-leader \
|
||||
--set controller.ingressClassResource.name=nginx-two \
|
||||
--set controller.ingressClass=nginx-two \
|
||||
--set controller.ingressClassResource.controllerValue="example.com/ingress-nginx-2" \
|
||||
--set controller.ingressClassResource.enabled=true \
|
||||
--set controller.ingressClassByName=true
|
||||
```
|
|
@ -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
|
||||
|
|
|
@ -25,195 +25,199 @@ data:
|
|||
|
||||
The following table shows a configuration option's name, type, and the default value:
|
||||
|
||||
|name|type|default|
|
||||
|:---|:---|:------|
|
||||
|[add-headers](#add-headers)|string|""|
|
||||
|[allow-backend-server-header](#allow-backend-server-header)|bool|"false"|
|
||||
|[allow-snippet-annotations](#allow-snippet-annotations)|bool|true|
|
||||
|[annotation-value-word-blocklist](#annotation-value-word-blocklist)|string array|""|
|
||||
|[hide-headers](#hide-headers)|string array|empty|
|
||||
|[access-log-params](#access-log-params)|string|""|
|
||||
|[access-log-path](#access-log-path)|string|"/var/log/nginx/access.log"|
|
||||
|[http-access-log-path](#http-access-log-path)|string|""|
|
||||
|[stream-access-log-path](#stream-access-log-path)|string|""|
|
||||
|[enable-access-log-for-default-backend](#enable-access-log-for-default-backend)|bool|"false"|
|
||||
|[error-log-path](#error-log-path)|string|"/var/log/nginx/error.log"|
|
||||
|[enable-modsecurity](#enable-modsecurity)|bool|"false"|
|
||||
|[modsecurity-snippet](#modsecurity-snippet)|string|""|
|
||||
|[enable-owasp-modsecurity-crs](#enable-owasp-modsecurity-crs)|bool|"false"|
|
||||
|[client-header-buffer-size](#client-header-buffer-size)|string|"1k"|
|
||||
|[client-header-timeout](#client-header-timeout)|int|60|
|
||||
|[client-body-buffer-size](#client-body-buffer-size)|string|"8k"|
|
||||
|[client-body-timeout](#client-body-timeout)|int|60|
|
||||
|[disable-access-log](#disable-access-log)|bool|false|
|
||||
|[disable-ipv6](#disable-ipv6)|bool|false|
|
||||
|[disable-ipv6-dns](#disable-ipv6-dns)|bool|false|
|
||||
|[enable-underscores-in-headers](#enable-underscores-in-headers)|bool|false|
|
||||
|[enable-ocsp](#enable-ocsp)|bool|false|
|
||||
|[ignore-invalid-headers](#ignore-invalid-headers)|bool|true|
|
||||
|[retry-non-idempotent](#retry-non-idempotent)|bool|"false"|
|
||||
|[error-log-level](#error-log-level)|string|"notice"|
|
||||
|[http2-max-field-size](#http2-max-field-size)|string|"4k"|
|
||||
|[http2-max-header-size](#http2-max-header-size)|string|"16k"|
|
||||
|[http2-max-requests](#http2-max-requests)|int|1000|
|
||||
|[http2-max-concurrent-streams](#http2-max-concurrent-streams)|int|128|
|
||||
|[hsts](#hsts)|bool|"true"|
|
||||
|[hsts-include-subdomains](#hsts-include-subdomains)|bool|"true"|
|
||||
|[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|
|
||||
|[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"|
|
||||
|[log-format-upstream](#log-format-upstream)|string|`$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_upstream_name] [$proxy_alternative_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status $req_id`|
|
||||
|[log-format-stream](#log-format-stream)|string|`[$remote_addr] [$time_local] $protocol $status $bytes_sent $bytes_received $session_time`|
|
||||
|[enable-multi-accept](#enable-multi-accept)|bool|"true"|
|
||||
|[max-worker-connections](#max-worker-connections)|int|16384|
|
||||
|[max-worker-open-files](#max-worker-open-files)|int|0|
|
||||
|[map-hash-bucket-size](#max-hash-bucket-size)|int|64|
|
||||
|[nginx-status-ipv4-whitelist](#nginx-status-ipv4-whitelist)|[]string|"127.0.0.1"|
|
||||
|[nginx-status-ipv6-whitelist](#nginx-status-ipv6-whitelist)|[]string|"::1"|
|
||||
|[proxy-real-ip-cidr](#proxy-real-ip-cidr)|[]string|"0.0.0.0/0"|
|
||||
|[proxy-set-headers](#proxy-set-headers)|string|""|
|
||||
|[server-name-hash-max-size](#server-name-hash-max-size)|int|1024|
|
||||
|[server-name-hash-bucket-size](#server-name-hash-bucket-size)|int|`<size of the processor’s cache line>`
|
||||
|[proxy-headers-hash-max-size](#proxy-headers-hash-max-size)|int|512|
|
||||
|[proxy-headers-hash-bucket-size](#proxy-headers-hash-bucket-size)|int|64|
|
||||
|[plugins](#plugins)|[]string| |
|
||||
|[reuse-port](#reuse-port)|bool|"true"|
|
||||
|[server-tokens](#server-tokens)|bool|"false"|
|
||||
|[ssl-ciphers](#ssl-ciphers)|string|"ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"|
|
||||
|[ssl-ecdh-curve](#ssl-ecdh-curve)|string|"auto"|
|
||||
|[ssl-dh-param](#ssl-dh-param)|string|""|
|
||||
|[ssl-protocols](#ssl-protocols)|string|"TLSv1.2 TLSv1.3"|
|
||||
|[ssl-session-cache](#ssl-session-cache)|bool|"true"|
|
||||
|[ssl-session-cache-size](#ssl-session-cache-size)|string|"10m"|
|
||||
|[ssl-session-tickets](#ssl-session-tickets)|bool|"false"|
|
||||
|[ssl-session-ticket-key](#ssl-session-ticket-key)|string|`<Randomly Generated>`
|
||||
|[ssl-session-timeout](#ssl-session-timeout)|string|"10m"|
|
||||
|[ssl-buffer-size](#ssl-buffer-size)|string|"4k"|
|
||||
|[use-proxy-protocol](#use-proxy-protocol)|bool|"false"|
|
||||
|[proxy-protocol-header-timeout](#proxy-protocol-header-timeout)|string|"5s"|
|
||||
|[use-gzip](#use-gzip)|bool|"false"|
|
||||
|[use-geoip](#use-geoip)|bool|"true"|
|
||||
|[use-geoip2](#use-geoip2)|bool|"false"|
|
||||
|[enable-brotli](#enable-brotli)|bool|"false"|
|
||||
|[brotli-level](#brotli-level)|int|4|
|
||||
|[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-level](#gzip-level)|int|1|
|
||||
|[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|""|
|
||||
|[worker-shutdown-timeout](#worker-shutdown-timeout)|string|"240s"|
|
||||
|[load-balance](#load-balance)|string|"round_robin"|
|
||||
|[variables-hash-bucket-size](#variables-hash-bucket-size)|int|128|
|
||||
|[variables-hash-max-size](#variables-hash-max-size)|int|2048|
|
||||
|[upstream-keepalive-connections](#upstream-keepalive-connections)|int|320|
|
||||
|[upstream-keepalive-time](#upstream-keepalive-time)|string|"1h"|
|
||||
|[upstream-keepalive-timeout](#upstream-keepalive-timeout)|int|60|
|
||||
|[upstream-keepalive-requests](#upstream-keepalive-requests)|int|10000|
|
||||
|[limit-conn-zone-variable](#limit-conn-zone-variable)|string|"$binary_remote_addr"|
|
||||
|[proxy-stream-timeout](#proxy-stream-timeout)|string|"600s"|
|
||||
|[proxy-stream-next-upstream](#proxy-stream-next-upstream)|bool|"true"|
|
||||
|[proxy-stream-next-upstream-timeout](#proxy-stream-next-upstream-timeout)|string|"600s"|
|
||||
|[proxy-stream-next-upstream-tries](#proxy-stream-next-upstream-tries)|int|3|
|
||||
|[proxy-stream-responses](#proxy-stream-responses)|int|1|
|
||||
|[bind-address](#bind-address)|[]string|""|
|
||||
|[use-forwarded-headers](#use-forwarded-headers)|bool|"false"|
|
||||
|[enable-real-ip](#enable-real-ip)|bool|"false"|
|
||||
|[forwarded-for-header](#forwarded-for-header)|string|"X-Forwarded-For"|
|
||||
|[compute-full-forwarded-for](#compute-full-forwarded-for)|bool|"false"|
|
||||
|[proxy-add-original-uri-header](#proxy-add-original-uri-header)|bool|"false"|
|
||||
|[generate-request-id](#generate-request-id)|bool|"true"|
|
||||
|[enable-opentracing](#enable-opentracing)|bool|"false"|
|
||||
|[opentracing-operation-name](#opentracing-operation-name)|string|""|
|
||||
|[opentracing-location-operation-name](#opentracing-location-operation-name)|string|""|
|
||||
|[zipkin-collector-host](#zipkin-collector-host)|string|""|
|
||||
|[zipkin-collector-port](#zipkin-collector-port)|int|9411|
|
||||
|[zipkin-service-name](#zipkin-service-name)|string|"nginx"|
|
||||
|[zipkin-sample-rate](#zipkin-sample-rate)|float|1.0|
|
||||
|[jaeger-collector-host](#jaeger-collector-host)|string|""|
|
||||
|[jaeger-collector-port](#jaeger-collector-port)|int|6831|
|
||||
|[jaeger-endpoint](#jaeger-endpoint)|string|""|
|
||||
|[jaeger-service-name](#jaeger-service-name)|string|"nginx"|
|
||||
|[jaeger-propagation-format](#jaeger-propagation-format)|string|"jaeger"|
|
||||
|[jaeger-sampler-type](#jaeger-sampler-type)|string|"const"|
|
||||
|[jaeger-sampler-param](#jaeger-sampler-param)|string|"1"|
|
||||
|[jaeger-sampler-host](#jaeger-sampler-host)|string|"http://127.0.0.1"|
|
||||
|[jaeger-sampler-port](#jaeger-sampler-port)|int|5778|
|
||||
|[jaeger-trace-context-header-name](#jaeger-trace-context-header-name)|string|uber-trace-id|
|
||||
|[jaeger-debug-header](#jaeger-debug-header)|string|uber-debug-id|
|
||||
|[jaeger-baggage-header](#jaeger-baggage-header)|string|jaeger-baggage|
|
||||
|[jaeger-trace-baggage-header-prefix](#jaeger-trace-baggage-header-prefix)|string|uberctx-|
|
||||
|[datadog-collector-host](#datadog-collector-host)|string|""|
|
||||
|[datadog-collector-port](#datadog-collector-port)|int|8126|
|
||||
|[datadog-service-name](#datadog-service-name)|string|"nginx"|
|
||||
|[datadog-environment](#datadog-environment)|string|"prod"|
|
||||
|[datadog-operation-name-override](#datadog-operation-name-override)|string|"nginx.handle"|
|
||||
|[datadog-priority-sampling](#datadog-priority-sampling)|bool|"true"|
|
||||
|[datadog-sample-rate](#datadog-sample-rate)|float|1.0|
|
||||
|[main-snippet](#main-snippet)|string|""|
|
||||
|[http-snippet](#http-snippet)|string|""|
|
||||
|[server-snippet](#server-snippet)|string|""|
|
||||
|[stream-snippet](#stream-snippet)|string|""|
|
||||
|[location-snippet](#location-snippet)|string|""|
|
||||
|[custom-http-errors](#custom-http-errors)|[]int|[]int{}|
|
||||
|[proxy-body-size](#proxy-body-size)|string|"1m"|
|
||||
|[proxy-connect-timeout](#proxy-connect-timeout)|int|5|
|
||||
|[proxy-read-timeout](#proxy-read-timeout)|int|60|
|
||||
|[proxy-send-timeout](#proxy-send-timeout)|int|60|
|
||||
|[proxy-buffers-number](#proxy-buffers-number)|int|4|
|
||||
|[proxy-buffer-size](#proxy-buffer-size)|string|"4k"|
|
||||
|[proxy-cookie-path](#proxy-cookie-path)|string|"off"|
|
||||
|[proxy-cookie-domain](#proxy-cookie-domain)|string|"off"|
|
||||
|[proxy-next-upstream](#proxy-next-upstream)|string|"error timeout"|
|
||||
|[proxy-next-upstream-timeout](#proxy-next-upstream-timeout)|int|0|
|
||||
|[proxy-next-upstream-tries](#proxy-next-upstream-tries)|int|3|
|
||||
|[proxy-redirect-from](#proxy-redirect-from)|string|"off"|
|
||||
|[proxy-request-buffering](#proxy-request-buffering)|string|"on"|
|
||||
|[ssl-redirect](#ssl-redirect)|bool|"true"|
|
||||
|[force-ssl-redirect](#force-ssl-redirect)|bool|"false"|
|
||||
|[denylist-source-range](#denylist-source-range)|[]string|[]string{}|
|
||||
|[whitelist-source-range](#whitelist-source-range)|[]string|[]string{}|
|
||||
|[skip-access-log-urls](#skip-access-log-urls)|[]string|[]string{}|
|
||||
|[limit-rate](#limit-rate)|int|0|
|
||||
|[limit-rate-after](#limit-rate-after)|int|0|
|
||||
|[lua-shared-dicts](#lua-shared-dicts)|string|""|
|
||||
|[http-redirect-code](#http-redirect-code)|int|308|
|
||||
|[proxy-buffering](#proxy-buffering)|string|"off"|
|
||||
|[limit-req-status-code](#limit-req-status-code)|int|503|
|
||||
|[limit-conn-status-code](#limit-conn-status-code)|int|503|
|
||||
|[enable-syslog](#enable-syslog)|bool|false|
|
||||
|[syslog-host](#syslog-host)|string|""|
|
||||
|[syslog-port](#syslog-port)|int|514|
|
||||
|[no-tls-redirect-locations](#no-tls-redirect-locations)|string|"/.well-known/acme-challenge"|
|
||||
|[global-auth-url](#global-auth-url)|string|""|
|
||||
|[global-auth-method](#global-auth-method)|string|""|
|
||||
|[global-auth-signin](#global-auth-signin)|string|""|
|
||||
|[global-auth-signin-redirect-param](#global-auth-signin-redirect-param)|string|"rd"|
|
||||
|[global-auth-response-headers](#global-auth-response-headers)|string|""|
|
||||
|[global-auth-request-redirect](#global-auth-request-redirect)|string|""|
|
||||
|[global-auth-snippet](#global-auth-snippet)|string|""|
|
||||
|[global-auth-cache-key](#global-auth-cache-key)|string|""|
|
||||
|[global-auth-cache-duration](#global-auth-cache-duration)|string|"200 202 401 5m"|
|
||||
|[no-auth-locations](#no-auth-locations)|string|"/.well-known/acme-challenge"|
|
||||
|[block-cidrs](#block-cidrs)|[]string|""|
|
||||
|[block-user-agents](#block-user-agents)|[]string|""|
|
||||
|[block-referers](#block-referers)|[]string|""|
|
||||
|[proxy-ssl-location-only](#proxy-ssl-location-only)|bool|"false"|
|
||||
|[default-type](#default-type)|string|"text/html"|
|
||||
|[global-rate-limit-memcached-host](#global-rate-limit)|string|""|
|
||||
|[global-rate-limit-memcached-port](#global-rate-limit)|int|11211|
|
||||
|[global-rate-limit-memcached-connect-timeout](#global-rate-limit)|int|50|
|
||||
|[global-rate-limit-memcached-max-idle-timeout](#global-rate-limit)|int|10000|
|
||||
|[global-rate-limit-memcached-pool-size](#global-rate-limit)|int|50|
|
||||
|[global-rate-limit-status-code](#global-rate-limit)|int|429|
|
||||
|[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"|
|
||||
| name | type | default |
|
||||
|:--------------------------------------------------------------------------------|:-------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [add-headers](#add-headers) | string | "" |
|
||||
| [allow-backend-server-header](#allow-backend-server-header) | bool | "false" |
|
||||
| [allow-snippet-annotations](#allow-snippet-annotations) | bool | true |
|
||||
| [annotation-value-word-blocklist](#annotation-value-word-blocklist) | string array | "" |
|
||||
| [hide-headers](#hide-headers) | string array | empty |
|
||||
| [access-log-params](#access-log-params) | string | "" |
|
||||
| [access-log-path](#access-log-path) | string | "/var/log/nginx/access.log" |
|
||||
| [http-access-log-path](#http-access-log-path) | string | "" |
|
||||
| [stream-access-log-path](#stream-access-log-path) | string | "" |
|
||||
| [enable-access-log-for-default-backend](#enable-access-log-for-default-backend) | bool | "false" |
|
||||
| [error-log-path](#error-log-path) | string | "/var/log/nginx/error.log" |
|
||||
| [enable-modsecurity](#enable-modsecurity) | bool | "false" |
|
||||
| [modsecurity-snippet](#modsecurity-snippet) | string | "" |
|
||||
| [enable-owasp-modsecurity-crs](#enable-owasp-modsecurity-crs) | bool | "false" |
|
||||
| [client-header-buffer-size](#client-header-buffer-size) | string | "1k" |
|
||||
| [client-header-timeout](#client-header-timeout) | int | 60 |
|
||||
| [client-body-buffer-size](#client-body-buffer-size) | string | "8k" |
|
||||
| [client-body-timeout](#client-body-timeout) | int | 60 |
|
||||
| [disable-access-log](#disable-access-log) | bool | false |
|
||||
| [disable-ipv6](#disable-ipv6) | bool | false |
|
||||
| [disable-ipv6-dns](#disable-ipv6-dns) | bool | false |
|
||||
| [enable-underscores-in-headers](#enable-underscores-in-headers) | bool | false |
|
||||
| [enable-ocsp](#enable-ocsp) | bool | false |
|
||||
| [ignore-invalid-headers](#ignore-invalid-headers) | bool | true |
|
||||
| [retry-non-idempotent](#retry-non-idempotent) | bool | "false" |
|
||||
| [error-log-level](#error-log-level) | string | "notice" |
|
||||
| [http2-max-field-size](#http2-max-field-size) | string | "4k" |
|
||||
| [http2-max-header-size](#http2-max-header-size) | string | "16k" |
|
||||
| [http2-max-requests](#http2-max-requests) | int | 1000 |
|
||||
| [http2-max-concurrent-streams](#http2-max-concurrent-streams) | int | 128 |
|
||||
| [hsts](#hsts) | bool | "true" |
|
||||
| [hsts-include-subdomains](#hsts-include-subdomains) | bool | "true" |
|
||||
| [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 | 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" |
|
||||
| [log-format-upstream](#log-format-upstream) | string | `$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_upstream_name] [$proxy_alternative_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status $req_id` |
|
||||
| [log-format-stream](#log-format-stream) | string | `[$remote_addr] [$time_local] $protocol $status $bytes_sent $bytes_received $session_time` |
|
||||
| [enable-multi-accept](#enable-multi-accept) | bool | "true" |
|
||||
| [max-worker-connections](#max-worker-connections) | int | 16384 |
|
||||
| [max-worker-open-files](#max-worker-open-files) | int | 0 |
|
||||
| [map-hash-bucket-size](#max-hash-bucket-size) | int | 64 |
|
||||
| [nginx-status-ipv4-whitelist](#nginx-status-ipv4-whitelist) | []string | "127.0.0.1" |
|
||||
| [nginx-status-ipv6-whitelist](#nginx-status-ipv6-whitelist) | []string | "::1" |
|
||||
| [proxy-real-ip-cidr](#proxy-real-ip-cidr) | []string | "0.0.0.0/0" |
|
||||
| [proxy-set-headers](#proxy-set-headers) | string | "" |
|
||||
| [server-name-hash-max-size](#server-name-hash-max-size) | int | 1024 |
|
||||
| [server-name-hash-bucket-size](#server-name-hash-bucket-size) | int | `<size of the processor’s cache line>` |
|
||||
| [proxy-headers-hash-max-size](#proxy-headers-hash-max-size) | int | 512 |
|
||||
| [proxy-headers-hash-bucket-size](#proxy-headers-hash-bucket-size) | int | 64 |
|
||||
| [plugins](#plugins) | []string | |
|
||||
| [reuse-port](#reuse-port) | bool | "true" |
|
||||
| [server-tokens](#server-tokens) | bool | "false" |
|
||||
| [ssl-ciphers](#ssl-ciphers) | string | "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" |
|
||||
| [ssl-ecdh-curve](#ssl-ecdh-curve) | string | "auto" |
|
||||
| [ssl-dh-param](#ssl-dh-param) | string | "" |
|
||||
| [ssl-protocols](#ssl-protocols) | string | "TLSv1.2 TLSv1.3" |
|
||||
| [ssl-session-cache](#ssl-session-cache) | bool | "true" |
|
||||
| [ssl-session-cache-size](#ssl-session-cache-size) | string | "10m" |
|
||||
| [ssl-session-tickets](#ssl-session-tickets) | bool | "false" |
|
||||
| [ssl-session-ticket-key](#ssl-session-ticket-key) | string | `<Randomly Generated>` |
|
||||
| [ssl-session-timeout](#ssl-session-timeout) | string | "10m" |
|
||||
| [ssl-buffer-size](#ssl-buffer-size) | string | "4k" |
|
||||
| [use-proxy-protocol](#use-proxy-protocol) | bool | "false" |
|
||||
| [proxy-protocol-header-timeout](#proxy-protocol-header-timeout) | string | "5s" |
|
||||
| [use-gzip](#use-gzip) | bool | "false" |
|
||||
| [use-geoip](#use-geoip) | bool | "true" |
|
||||
| [use-geoip2](#use-geoip2) | bool | "false" |
|
||||
| [enable-brotli](#enable-brotli) | bool | "false" |
|
||||
| [brotli-level](#brotli-level) | int | 4 |
|
||||
| [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 | "" |
|
||||
| [worker-shutdown-timeout](#worker-shutdown-timeout) | string | "240s" |
|
||||
| [load-balance](#load-balance) | string | "round_robin" |
|
||||
| [variables-hash-bucket-size](#variables-hash-bucket-size) | int | 128 |
|
||||
| [variables-hash-max-size](#variables-hash-max-size) | int | 2048 |
|
||||
| [upstream-keepalive-connections](#upstream-keepalive-connections) | int | 320 |
|
||||
| [upstream-keepalive-time](#upstream-keepalive-time) | string | "1h" |
|
||||
| [upstream-keepalive-timeout](#upstream-keepalive-timeout) | int | 60 |
|
||||
| [upstream-keepalive-requests](#upstream-keepalive-requests) | int | 10000 |
|
||||
| [limit-conn-zone-variable](#limit-conn-zone-variable) | string | "$binary_remote_addr" |
|
||||
| [proxy-stream-timeout](#proxy-stream-timeout) | string | "600s" |
|
||||
| [proxy-stream-next-upstream](#proxy-stream-next-upstream) | bool | "true" |
|
||||
| [proxy-stream-next-upstream-timeout](#proxy-stream-next-upstream-timeout) | string | "600s" |
|
||||
| [proxy-stream-next-upstream-tries](#proxy-stream-next-upstream-tries) | int | 3 |
|
||||
| [proxy-stream-responses](#proxy-stream-responses) | int | 1 |
|
||||
| [bind-address](#bind-address) | []string | "" |
|
||||
| [use-forwarded-headers](#use-forwarded-headers) | bool | "false" |
|
||||
| [enable-real-ip](#enable-real-ip) | bool | "false" |
|
||||
| [forwarded-for-header](#forwarded-for-header) | string | "X-Forwarded-For" |
|
||||
| [compute-full-forwarded-for](#compute-full-forwarded-for) | bool | "false" |
|
||||
| [proxy-add-original-uri-header](#proxy-add-original-uri-header) | bool | "false" |
|
||||
| [generate-request-id](#generate-request-id) | bool | "true" |
|
||||
| [enable-opentracing](#enable-opentracing) | bool | "false" |
|
||||
| [opentracing-operation-name](#opentracing-operation-name) | string | "" |
|
||||
| [opentracing-location-operation-name](#opentracing-location-operation-name) | string | "" |
|
||||
| [zipkin-collector-host](#zipkin-collector-host) | string | "" |
|
||||
| [zipkin-collector-port](#zipkin-collector-port) | int | 9411 |
|
||||
| [zipkin-service-name](#zipkin-service-name) | string | "nginx" |
|
||||
| [zipkin-sample-rate](#zipkin-sample-rate) | float | 1.0 |
|
||||
| [jaeger-collector-host](#jaeger-collector-host) | string | "" |
|
||||
| [jaeger-collector-port](#jaeger-collector-port) | int | 6831 |
|
||||
| [jaeger-endpoint](#jaeger-endpoint) | string | "" |
|
||||
| [jaeger-service-name](#jaeger-service-name) | string | "nginx" |
|
||||
| [jaeger-propagation-format](#jaeger-propagation-format) | string | "jaeger" |
|
||||
| [jaeger-sampler-type](#jaeger-sampler-type) | string | "const" |
|
||||
| [jaeger-sampler-param](#jaeger-sampler-param) | string | "1" |
|
||||
| [jaeger-sampler-host](#jaeger-sampler-host) | string | "http://127.0.0.1" |
|
||||
| [jaeger-sampler-port](#jaeger-sampler-port) | int | 5778 |
|
||||
| [jaeger-trace-context-header-name](#jaeger-trace-context-header-name) | string | uber-trace-id |
|
||||
| [jaeger-debug-header](#jaeger-debug-header) | string | uber-debug-id |
|
||||
| [jaeger-baggage-header](#jaeger-baggage-header) | string | jaeger-baggage |
|
||||
| [jaeger-trace-baggage-header-prefix](#jaeger-trace-baggage-header-prefix) | string | uberctx- |
|
||||
| [datadog-collector-host](#datadog-collector-host) | string | "" |
|
||||
| [datadog-collector-port](#datadog-collector-port) | int | 8126 |
|
||||
| [datadog-service-name](#datadog-service-name) | string | "nginx" |
|
||||
| [datadog-environment](#datadog-environment) | string | "prod" |
|
||||
| [datadog-operation-name-override](#datadog-operation-name-override) | string | "nginx.handle" |
|
||||
| [datadog-priority-sampling](#datadog-priority-sampling) | bool | "true" |
|
||||
| [datadog-sample-rate](#datadog-sample-rate) | float | 1.0 |
|
||||
| [main-snippet](#main-snippet) | string | "" |
|
||||
| [http-snippet](#http-snippet) | string | "" |
|
||||
| [server-snippet](#server-snippet) | string | "" |
|
||||
| [stream-snippet](#stream-snippet) | string | "" |
|
||||
| [location-snippet](#location-snippet) | string | "" |
|
||||
| [custom-http-errors](#custom-http-errors) | []int | []int{} |
|
||||
| [proxy-body-size](#proxy-body-size) | string | "1m" |
|
||||
| [proxy-connect-timeout](#proxy-connect-timeout) | int | 5 |
|
||||
| [proxy-read-timeout](#proxy-read-timeout) | int | 60 |
|
||||
| [proxy-send-timeout](#proxy-send-timeout) | int | 60 |
|
||||
| [proxy-buffers-number](#proxy-buffers-number) | int | 4 |
|
||||
| [proxy-buffer-size](#proxy-buffer-size) | string | "4k" |
|
||||
| [proxy-cookie-path](#proxy-cookie-path) | string | "off" |
|
||||
| [proxy-cookie-domain](#proxy-cookie-domain) | string | "off" |
|
||||
| [proxy-next-upstream](#proxy-next-upstream) | string | "error timeout" |
|
||||
| [proxy-next-upstream-timeout](#proxy-next-upstream-timeout) | int | 0 |
|
||||
| [proxy-next-upstream-tries](#proxy-next-upstream-tries) | int | 3 |
|
||||
| [proxy-redirect-from](#proxy-redirect-from) | string | "off" |
|
||||
| [proxy-request-buffering](#proxy-request-buffering) | string | "on" |
|
||||
| [ssl-redirect](#ssl-redirect) | bool | "true" |
|
||||
| [force-ssl-redirect](#force-ssl-redirect) | bool | "false" |
|
||||
| [denylist-source-range](#denylist-source-range) | []string | []string{} |
|
||||
| [whitelist-source-range](#whitelist-source-range) | []string | []string{} |
|
||||
| [skip-access-log-urls](#skip-access-log-urls) | []string | []string{} |
|
||||
| [limit-rate](#limit-rate) | int | 0 |
|
||||
| [limit-rate-after](#limit-rate-after) | int | 0 |
|
||||
| [lua-shared-dicts](#lua-shared-dicts) | string | "" |
|
||||
| [http-redirect-code](#http-redirect-code) | int | 308 |
|
||||
| [proxy-buffering](#proxy-buffering) | string | "off" |
|
||||
| [limit-req-status-code](#limit-req-status-code) | int | 503 |
|
||||
| [limit-conn-status-code](#limit-conn-status-code) | int | 503 |
|
||||
| [enable-syslog](#enable-syslog) | bool | false |
|
||||
| [syslog-host](#syslog-host) | string | "" |
|
||||
| [syslog-port](#syslog-port) | int | 514 |
|
||||
| [no-tls-redirect-locations](#no-tls-redirect-locations) | string | "/.well-known/acme-challenge" |
|
||||
| [global-auth-url](#global-auth-url) | string | "" |
|
||||
| [global-auth-method](#global-auth-method) | string | "" |
|
||||
| [global-auth-signin](#global-auth-signin) | string | "" |
|
||||
| [global-auth-signin-redirect-param](#global-auth-signin-redirect-param) | string | "rd" |
|
||||
| [global-auth-response-headers](#global-auth-response-headers) | string | "" |
|
||||
| [global-auth-request-redirect](#global-auth-request-redirect) | string | "" |
|
||||
| [global-auth-snippet](#global-auth-snippet) | string | "" |
|
||||
| [global-auth-cache-key](#global-auth-cache-key) | string | "" |
|
||||
| [global-auth-cache-duration](#global-auth-cache-duration) | string | "200 202 401 5m" |
|
||||
| [no-auth-locations](#no-auth-locations) | string | "/.well-known/acme-challenge" |
|
||||
| [block-cidrs](#block-cidrs) | []string | "" |
|
||||
| [block-user-agents](#block-user-agents) | []string | "" |
|
||||
| [block-referers](#block-referers) | []string | "" |
|
||||
| [proxy-ssl-location-only](#proxy-ssl-location-only) | bool | "false" |
|
||||
| [default-type](#default-type) | string | "text/html" |
|
||||
| [global-rate-limit-memcached-host](#global-rate-limit) | string | "" |
|
||||
| [global-rate-limit-memcached-port](#global-rate-limit) | int | 11211 |
|
||||
| [global-rate-limit-memcached-connect-timeout](#global-rate-limit) | int | 50 |
|
||||
| [global-rate-limit-memcached-max-idle-timeout](#global-rate-limit) | int | 10000 |
|
||||
| [global-rate-limit-memcached-pool-size](#global-rate-limit) | int | 50 |
|
||||
| [global-rate-limit-status-code](#global-rate-limit) | int | 429 |
|
||||
| [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" |
|
||||
| [enable-pathtype-validation](#enable-pathtype-validation) | bool | "false" |
|
||||
| [path-additional-allowed-chars](#path-additional-allowed-chars) | string | "^%$[](){}*+?" |
|
||||
|
||||
## add-headers
|
||||
|
||||
|
@ -693,7 +697,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)
|
||||
|
||||
|
@ -714,6 +719,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
|
||||
|
@ -1319,3 +1328,22 @@ _**default:**_ ""
|
|||
|
||||
_References:_
|
||||
[http://nginx.org/en/docs/ngx_core_module.html#debug_connection](http://nginx.org/en/docs/ngx_core_module.html#debug_connection)
|
||||
|
||||
## enable-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 is disabled by default, so special characters are accepted regardless of pathType
|
||||
_**default:**_ "false"
|
||||
|
||||
## path-additional-allowed-chars
|
||||
When [enable-pathtype-validation](enable-pathtype-validation) is set to true [#path-additional-allowed-chars](#path-additional-allowed-chars) defines the additional set of special characters that
|
||||
will be allowed.
|
||||
|
||||
_**default:**_ "^%$[](){}*+?|"
|
||||
|
|
44
go.mod
44
go.mod
|
@ -26,36 +26,26 @@ require (
|
|||
github.com/yudai/gojsondiff v1.0.0
|
||||
github.com/zakjan/cert-chain-resolver v0.0.0-20211122211144-c6b0b792af9a
|
||||
golang.org/x/crypto v0.5.0
|
||||
google.golang.org/grpc v1.51.0
|
||||
google.golang.org/grpc v1.52.3
|
||||
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/klog/v2 v2.80.1
|
||||
k8s.io/api v0.26.1
|
||||
k8s.io/apiextensions-apiserver v0.26.1
|
||||
k8s.io/apimachinery v0.26.1
|
||||
k8s.io/apiserver v0.26.1
|
||||
k8s.io/cli-runtime v0.26.0
|
||||
k8s.io/client-go v0.26.1
|
||||
k8s.io/code-generator v0.26.1
|
||||
k8s.io/component-base v0.26.1
|
||||
k8s.io/klog/v2 v2.90.0
|
||||
pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732
|
||||
sigs.k8s.io/controller-runtime v0.13.1
|
||||
sigs.k8s.io/controller-runtime v0.14.2
|
||||
sigs.k8s.io/mdtoc v1.1.0
|
||||
)
|
||||
|
||||
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
|
||||
|
@ -98,6 +87,7 @@ require (
|
|||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/ncabatoff/go-seq v0.0.0-20180805175032-b08ef85ed833 // indirect
|
||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
|
@ -114,7 +104,7 @@ require (
|
|||
golang.org/x/sys v0.4.0 // indirect
|
||||
golang.org/x/term v0.4.0 // indirect
|
||||
golang.org/x/text v0.6.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.4.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
|
||||
|
@ -123,9 +113,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-20221128185143-99ec85e7a448 // 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
|
||||
|
|
122
go.sum
122
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=
|
||||
|
@ -111,6 +87,8 @@ github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQL
|
|||
github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
|
||||
github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/fullsailor/pkcs7 v0.0.0-20160414161337-2585af45975b h1:074/xhloHUBOpTZwlIzQ28rbPY8pNJvzY7Gcx5KnNOk=
|
||||
|
@ -126,7 +104,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,21 +112,19 @@ 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=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro=
|
||||
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
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=
|
||||
|
@ -223,6 +198,7 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWet
|
|||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
|
||||
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
|
||||
|
@ -302,10 +278,17 @@ github.com/ncabatoff/go-seq v0.0.0-20180805175032-b08ef85ed833/go.mod h1:0CznHmX
|
|||
github.com/ncabatoff/process-exporter v0.7.10 h1:+Ere7+3se6QqP54gg7aBRagWcL8bq3u5zNi/GRSWeKQ=
|
||||
github.com/ncabatoff/process-exporter v0.7.10/go.mod h1:DHZRZjqxw9LCOpLlX0DjBuyn6d5plh41Jv6Tmttj7Ek=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.6.1 h1:1xQPCjcqYw/J5LchOcp4/2q/jzJFjiAOc25chhnDw+Q=
|
||||
github.com/onsi/ginkgo/v2 v2.6.1/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
|
||||
github.com/opencontainers/runc v1.1.4 h1:nRCz/8sKg6K6jgYAFLDlXzPeITBZJyX28DBVhWD+5dg=
|
||||
github.com/opencontainers/runc v1.1.4/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg=
|
||||
|
@ -362,7 +345,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=
|
||||
|
@ -412,7 +394,7 @@ go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee33
|
|||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
|
@ -421,8 +403,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=
|
||||
|
@ -459,6 +439,7 @@ golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
|||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -471,7 +452,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=
|
||||
|
@ -482,6 +462,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
|
|||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
|
@ -490,7 +471,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,9 +491,9 @@ 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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -525,10 +505,13 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -549,6 +532,7 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -574,8 +558,8 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U=
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
|
@ -618,6 +602,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
|
|||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4=
|
||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||
|
@ -694,8 +679,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
|
|||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
|
||||
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
|
||||
google.golang.org/grpc v1.52.3 h1:pf7sOysg4LdgBqduXveGKrcEwbStiK2rtfghdzlUYDQ=
|
||||
google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
|
||||
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7 h1:pPsdyuBif+uoyUoL19yuj/TCfUPsmpJHJZhWQ98JGLU=
|
||||
google.golang.org/grpc/examples v0.0.0-20221220003428-4f16fbe410f7/go.mod h1:8pQa1yxxkh+EsxUK8/455D5MSbv3vgmEJqKCH3y17mI=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
|
@ -721,6 +706,7 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8
|
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/pool.v3 v3.1.1 h1:4Qcj91IsYTpIeRhe/eo6Fz+w6uKWPEghx8vHFTYMfhw=
|
||||
|
@ -730,6 +716,7 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
|||
gopkg.in/mcuadros/go-syslog.v2 v2.3.0 h1:kcsiS+WsTKyIEPABJBJtoG0KkOS6yzvJ+/eZlhD79kk=
|
||||
gopkg.in/mcuadros/go-syslog.v2 v2.3.0/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
@ -750,39 +737,38 @@ 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.1 h1:f+SWYiPd/GsiWwVRz+NbFyCgvv75Pk9NK6dlkZgpCRQ=
|
||||
k8s.io/api v0.26.1/go.mod h1:xd/GBNgR0f707+ATNyPmQ1oyKSgndzXij81FzWGsejg=
|
||||
k8s.io/apiextensions-apiserver v0.26.1 h1:cB8h1SRk6e/+i3NOrQgSFij1B2S0Y0wDoNl66bn8RMI=
|
||||
k8s.io/apiextensions-apiserver v0.26.1/go.mod h1:AptjOSXDGuE0JICx/Em15PaoO7buLwTs0dGleIHixSM=
|
||||
k8s.io/apimachinery v0.26.1 h1:8EZ/eGJL+hY/MYCNwhmDzVqq2lPl3N3Bo8rvweJwXUQ=
|
||||
k8s.io/apimachinery v0.26.1/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74=
|
||||
k8s.io/apiserver v0.26.1 h1:6vmnAqCDO194SVCPU3MU8NcDgSqsUA62tBUSWrFXhsc=
|
||||
k8s.io/apiserver v0.26.1/go.mod h1:wr75z634Cv+sifswE9HlAo5FQ7UoUauIICRlOE+5dCg=
|
||||
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.1 h1:87CXzYJnAMGaa/IDDfRdhTzxk/wzGZ+/HUQpqgVSZXU=
|
||||
k8s.io/client-go v0.26.1/go.mod h1:IWNSglg+rQ3OcvDkhY6+QLeasV4OYHDjdqeWkDQZwGE=
|
||||
k8s.io/code-generator v0.26.1 h1:dusFDsnNSKlMFYhzIM0jAO1OlnTN5WYwQQ+Ai12IIlo=
|
||||
k8s.io/code-generator v0.26.1/go.mod h1:OMoJ5Dqx1wgaQzKgc+ZWaZPfGjdRq/Y3WubFrZmeI3I=
|
||||
k8s.io/component-base v0.26.1 h1:4ahudpeQXHZL5kko+iDHqLj/FSGAEUnSVO0EBbgDd+4=
|
||||
k8s.io/component-base v0.26.1/go.mod h1:VHrLR0b58oC035w6YQiBSbtsf0ThuSwXP+p5dD/kAWU=
|
||||
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/klog/v2 v2.90.0 h1:VkTxIV/FjRXn1fgNNcKGM8cfmL1Z33ZjXRTVxKCoF5M=
|
||||
k8s.io/klog/v2 v2.90.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
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-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y=
|
||||
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/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=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/controller-runtime v0.13.1 h1:tUsRCSJVM1QQOOeViGeX3GMT3dQF1eePPw6sEE3xSlg=
|
||||
sigs.k8s.io/controller-runtime v0.13.1/go.mod h1:Zbz+el8Yg31jubvAEyglRZGdLAjplZl+PgtYNI6WNTI=
|
||||
sigs.k8s.io/controller-runtime v0.14.2 h1:P6IwDhbsRWsBClt/8/h8Zy36bCuGuW5Op7MHpFrN/60=
|
||||
sigs.k8s.io/controller-runtime v0.14.2/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0=
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||
sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM=
|
||||
|
|
68
ingress-nginx.yaml
Normal file
68
ingress-nginx.yaml
Normal file
|
@ -0,0 +1,68 @@
|
|||
CURRENT_VERSION: "v1.5.1"
|
||||
GOLANG_VERSION: "1.19.2"
|
||||
GIT_TAG: "controller-v1.5.1"
|
||||
NGINX_BASE_IMAGE: "registry.k8s.io/ingress-nginx/nginx:0b5e0685112e4537ee20a0bdbba451e9f6158aa3@sha256:3f5e28bb248d5170e77b77fc2a1a385724aeff41a0b34b5afad7dd9cf93de000"
|
||||
NGINX_VERSION: "1.21.6"
|
||||
VERSION_TABLE:
|
||||
- "v1.5.1":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: ["1.25","1.24","1.23"]
|
||||
- NGINX: "1.21.6"
|
||||
- CONTROLLER_IMAGE: "registry.k8s.io/ingress-nginx/controller:v1.5.1@sha256:4ba73c697770664c1e00e9f968de14e08f606ff961c76e5d7033a4a9c593c629"
|
||||
- CHROOT_CONTROLLER_IMAGE: "registry.k8s.io/ingress-nginx/controller-chroot:v1.5.1@sha256:c1c091b88a6c936a83bd7b098662760a87868d12452529bad0d178fb36147345"
|
||||
- "v1.4.0":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: [ "1.24","1.23", "1.22", "1.21", "1.20" ]
|
||||
- NGINX: "1.19.10"
|
||||
- "v1.3.1":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: [ "1.24","1.23", "1.22", "1.21", "1.20" ]
|
||||
- NGINX: "1.19.10"
|
||||
- "v1.3.0":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: [ "1.24","1.23", "1.22", "1.21", "1.20" ]
|
||||
- NGINX: "1.19.10"
|
||||
- "v1.2.1":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: [ "1.24","1.23", "1.22", "1.21", "1.20" ]
|
||||
- NGINX: "1.19.10"
|
||||
- "v1.1.3":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: [ "1.24","1.23", "1.22", "1.21", "1.20" ]
|
||||
- NGINX: "1.19.10"
|
||||
- "v1.1.2":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: [ "1.24","1.23", "1.22", "1.21", "1.20" ]
|
||||
- NGINX: "1.19.10"
|
||||
- "v1.1.1":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: [ "1.24","1.23", "1.22", "1.21", "1.20" ]
|
||||
- NGINX: "1.19.10"
|
||||
- "v1.1.0":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: [ "1.24","1.23", "1.22", "1.21", "1.20" ]
|
||||
- NGINX: "1.19.10"
|
||||
- "v1.0.5":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: [ "1.24","1.23", "1.22", "1.21", "1.20" ]
|
||||
- NGINX: "1.19.10"
|
||||
- "v1.0.4":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: [ "1.24","1.23", "1.22", "1.21", "1.20" ]
|
||||
- NGINX: "1.19.10"
|
||||
- "v1.0.3":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: [ "1.24","1.23", "1.22", "1.21", "1.20" ]
|
||||
- NGINX: "1.19.10"
|
||||
- "v1.0.2":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: [ "1.24","1.23", "1.22", "1.21", "1.20" ]
|
||||
- NGINX: "1.19.10"
|
||||
- "v1.0.1":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: [ "1.24","1.23", "1.22", "1.21", "1.20" ]
|
||||
- NGINX: "1.19.10"
|
||||
- "v1.0.0":
|
||||
- Alpine: "3.16.2"
|
||||
- Kubernetes: [ "1.24","1.23", "1.22", "1.21", "1.20" ]
|
||||
- NGINX: "1.19.10"
|
|
@ -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"`
|
||||
|
||||
|
@ -825,6 +830,18 @@ type Configuration struct {
|
|||
// http://nginx.org/en/docs/ngx_core_module.html#debug_connection
|
||||
// Default: ""
|
||||
DebugConnections []string `json:"debug-connections"`
|
||||
|
||||
// EnablePathTypeValidation allows the admin to enable the pathType validation.
|
||||
// If EnablePathTypeValidation is enabled, the Controller will only allow alphanumeric
|
||||
// characters on path (0-9, a-z, A-Z, "-", ".", "_", "~", "/")
|
||||
// to control what characters are allowed set them with PathAdditionalAllowedChars
|
||||
EnablePathTypeValidation bool `json:"enable-pathtype-validation"`
|
||||
|
||||
// PathAdditionalAllowedChars allows the admin to specify what are the additional
|
||||
// characters allowed in case of pathType=ImplementationSpecific.
|
||||
// Case enable-pathtype-validation=true, this characters will be only allowed on ImplementationSpecific.
|
||||
// Defaults to: "^%$[](){}*+?"
|
||||
PathAdditionalAllowedChars string `json:"path-additional-allowed-chars"`
|
||||
}
|
||||
|
||||
// NewDefault returns the default nginx configuration
|
||||
|
@ -842,7 +859,6 @@ func NewDefault() Configuration {
|
|||
defGlobalExternalAuth := GlobalExternalAuth{"", "", "", "", "", append(defResponseHeaders, ""), "", "", "", []string{}, map[string]string{}, false}
|
||||
|
||||
cfg := Configuration{
|
||||
|
||||
AllowSnippetAnnotations: true,
|
||||
AllowBackendServerHeader: false,
|
||||
AnnotationValueWordBlocklist: "",
|
||||
|
@ -861,6 +877,8 @@ func NewDefault() Configuration {
|
|||
ClientHeaderTimeout: 60,
|
||||
ClientBodyBufferSize: "8k",
|
||||
ClientBodyTimeout: 60,
|
||||
EnablePathTypeValidation: false,
|
||||
PathAdditionalAllowedChars: "^%$[](){}*+?|",
|
||||
EnableUnderscoresInHeaders: false,
|
||||
ErrorLogLevel: errorLevel,
|
||||
UseForwardedHeaders: false,
|
||||
|
@ -883,7 +901,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.EnablePathTypeValidation, 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 enabled", func(t *testing.T) {
|
||||
nginx.store = fakeIngressStore{
|
||||
ingresses: []*ingress.Ingress{},
|
||||
configuration: ngx_config.Configuration{
|
||||
EnablePathTypeValidation: true,
|
||||
},
|
||||
}
|
||||
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{
|
||||
EnablePathTypeValidation: false,
|
||||
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.EnablePathTypeValidation, 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
82
magefiles/common.go
Normal file
82
magefiles/common.go
Normal file
|
@ -0,0 +1,82 @@
|
|||
//go:build mage
|
||||
|
||||
/*
|
||||
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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var DEBUG bool
|
||||
|
||||
func init() {
|
||||
DEBUG = false
|
||||
debugENV := os.Getenv("MAGE_DEBUG")
|
||||
if debugENV == "true" {
|
||||
DEBUG = true
|
||||
}
|
||||
}
|
||||
|
||||
// CheckArgs should be used to ensure the right command line arguments are
|
||||
// passed before executing an example.
|
||||
func CheckArgs(arg ...string) {
|
||||
if len(os.Args) < len(arg)+1 {
|
||||
ErrorF("Usage: %s %s", os.Args[0], strings.Join(arg, " "))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// CheckIfError should be used to naively panics if an error is not nil.
|
||||
func CheckIfError(err error, format string, args ...interface{}) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("\x1b[31;1m%s ERROR %s %s\x1b[0m\n", timeStamp(), fmt.Sprintf(format, args...), err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Info should be used to describe the example commands that are about to run.
|
||||
func Info(format string, args ...interface{}) {
|
||||
fmt.Printf("\x1b[34;1m%s INFO: %s\x1b[0m\n", timeStamp(), fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func timeStamp() string {
|
||||
t := time.Now()
|
||||
return t.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
// Warning should be used to display a warning
|
||||
func Warning(format string, args ...interface{}) {
|
||||
fmt.Printf("\x1b[36;1m%s WARNING: %s\x1b[0m\n", timeStamp(), fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// Info should be used to describe the example commands that are about to run.
|
||||
func Debug(format string, args ...interface{}) {
|
||||
if DEBUG {
|
||||
fmt.Printf("\x1b[34;1m%s DEBUG: %s\x1b[0m\n", timeStamp(), fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
// Info should be used to describe the example commands that are about to run.
|
||||
func ErrorF(format string, args ...interface{}) {
|
||||
fmt.Printf("\x1b[31;1m%s ERROR: %s\x1b[0m\n", timeStamp(), fmt.Sprintf(format, args...))
|
||||
}
|
19
magefiles/docker.go
Normal file
19
magefiles/docker.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
//go:build mage
|
||||
|
||||
/*
|
||||
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 main
|
31
magefiles/go.go
Normal file
31
magefiles/go.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
//go:build mage
|
||||
|
||||
/*
|
||||
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 main
|
||||
|
||||
//import (
|
||||
// "github.com/magefile/mage/mg"
|
||||
// "github.com/mysteriumnetwork/go-ci/commands"
|
||||
//)
|
||||
//
|
||||
//type Go mg.Namespace
|
||||
//
|
||||
//// Checks for issues with go imports
|
||||
//func (Go) CheckGoImports() error {
|
||||
// return commands.GoImports("./...")
|
||||
//}
|
32
magefiles/go.mod
Normal file
32
magefiles/go.mod
Normal file
|
@ -0,0 +1,32 @@
|
|||
module github.com/kubernetes/ingress-nginx/magefiles
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/blang/semver/v4 v4.0.0
|
||||
github.com/google/go-github/v48 v48.2.0
|
||||
github.com/helm/helm v2.17.0+incompatible
|
||||
github.com/magefile/mage v1.14.0
|
||||
github.com/vmware-labs/yaml-jsonpath v0.3.2
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.2.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||
github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/stretchr/testify v1.8.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/apimachinery v0.25.4 // indirect
|
||||
k8s.io/helm v2.17.0+incompatible // indirect
|
||||
)
|
105
magefiles/go.sum
Normal file
105
magefiles/go.sum
Normal file
|
@ -0,0 +1,105 @@
|
|||
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
|
||||
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960 h1:aRd8M7HJVZOqn/vhOzrGcQH0lNAMkqMn+pXUYkatmcA=
|
||||
github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-github/v48 v48.2.0 h1:68puzySE6WqUY9KWmpOsDEQfDZsso98rT6pZcz9HqcE=
|
||||
github.com/google/go-github/v48 v48.2.0/go.mod h1:dDlehKBDo850ZPvCTK0sEqTCVWcrGl2LcDiajkYi89Y=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/helm/helm v2.17.0+incompatible h1:0iy95yMXrfWpwaoOA9XRP+cTvitTrq+LcJV9DvR5n1Y=
|
||||
github.com/helm/helm v2.17.0+incompatible/go.mod h1:ahXhuvluW4YnSL6W6hDVetZsVK8Pv4BP8OwKli7aMqo=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
|
||||
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.2 h1:uqH7bpe+ERSiDa34FDOF7RikN6RzXgduUF8yarlZp94=
|
||||
github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk=
|
||||
github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/apimachinery v0.25.4 h1:CtXsuaitMESSu339tfhVXhQrPET+EiWnIY1rcurKnAc=
|
||||
k8s.io/apimachinery v0.25.4/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo=
|
||||
k8s.io/helm v2.17.0+incompatible h1:Bpn6o1wKLYqKM3+Osh8e+1/K2g/GsQJ4F4yNF2+deao=
|
||||
k8s.io/helm v2.17.0+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI=
|
624
magefiles/helm.go
Normal file
624
magefiles/helm.go
Normal file
|
@ -0,0 +1,624 @@
|
|||
//go:build mage
|
||||
|
||||
/*
|
||||
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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
semver "github.com/blang/semver/v4"
|
||||
"github.com/helm/helm/pkg/chartutil"
|
||||
"github.com/magefile/mage/mg"
|
||||
"github.com/magefile/mage/sh"
|
||||
yamlpath "github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath"
|
||||
"gopkg.in/yaml.v3"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const HelmChartPath = "charts/ingress-nginx/Chart.yaml"
|
||||
const HelmChartValues = "charts/ingress-nginx/values.yaml"
|
||||
|
||||
type Helm mg.Namespace
|
||||
|
||||
// UpdateAppVersion Updates the Helm App Version of Ingress Nginx Controller
|
||||
func (Helm) UpdateAppVersion() {
|
||||
updateAppVersion()
|
||||
}
|
||||
|
||||
func updateAppVersion() {
|
||||
|
||||
}
|
||||
|
||||
// UpdateVersion Update Helm Version of the Chart
|
||||
func (Helm) UpdateVersion(version string) {
|
||||
updateVersion(version)
|
||||
}
|
||||
|
||||
func currentChartVersion() string {
|
||||
chart, err := chartutil.LoadChartfile(HelmChartPath)
|
||||
CheckIfError(err, "HELM Could not Load Chart")
|
||||
return chart.Version
|
||||
}
|
||||
|
||||
func currentChartAppVersion() string {
|
||||
chart, err := chartutil.LoadChartfile(HelmChartPath)
|
||||
CheckIfError(err, "HELM Could not Load Chart")
|
||||
return chart.AppVersion
|
||||
}
|
||||
|
||||
func updateVersion(version string) {
|
||||
Info("HELM Reading File %v", HelmChartPath)
|
||||
|
||||
chart, err := chartutil.LoadChartfile(HelmChartPath)
|
||||
CheckIfError(err, "HELM Could not Load Chart")
|
||||
|
||||
//Get the current tag
|
||||
//appVersionV, err := getIngressNGINXVersion()
|
||||
//CheckIfError(err, "HELM Issue Retrieving the Current Ingress Nginx Version")
|
||||
|
||||
//remove the v from TAG
|
||||
appVersion := version
|
||||
|
||||
Info("HELM Ingress-Nginx App Version: %s Chart AppVersion: %s", appVersion, chart.AppVersion)
|
||||
if appVersion == chart.AppVersion {
|
||||
Warning("HELM Ingress NGINX Version didnt change Ingress-Nginx App Version: %s Chart AppVersion: %s", appVersion, chart.AppVersion)
|
||||
return
|
||||
}
|
||||
|
||||
//Update the helm chart
|
||||
chart.AppVersion = appVersion
|
||||
cTag, err := semver.Make(chart.Version)
|
||||
CheckIfError(err, "HELM Creating Chart Version: %v", err)
|
||||
|
||||
if err = cTag.IncrementPatch(); err != nil {
|
||||
ErrorF("HELM Incrementing Chart Version: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
chart.Version = cTag.String()
|
||||
Debug("HELM Updated Chart Version: %v", chart.Version)
|
||||
|
||||
err = chartutil.SaveChartfile(HelmChartPath, chart)
|
||||
CheckIfError(err, "HELM Saving new Chart")
|
||||
}
|
||||
|
||||
func updateChartReleaseNotes(releasesNotes []string) {
|
||||
Info("HELM Updating the Chart Release notes")
|
||||
chart, err := chartutil.LoadChartfile(HelmChartPath)
|
||||
CheckIfError(err, "HELM Could not Load Chart to update release notes %s", HelmChartPath)
|
||||
var releaseNoteString string
|
||||
for i := range releasesNotes {
|
||||
releaseNoteString = fmt.Sprintf("%s - %s\n", releaseNoteString, releasesNotes[i])
|
||||
}
|
||||
Info("HELM Release note string %s", releaseNoteString)
|
||||
chart.Annotations["artifacthub.io/changes"] = releaseNoteString
|
||||
err = chartutil.SaveChartfile(HelmChartPath, chart)
|
||||
CheckIfError(err, "HELM Saving updated release notes for Chart")
|
||||
}
|
||||
|
||||
func UpdateChartChangelog() {
|
||||
|
||||
}
|
||||
|
||||
// UpdateAppVersion Updates the Helm App Version of Ingress Nginx Controller
|
||||
func (Helm) UpdateChartValue(key, value string) {
|
||||
updateChartValue(key, value)
|
||||
}
|
||||
|
||||
func updateChartValue(key, value string) {
|
||||
Info("HELM Updating Chart %s %s:%s", HelmChartValues, key, value)
|
||||
|
||||
//read current values.yaml
|
||||
data, err := os.ReadFile(HelmChartValues)
|
||||
CheckIfError(err, "HELM Could not Load Helm Chart Values files %s", HelmChartValues)
|
||||
|
||||
//var valuesStruct IngressChartValue
|
||||
var n yaml.Node
|
||||
CheckIfError(yaml.Unmarshal(data, &n), "HELM Could not Unmarshal %s", HelmChartValues)
|
||||
|
||||
//update value
|
||||
//keyParse := parsePath(key)
|
||||
p, err := yamlpath.NewPath(key)
|
||||
CheckIfError(err, "HELM cannot create path")
|
||||
|
||||
q, err := p.Find(&n)
|
||||
CheckIfError(err, "HELM unexpected error finding path")
|
||||
|
||||
for _, i := range q {
|
||||
Info("HELM Found %s at %s", i.Value, key)
|
||||
i.Value = value
|
||||
Info("HELM Updated %s at %s", i.Value, key)
|
||||
}
|
||||
|
||||
//// write to file
|
||||
newValueFile, err := yaml.Marshal(&n)
|
||||
CheckIfError(err, "HELM Could not Marshal new Values file")
|
||||
err = os.WriteFile(HelmChartValues, newValueFile, 0644)
|
||||
CheckIfError(err, "HELM Could not write new Values file to %s", HelmChartValues)
|
||||
|
||||
Info("HELM Ingress Nginx Helm Chart update %s %s", key, value)
|
||||
}
|
||||
|
||||
func runHelmDocs() error {
|
||||
err := installHelmDocs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = sh.RunV("helm-docs", "--chart-search-root=${PWD}/charts")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func installHelmDocs() error {
|
||||
Info("HELM Install HelmDocs")
|
||||
var g0 = sh.RunCmd("go")
|
||||
|
||||
err := g0("install", "github.com/norwoodj/helm-docs/cmd/helm-docs@v1.11.0")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func parsePath(key string) []string { return strings.Split(key, ".") }
|
||||
|
||||
func updateHelmDocs() {
|
||||
|
||||
}
|
||||
|
||||
type IngressChartValue struct {
|
||||
CommonLabels struct {
|
||||
} `yaml:"commonLabels"`
|
||||
Controller struct {
|
||||
Name string `yaml:"name"`
|
||||
Image struct {
|
||||
Chroot bool `yaml:"chroot"`
|
||||
Registry string `yaml:"registry"`
|
||||
Image string `yaml:"image"`
|
||||
Tag string `yaml:"tag"`
|
||||
Digest string `yaml:"digest"`
|
||||
DigestChroot string `yaml:"digestChroot"`
|
||||
PullPolicy string `yaml:"pullPolicy"`
|
||||
RunAsUser int `yaml:"runAsUser"`
|
||||
AllowPrivilegeEscalation bool `yaml:"allowPrivilegeEscalation"`
|
||||
} `yaml:"image"`
|
||||
ExistingPsp string `yaml:"existingPsp"`
|
||||
ContainerName string `yaml:"containerName"`
|
||||
ContainerPort struct {
|
||||
HTTP int `yaml:"http"`
|
||||
HTTPS int `yaml:"https"`
|
||||
} `yaml:"containerPort"`
|
||||
Config struct {
|
||||
} `yaml:"config"`
|
||||
ConfigAnnotations struct {
|
||||
} `yaml:"configAnnotations"`
|
||||
ProxySetHeaders struct {
|
||||
} `yaml:"proxySetHeaders"`
|
||||
AddHeaders struct {
|
||||
} `yaml:"addHeaders"`
|
||||
DNSConfig struct {
|
||||
} `yaml:"dnsConfig"`
|
||||
Hostname struct {
|
||||
} `yaml:"hostname"`
|
||||
DNSPolicy string `yaml:"dnsPolicy"`
|
||||
ReportNodeInternalIP bool `yaml:"reportNodeInternalIp"`
|
||||
WatchIngressWithoutClass bool `yaml:"watchIngressWithoutClass"`
|
||||
IngressClassByName bool `yaml:"ingressClassByName"`
|
||||
AllowSnippetAnnotations bool `yaml:"allowSnippetAnnotations"`
|
||||
HostNetwork bool `yaml:"hostNetwork"`
|
||||
HostPort struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Ports struct {
|
||||
HTTP int `yaml:"http"`
|
||||
HTTPS int `yaml:"https"`
|
||||
} `yaml:"ports"`
|
||||
} `yaml:"hostPort"`
|
||||
ElectionID string `yaml:"electionID"`
|
||||
IngressClassResource struct {
|
||||
Name string `yaml:"name"`
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Default bool `yaml:"default"`
|
||||
ControllerValue string `yaml:"controllerValue"`
|
||||
Parameters struct {
|
||||
} `yaml:"parameters"`
|
||||
} `yaml:"ingressClassResource"`
|
||||
IngressClass string `yaml:"ingressClass"`
|
||||
PodLabels struct {
|
||||
} `yaml:"podLabels"`
|
||||
PodSecurityContext struct {
|
||||
} `yaml:"podSecurityContext"`
|
||||
Sysctls struct {
|
||||
} `yaml:"sysctls"`
|
||||
PublishService struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
PathOverride string `yaml:"pathOverride"`
|
||||
} `yaml:"publishService"`
|
||||
Scope struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Namespace string `yaml:"namespace"`
|
||||
NamespaceSelector string `yaml:"namespaceSelector"`
|
||||
} `yaml:"scope"`
|
||||
ConfigMapNamespace string `yaml:"configMapNamespace"`
|
||||
TCP struct {
|
||||
ConfigMapNamespace string `yaml:"configMapNamespace"`
|
||||
Annotations struct {
|
||||
} `yaml:"annotations"`
|
||||
} `yaml:"tcp"`
|
||||
UDP struct {
|
||||
ConfigMapNamespace string `yaml:"configMapNamespace"`
|
||||
Annotations struct {
|
||||
} `yaml:"annotations"`
|
||||
} `yaml:"udp"`
|
||||
MaxmindLicenseKey string `yaml:"maxmindLicenseKey"`
|
||||
ExtraArgs struct {
|
||||
} `yaml:"extraArgs"`
|
||||
ExtraEnvs []interface{} `yaml:"extraEnvs"`
|
||||
Kind string `yaml:"kind"`
|
||||
Annotations struct {
|
||||
} `yaml:"annotations"`
|
||||
Labels struct {
|
||||
} `yaml:"labels"`
|
||||
UpdateStrategy struct {
|
||||
} `yaml:"updateStrategy"`
|
||||
MinReadySeconds int `yaml:"minReadySeconds"`
|
||||
Tolerations []interface{} `yaml:"tolerations"`
|
||||
Affinity struct {
|
||||
} `yaml:"affinity"`
|
||||
TopologySpreadConstraints []interface{} `yaml:"topologySpreadConstraints"`
|
||||
TerminationGracePeriodSeconds int `yaml:"terminationGracePeriodSeconds"`
|
||||
NodeSelector struct {
|
||||
KubernetesIoOs string `yaml:"kubernetes.io/os"`
|
||||
} `yaml:"nodeSelector"`
|
||||
LivenessProbe struct {
|
||||
HTTPGet struct {
|
||||
Path string `yaml:"path"`
|
||||
Port int `yaml:"port"`
|
||||
Scheme string `yaml:"scheme"`
|
||||
} `yaml:"httpGet"`
|
||||
InitialDelaySeconds int `yaml:"initialDelaySeconds"`
|
||||
PeriodSeconds int `yaml:"periodSeconds"`
|
||||
TimeoutSeconds int `yaml:"timeoutSeconds"`
|
||||
SuccessThreshold int `yaml:"successThreshold"`
|
||||
FailureThreshold int `yaml:"failureThreshold"`
|
||||
} `yaml:"livenessProbe"`
|
||||
ReadinessProbe struct {
|
||||
HTTPGet struct {
|
||||
Path string `yaml:"path"`
|
||||
Port int `yaml:"port"`
|
||||
Scheme string `yaml:"scheme"`
|
||||
} `yaml:"httpGet"`
|
||||
InitialDelaySeconds int `yaml:"initialDelaySeconds"`
|
||||
PeriodSeconds int `yaml:"periodSeconds"`
|
||||
TimeoutSeconds int `yaml:"timeoutSeconds"`
|
||||
SuccessThreshold int `yaml:"successThreshold"`
|
||||
FailureThreshold int `yaml:"failureThreshold"`
|
||||
} `yaml:"readinessProbe"`
|
||||
HealthCheckPath string `yaml:"healthCheckPath"`
|
||||
HealthCheckHost string `yaml:"healthCheckHost"`
|
||||
PodAnnotations struct {
|
||||
} `yaml:"podAnnotations"`
|
||||
ReplicaCount int `yaml:"replicaCount"`
|
||||
MinAvailable int `yaml:"minAvailable"`
|
||||
Resources struct {
|
||||
Requests struct {
|
||||
CPU string `yaml:"cpu"`
|
||||
Memory string `yaml:"memory"`
|
||||
} `yaml:"requests"`
|
||||
} `yaml:"resources"`
|
||||
Autoscaling struct {
|
||||
APIVersion string `yaml:"apiVersion"`
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Annotations struct {
|
||||
} `yaml:"annotations"`
|
||||
MinReplicas int `yaml:"minReplicas"`
|
||||
MaxReplicas int `yaml:"maxReplicas"`
|
||||
TargetCPUUtilizationPercentage int `yaml:"targetCPUUtilizationPercentage"`
|
||||
TargetMemoryUtilizationPercentage int `yaml:"targetMemoryUtilizationPercentage"`
|
||||
Behavior struct {
|
||||
} `yaml:"behavior"`
|
||||
} `yaml:"autoscaling"`
|
||||
AutoscalingTemplate []interface{} `yaml:"autoscalingTemplate"`
|
||||
Keda struct {
|
||||
APIVersion string `yaml:"apiVersion"`
|
||||
Enabled bool `yaml:"enabled"`
|
||||
MinReplicas int `yaml:"minReplicas"`
|
||||
MaxReplicas int `yaml:"maxReplicas"`
|
||||
PollingInterval int `yaml:"pollingInterval"`
|
||||
CooldownPeriod int `yaml:"cooldownPeriod"`
|
||||
RestoreToOriginalReplicaCount bool `yaml:"restoreToOriginalReplicaCount"`
|
||||
ScaledObject struct {
|
||||
Annotations struct {
|
||||
} `yaml:"annotations"`
|
||||
} `yaml:"scaledObject"`
|
||||
Triggers []interface{} `yaml:"triggers"`
|
||||
Behavior struct {
|
||||
} `yaml:"behavior"`
|
||||
} `yaml:"keda"`
|
||||
EnableMimalloc bool `yaml:"enableMimalloc"`
|
||||
CustomTemplate struct {
|
||||
ConfigMapName string `yaml:"configMapName"`
|
||||
ConfigMapKey string `yaml:"configMapKey"`
|
||||
} `yaml:"customTemplate"`
|
||||
Service struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
AppProtocol bool `yaml:"appProtocol"`
|
||||
Annotations struct {
|
||||
} `yaml:"annotations"`
|
||||
Labels struct {
|
||||
} `yaml:"labels"`
|
||||
ExternalIPs []interface{} `yaml:"externalIPs"`
|
||||
LoadBalancerIP string `yaml:"loadBalancerIP"`
|
||||
LoadBalancerSourceRanges []interface{} `yaml:"loadBalancerSourceRanges"`
|
||||
EnableHTTP bool `yaml:"enableHttp"`
|
||||
EnableHTTPS bool `yaml:"enableHttps"`
|
||||
IPFamilyPolicy string `yaml:"ipFamilyPolicy"`
|
||||
IPFamilies []string `yaml:"ipFamilies"`
|
||||
Ports struct {
|
||||
HTTP int `yaml:"http"`
|
||||
HTTPS int `yaml:"https"`
|
||||
} `yaml:"ports"`
|
||||
TargetPorts struct {
|
||||
HTTP string `yaml:"http"`
|
||||
HTTPS string `yaml:"https"`
|
||||
} `yaml:"targetPorts"`
|
||||
Type string `yaml:"type"`
|
||||
NodePorts struct {
|
||||
HTTP string `yaml:"http"`
|
||||
HTTPS string `yaml:"https"`
|
||||
TCP struct {
|
||||
} `yaml:"tcp"`
|
||||
UDP struct {
|
||||
} `yaml:"udp"`
|
||||
} `yaml:"nodePorts"`
|
||||
External struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
} `yaml:"external"`
|
||||
Internal struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Annotations struct {
|
||||
} `yaml:"annotations"`
|
||||
LoadBalancerSourceRanges []interface{} `yaml:"loadBalancerSourceRanges"`
|
||||
} `yaml:"internal"`
|
||||
} `yaml:"service"`
|
||||
ShareProcessNamespace bool `yaml:"shareProcessNamespace"`
|
||||
ExtraContainers []interface{} `yaml:"extraContainers"`
|
||||
ExtraVolumeMounts []interface{} `yaml:"extraVolumeMounts"`
|
||||
ExtraVolumes []interface{} `yaml:"extraVolumes"`
|
||||
ExtraInitContainers []interface{} `yaml:"extraInitContainers"`
|
||||
ExtraModules []interface{} `yaml:"extraModules"`
|
||||
Opentelemetry struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Image string `yaml:"image"`
|
||||
ContainerSecurityContext struct {
|
||||
AllowPrivilegeEscalation bool `yaml:"allowPrivilegeEscalation"`
|
||||
} `yaml:"containerSecurityContext"`
|
||||
} `yaml:"opentelemetry"`
|
||||
AdmissionWebhooks struct {
|
||||
Annotations struct {
|
||||
} `yaml:"annotations"`
|
||||
Enabled bool `yaml:"enabled"`
|
||||
ExtraEnvs []interface{} `yaml:"extraEnvs"`
|
||||
FailurePolicy string `yaml:"failurePolicy"`
|
||||
Port int `yaml:"port"`
|
||||
Certificate string `yaml:"certificate"`
|
||||
Key string `yaml:"key"`
|
||||
NamespaceSelector struct {
|
||||
} `yaml:"namespaceSelector"`
|
||||
ObjectSelector struct {
|
||||
} `yaml:"objectSelector"`
|
||||
Labels struct {
|
||||
} `yaml:"labels"`
|
||||
ExistingPsp string `yaml:"existingPsp"`
|
||||
NetworkPolicyEnabled bool `yaml:"networkPolicyEnabled"`
|
||||
Service struct {
|
||||
Annotations struct {
|
||||
} `yaml:"annotations"`
|
||||
ExternalIPs []interface{} `yaml:"externalIPs"`
|
||||
LoadBalancerSourceRanges []interface{} `yaml:"loadBalancerSourceRanges"`
|
||||
ServicePort int `yaml:"servicePort"`
|
||||
Type string `yaml:"type"`
|
||||
} `yaml:"service"`
|
||||
CreateSecretJob struct {
|
||||
SecurityContext struct {
|
||||
AllowPrivilegeEscalation bool `yaml:"allowPrivilegeEscalation"`
|
||||
} `yaml:"securityContext"`
|
||||
Resources struct {
|
||||
} `yaml:"resources"`
|
||||
} `yaml:"createSecretJob"`
|
||||
PatchWebhookJob struct {
|
||||
SecurityContext struct {
|
||||
AllowPrivilegeEscalation bool `yaml:"allowPrivilegeEscalation"`
|
||||
} `yaml:"securityContext"`
|
||||
Resources struct {
|
||||
} `yaml:"resources"`
|
||||
} `yaml:"patchWebhookJob"`
|
||||
Patch struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Image struct {
|
||||
Registry string `yaml:"registry"`
|
||||
Image string `yaml:"image"`
|
||||
Tag string `yaml:"tag"`
|
||||
Digest string `yaml:"digest"`
|
||||
PullPolicy string `yaml:"pullPolicy"`
|
||||
} `yaml:"image"`
|
||||
PriorityClassName string `yaml:"priorityClassName"`
|
||||
PodAnnotations struct {
|
||||
} `yaml:"podAnnotations"`
|
||||
NodeSelector struct {
|
||||
KubernetesIoOs string `yaml:"kubernetes.io/os"`
|
||||
} `yaml:"nodeSelector"`
|
||||
Tolerations []interface{} `yaml:"tolerations"`
|
||||
Labels struct {
|
||||
} `yaml:"labels"`
|
||||
SecurityContext struct {
|
||||
RunAsNonRoot bool `yaml:"runAsNonRoot"`
|
||||
RunAsUser int `yaml:"runAsUser"`
|
||||
FsGroup int `yaml:"fsGroup"`
|
||||
} `yaml:"securityContext"`
|
||||
} `yaml:"patch"`
|
||||
CertManager struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
RootCert struct {
|
||||
Duration string `yaml:"duration"`
|
||||
} `yaml:"rootCert"`
|
||||
AdmissionCert struct {
|
||||
Duration string `yaml:"duration"`
|
||||
} `yaml:"admissionCert"`
|
||||
} `yaml:"certManager"`
|
||||
} `yaml:"admissionWebhooks"`
|
||||
Metrics struct {
|
||||
Port int `yaml:"port"`
|
||||
PortName string `yaml:"portName"`
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Service struct {
|
||||
Annotations struct {
|
||||
} `yaml:"annotations"`
|
||||
ExternalIPs []interface{} `yaml:"externalIPs"`
|
||||
LoadBalancerSourceRanges []interface{} `yaml:"loadBalancerSourceRanges"`
|
||||
ServicePort int `yaml:"servicePort"`
|
||||
Type string `yaml:"type"`
|
||||
} `yaml:"service"`
|
||||
ServiceMonitor struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
AdditionalLabels struct {
|
||||
} `yaml:"additionalLabels"`
|
||||
Namespace string `yaml:"namespace"`
|
||||
NamespaceSelector struct {
|
||||
} `yaml:"namespaceSelector"`
|
||||
ScrapeInterval string `yaml:"scrapeInterval"`
|
||||
TargetLabels []interface{} `yaml:"targetLabels"`
|
||||
Relabelings []interface{} `yaml:"relabelings"`
|
||||
MetricRelabelings []interface{} `yaml:"metricRelabelings"`
|
||||
} `yaml:"serviceMonitor"`
|
||||
PrometheusRule struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
AdditionalLabels struct {
|
||||
} `yaml:"additionalLabels"`
|
||||
Rules []interface{} `yaml:"rules"`
|
||||
} `yaml:"prometheusRule"`
|
||||
} `yaml:"metrics"`
|
||||
Lifecycle struct {
|
||||
PreStop struct {
|
||||
Exec struct {
|
||||
Command []string `yaml:"command"`
|
||||
} `yaml:"exec"`
|
||||
} `yaml:"preStop"`
|
||||
} `yaml:"lifecycle"`
|
||||
PriorityClassName string `yaml:"priorityClassName"`
|
||||
} `yaml:"controller"`
|
||||
RevisionHistoryLimit int `yaml:"revisionHistoryLimit"`
|
||||
DefaultBackend struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
Name string `yaml:"name"`
|
||||
Image struct {
|
||||
Registry string `yaml:"registry"`
|
||||
Image string `yaml:"image"`
|
||||
Tag string `yaml:"tag"`
|
||||
PullPolicy string `yaml:"pullPolicy"`
|
||||
RunAsUser int `yaml:"runAsUser"`
|
||||
RunAsNonRoot bool `yaml:"runAsNonRoot"`
|
||||
ReadOnlyRootFilesystem bool `yaml:"readOnlyRootFilesystem"`
|
||||
AllowPrivilegeEscalation bool `yaml:"allowPrivilegeEscalation"`
|
||||
} `yaml:"image"`
|
||||
ExistingPsp string `yaml:"existingPsp"`
|
||||
ExtraArgs struct {
|
||||
} `yaml:"extraArgs"`
|
||||
ServiceAccount struct {
|
||||
Create bool `yaml:"create"`
|
||||
Name string `yaml:"name"`
|
||||
AutomountServiceAccountToken bool `yaml:"automountServiceAccountToken"`
|
||||
} `yaml:"serviceAccount"`
|
||||
ExtraEnvs []interface{} `yaml:"extraEnvs"`
|
||||
Port int `yaml:"port"`
|
||||
LivenessProbe struct {
|
||||
FailureThreshold int `yaml:"failureThreshold"`
|
||||
InitialDelaySeconds int `yaml:"initialDelaySeconds"`
|
||||
PeriodSeconds int `yaml:"periodSeconds"`
|
||||
SuccessThreshold int `yaml:"successThreshold"`
|
||||
TimeoutSeconds int `yaml:"timeoutSeconds"`
|
||||
} `yaml:"livenessProbe"`
|
||||
ReadinessProbe struct {
|
||||
FailureThreshold int `yaml:"failureThreshold"`
|
||||
InitialDelaySeconds int `yaml:"initialDelaySeconds"`
|
||||
PeriodSeconds int `yaml:"periodSeconds"`
|
||||
SuccessThreshold int `yaml:"successThreshold"`
|
||||
TimeoutSeconds int `yaml:"timeoutSeconds"`
|
||||
} `yaml:"readinessProbe"`
|
||||
Tolerations []interface{} `yaml:"tolerations"`
|
||||
Affinity struct {
|
||||
} `yaml:"affinity"`
|
||||
PodSecurityContext struct {
|
||||
} `yaml:"podSecurityContext"`
|
||||
ContainerSecurityContext struct {
|
||||
} `yaml:"containerSecurityContext"`
|
||||
PodLabels struct {
|
||||
} `yaml:"podLabels"`
|
||||
NodeSelector struct {
|
||||
KubernetesIoOs string `yaml:"kubernetes.io/os"`
|
||||
} `yaml:"nodeSelector"`
|
||||
PodAnnotations struct {
|
||||
} `yaml:"podAnnotations"`
|
||||
ReplicaCount int `yaml:"replicaCount"`
|
||||
MinAvailable int `yaml:"minAvailable"`
|
||||
Resources struct {
|
||||
} `yaml:"resources"`
|
||||
ExtraVolumeMounts []interface{} `yaml:"extraVolumeMounts"`
|
||||
ExtraVolumes []interface{} `yaml:"extraVolumes"`
|
||||
Autoscaling struct {
|
||||
Annotations struct {
|
||||
} `yaml:"annotations"`
|
||||
Enabled bool `yaml:"enabled"`
|
||||
MinReplicas int `yaml:"minReplicas"`
|
||||
MaxReplicas int `yaml:"maxReplicas"`
|
||||
TargetCPUUtilizationPercentage int `yaml:"targetCPUUtilizationPercentage"`
|
||||
TargetMemoryUtilizationPercentage int `yaml:"targetMemoryUtilizationPercentage"`
|
||||
} `yaml:"autoscaling"`
|
||||
Service struct {
|
||||
Annotations struct {
|
||||
} `yaml:"annotations"`
|
||||
ExternalIPs []interface{} `yaml:"externalIPs"`
|
||||
LoadBalancerSourceRanges []interface{} `yaml:"loadBalancerSourceRanges"`
|
||||
ServicePort int `yaml:"servicePort"`
|
||||
Type string `yaml:"type"`
|
||||
} `yaml:"service"`
|
||||
PriorityClassName string `yaml:"priorityClassName"`
|
||||
Labels struct {
|
||||
} `yaml:"labels"`
|
||||
} `yaml:"defaultBackend"`
|
||||
Rbac struct {
|
||||
Create bool `yaml:"create"`
|
||||
Scope bool `yaml:"scope"`
|
||||
} `yaml:"rbac"`
|
||||
PodSecurityPolicy struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
} `yaml:"podSecurityPolicy"`
|
||||
ServiceAccount struct {
|
||||
Create bool `yaml:"create"`
|
||||
Name string `yaml:"name"`
|
||||
AutomountServiceAccountToken bool `yaml:"automountServiceAccountToken"`
|
||||
Annotations struct {
|
||||
} `yaml:"annotations"`
|
||||
} `yaml:"serviceAccount"`
|
||||
ImagePullSecrets []interface{} `yaml:"imagePullSecrets"`
|
||||
TCP struct {
|
||||
} `yaml:"tcp"`
|
||||
UDP struct {
|
||||
} `yaml:"udp"`
|
||||
PortNamePrefix string `yaml:"portNamePrefix"`
|
||||
DhParam interface{} `yaml:"dhParam"`
|
||||
}
|
29
magefiles/mage.go
Normal file
29
magefiles/mage.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
/*
|
||||
Copyright 2021 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 main
|
||||
|
||||
import (
|
||||
"github.com/magefile/mage/mage"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
os.Exit(mage.Main())
|
||||
}
|
545
magefiles/release.go
Normal file
545
magefiles/release.go
Normal file
|
@ -0,0 +1,545 @@
|
|||
//go:build mage
|
||||
|
||||
/*
|
||||
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 main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/google/go-github/v48/github"
|
||||
"github.com/magefile/mage/mg"
|
||||
"github.com/magefile/mage/sh"
|
||||
"golang.org/x/oauth2"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Release mg.Namespace
|
||||
|
||||
var INGRESS_ORG = "kubernetes" // the owner so we can test from forks
|
||||
var INGRESS_REPO = "ingress-nginx" // the repo to pull from
|
||||
var RELEASE_BRANCH = "main" //we only release from main
|
||||
var GITHUB_TOKEN string // the Google/gogithub lib needs an PAT to access the GitHub API
|
||||
var K8S_IO_ORG = "kubernetes" //the owner or organization for the k8s.io repo
|
||||
var K8S_IO_REPO = "k8s.io" //the repo that holds the images yaml for production promotion
|
||||
var INGRESS_REGISTRY = "registry.k8s.io" //Container registry for storage Ingress-nginx images
|
||||
var KUSTOMIZE_INSTALL_VERSION = "sigs.k8s.io/kustomize/kustomize/v4@v4.5.4" //static deploys needs kustomize to generate the template
|
||||
|
||||
// ingress-nginx releases start with a TAG then a cloudbuild, then a promotion through a PR, this the location of that PR
|
||||
var IMAGES_YAML = "https://raw.githubusercontent.com/kubernetes/k8s.io/main/k8s.gcr.io/images/k8s-staging-ingress-nginx/images.yaml"
|
||||
var ctx = context.Background() // Context used for GitHub Client
|
||||
|
||||
const INDEX_DOCS = "docs/deploy/index.md" //index.md has a version of the controller and needs to updated
|
||||
const CHANGELOG = "Changelog.md" //Name of the changelog
|
||||
|
||||
// ControllerImage - struct with info about controllers
|
||||
type ControllerImage struct {
|
||||
Tag string
|
||||
Digest string
|
||||
Registry string
|
||||
Name string
|
||||
}
|
||||
|
||||
// IngressRelease All the information about an ingress-nginx release that gets updated
|
||||
type IngressRelease struct {
|
||||
ControllerVersion string
|
||||
ControllerImage ControllerImage
|
||||
ReleaseNote ReleaseNote
|
||||
Release *github.RepositoryRelease
|
||||
}
|
||||
|
||||
// ReleaseNote - All the pieces of information/documents that get updated during a release
|
||||
type ReleaseNote struct {
|
||||
Version string
|
||||
NewControllerVersion string
|
||||
PreviousControllerVersion string
|
||||
ControllerImages []ControllerImage
|
||||
DepUpdates []string
|
||||
Updates []string
|
||||
HelmUpdates []string
|
||||
NewHelmChartVersion string
|
||||
PreviousHelmChartVersion string
|
||||
}
|
||||
|
||||
// IMAGES_YAML returns this data structure
|
||||
type ImageYamls []ImageElement
|
||||
|
||||
// ImageElement - a specific image and it's data structure the dmap is a list of shas and container versions
|
||||
type ImageElement struct {
|
||||
Name string `json:"name"`
|
||||
Dmap map[string][]string `json:"dmap"`
|
||||
}
|
||||
|
||||
// init will set the GitHub token from the committers/releasers env var
|
||||
func init() {
|
||||
GITHUB_TOKEN = os.Getenv("GITHUB_TOKEN")
|
||||
}
|
||||
|
||||
// PromoteImage Creates PR into the k8s.io repo for promotion of ingress from staging to production
|
||||
func (Release) PromoteImage(version, sha string) {
|
||||
|
||||
}
|
||||
|
||||
// Release Create a new release of ingress nginx controller
|
||||
func (Release) NewRelease(version string) {
|
||||
//newRelease := Release{}
|
||||
|
||||
//update ingress-nginx version
|
||||
//This is the step that kicks all the release process
|
||||
//it is already done, so it kicks off the gcloud build of the controller images
|
||||
//mg.Deps(mg.F(Tag.BumpNginx, version))
|
||||
|
||||
tag, err := getIngressNGINXVersion()
|
||||
CheckIfError(err, "RELEASE Retrieving the current Ingress Nginx Version")
|
||||
|
||||
Info("RELEASE Checking Current Version %s to New Version %s", tag, version)
|
||||
//if the version were upgrading does not match the TAG file, lets update the TAG file
|
||||
if tag[1:] != version {
|
||||
Warning("RELEASE Ingress Nginx TAG %s and new version %s do not match", tag, version)
|
||||
mg.Deps(mg.F(Tag.BumpNginx, fmt.Sprintf("v%s", version)))
|
||||
}
|
||||
|
||||
//update git controller tag controller-v$version
|
||||
mg.Deps(mg.F(Tag.NewControllerTag, version))
|
||||
|
||||
//make release notes
|
||||
releaseNotes, err := makeReleaseNotes(version)
|
||||
CheckIfError(err, "RELEASE Creating Release Notes for version %s", version)
|
||||
Info("RELEASE Release Notes %s completed", releaseNotes.Version)
|
||||
|
||||
//update chart values.yaml new controller tag and image digest
|
||||
releaseNotes.PreviousHelmChartVersion = currentChartVersion()
|
||||
|
||||
//controller tag
|
||||
updateChartValue("controller.image.tag", fmt.Sprintf("v%s", releaseNotes.Version))
|
||||
//controller digest
|
||||
if releaseNotes.ControllerImages[0].Name == "controller" {
|
||||
updateChartValue("controller.image.digest", releaseNotes.ControllerImages[0].Digest)
|
||||
}
|
||||
//controller chroot digest
|
||||
if releaseNotes.ControllerImages[1].Name == "controller-chroot" {
|
||||
updateChartValue("controller.image.digestChroot", releaseNotes.ControllerImages[1].Digest)
|
||||
}
|
||||
|
||||
//update helm chart app version
|
||||
mg.Deps(mg.F(Helm.UpdateVersion, version))
|
||||
|
||||
releaseNotes.NewHelmChartVersion = currentChartVersion()
|
||||
|
||||
//update helm chart release notes
|
||||
updateChartReleaseNotes(releaseNotes.HelmUpdates)
|
||||
|
||||
//Run helm docs update
|
||||
CheckIfError(runHelmDocs(), "Error Updating Helm Docs ")
|
||||
|
||||
releaseNotes.helmTemplate()
|
||||
|
||||
//update static manifest
|
||||
CheckIfError(updateStaticManifest(), "Error Updating Static manifests")
|
||||
|
||||
////update e2e docs
|
||||
updateE2EDocs()
|
||||
|
||||
//update documentation with ingress-nginx version
|
||||
CheckIfError(updateIndexMD(releaseNotes.PreviousControllerVersion, releaseNotes.NewControllerVersion), "Error Updating %s", INDEX_DOCS)
|
||||
|
||||
//keeping these manual for now
|
||||
//git commit TODO
|
||||
//make Pull Request TODO
|
||||
//make release TODO
|
||||
//mg.Deps(mg.F(Release.CreateRelease, version))
|
||||
}
|
||||
|
||||
// the index.md doc needs the controller version updated
|
||||
func updateIndexMD(old, new string) error {
|
||||
Info("Updating Deploy docs with new version")
|
||||
data, err := os.ReadFile(INDEX_DOCS)
|
||||
CheckIfError(err, "Could not read INDEX_DOCS file %s", INDEX_DOCS)
|
||||
datString := string(data)
|
||||
datString = strings.Replace(datString, old, new, -1)
|
||||
err = os.WriteFile(INDEX_DOCS, []byte(datString), 644)
|
||||
if err != nil {
|
||||
ErrorF("Could not write new %s %s", INDEX_DOCS, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// runs the hack/generate-deploy-scripts.sh
|
||||
func updateE2EDocs() {
|
||||
updates, err := sh.Output("./hack/generate-e2e-suite-doc.sh")
|
||||
CheckIfError(err, "Could not run update hack script")
|
||||
err = os.WriteFile("docs/e2e-tests.md", []byte(updates), 644)
|
||||
CheckIfError(err, "Could not write new e2e test file ")
|
||||
}
|
||||
|
||||
// The static deploy scripts use kustomize to generate them, this function ensures kustomize is installed
|
||||
func installKustomize() error {
|
||||
Info("Install Kustomize")
|
||||
var g0 = sh.RunCmd("go")
|
||||
// somewhere in your main code
|
||||
err := g0("install", KUSTOMIZE_INSTALL_VERSION)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateStaticManifest() error {
|
||||
CheckIfError(installKustomize(), "error installing kustomize")
|
||||
//hack/generate-deploy-scripts.sh
|
||||
err := sh.RunV("./hack/generate-deploy-scripts.sh")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//// CreateRelease Creates a new GitHub Release
|
||||
//func (Release) CreateRelease(name string) {
|
||||
// releaser, err := gh_release.NewReleaser(INGRESS_ORG, INGRESS_REPO, GITHUB_TOKEN)
|
||||
// CheckIfError(err, "GitHub Release Client error")
|
||||
// newRelease, err := releaser.Create(fmt.Sprintf("controller-%s", name))
|
||||
// CheckIfError(err, "Create release error")
|
||||
// Info("New Release: Tag %v, ID: %v", newRelease.TagName, newRelease.ID)
|
||||
//}
|
||||
|
||||
// Returns a GitHub client ready for use
|
||||
func githubClient() *github.Client {
|
||||
ts := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: GITHUB_TOKEN},
|
||||
)
|
||||
oauthClient := oauth2.NewClient(ctx, ts)
|
||||
return github.NewClient(oauthClient)
|
||||
}
|
||||
|
||||
// LatestCommitLogs Retrieves the commit log between the latest two controller versions.
|
||||
func (Release) LatestCommitLogs() {
|
||||
commitLog := commitsBetweenTags()
|
||||
for i, s := range commitLog {
|
||||
Info("#%v Version %v", i, s)
|
||||
}
|
||||
}
|
||||
|
||||
func commitsBetweenTags() []string {
|
||||
tags := getAllControllerTags()
|
||||
Info("Getting Commits between %v and %v", tags[0], tags[1])
|
||||
commitLog, err := git("log", "--full-history", "--pretty", "--oneline", fmt.Sprintf("%v..%v", tags[1], tags[0]))
|
||||
|
||||
if commitLog == "" {
|
||||
Warning("All Controller Tags is empty")
|
||||
}
|
||||
CheckIfError(err, "Retrieving Commit log")
|
||||
return strings.Split(commitLog, "\n")
|
||||
}
|
||||
|
||||
// Generate Release Notes
|
||||
func (Release) ReleaseNotes(newVersion string) error {
|
||||
notes, err := makeReleaseNotes(newVersion)
|
||||
CheckIfError(err, "Creating Release Notes for version %s", newVersion)
|
||||
Info("Release Notes %s completed", notes.Version)
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeReleaseNotes(newVersion string) (*ReleaseNote, error) {
|
||||
var newReleaseNotes = ReleaseNote{}
|
||||
|
||||
newReleaseNotes.Version = newVersion
|
||||
allControllerTags := getAllControllerTags()
|
||||
|
||||
//new version
|
||||
newReleaseNotes.NewControllerVersion = allControllerTags[0]
|
||||
newControllerVersion := fmt.Sprintf("controller-v%s", newVersion)
|
||||
|
||||
//the newControllerVersion should match the latest tag
|
||||
if newControllerVersion != allControllerTags[0] {
|
||||
return nil, errors.New(fmt.Sprintf("Generating release new version %s didnt match the current latest tag %s", newControllerVersion, allControllerTags[0]))
|
||||
}
|
||||
//previous version
|
||||
newReleaseNotes.PreviousControllerVersion = allControllerTags[1]
|
||||
|
||||
Info("New Version: %s Old Version: %s", newReleaseNotes.NewControllerVersion, newReleaseNotes.PreviousControllerVersion)
|
||||
|
||||
commits := commitsBetweenTags()
|
||||
|
||||
//dependency_updates
|
||||
//all_updates
|
||||
var allUpdates []string
|
||||
var depUpdates []string
|
||||
var helmUpdates []string
|
||||
prRegex := regexp.MustCompile("\\(#\\d+\\)")
|
||||
depBot := regexp.MustCompile("^(\\w){1,10} Bump ")
|
||||
helmRegex := regexp.MustCompile("helm|chart")
|
||||
for i, s := range commits {
|
||||
//matches on PR
|
||||
if prRegex.Match([]byte(s)) {
|
||||
//matches a dependant bot update
|
||||
if depBot.Match([]byte(s)) { //
|
||||
Debug("#%v DEPENDABOT %v", i, s)
|
||||
u := strings.SplitN(s, " ", 2)
|
||||
depUpdates = append(depUpdates, u[1])
|
||||
} else { // add it to the all updates slice
|
||||
Debug("#%v ALL UPDATES %v", i, s)
|
||||
u := strings.SplitN(s, " ", 2)
|
||||
allUpdates = append(allUpdates, u[1])
|
||||
|
||||
//helm chart updates
|
||||
if helmRegex.Match([]byte(s)) {
|
||||
u := strings.SplitN(s, " ", 2)
|
||||
helmUpdates = append(helmUpdates, u[1])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
helmUpdates = append(helmUpdates, fmt.Sprintf("Update Ingress-Nginx version %s", newReleaseNotes.NewControllerVersion))
|
||||
|
||||
newReleaseNotes.Updates = allUpdates
|
||||
newReleaseNotes.DepUpdates = depUpdates
|
||||
newReleaseNotes.HelmUpdates = helmUpdates
|
||||
|
||||
//controller_image_digests
|
||||
imagesYaml, err := downloadFile(IMAGES_YAML)
|
||||
if err != nil {
|
||||
ErrorF("Could not download file %s : %s", IMAGES_YAML, err)
|
||||
return nil, err
|
||||
}
|
||||
Debug("%s", imagesYaml)
|
||||
|
||||
data := ImageYamls{}
|
||||
|
||||
err = yaml.Unmarshal([]byte(imagesYaml), &data)
|
||||
if err != nil {
|
||||
ErrorF("Could not unmarshal images yaml %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//controller
|
||||
controllerDigest := findImageDigest(data, "controller", newVersion)
|
||||
if len(controllerDigest) == 0 {
|
||||
ErrorF("Controller Digest could not be found")
|
||||
return nil, errors.New("Controller digest could not be found")
|
||||
}
|
||||
|
||||
controllerChrootDigest := findImageDigest(data, "controller-chroot", newVersion)
|
||||
if len(controllerChrootDigest) == 0 {
|
||||
ErrorF("Controller Chroot Digest could not be found")
|
||||
return nil, errors.New("Controller Chroot digest could not be found")
|
||||
}
|
||||
|
||||
Debug("Latest Controller Digest %v", controllerDigest)
|
||||
Debug("Latest Controller Chroot Digest %v", controllerChrootDigest)
|
||||
c1 := ControllerImage{
|
||||
Digest: controllerDigest,
|
||||
Registry: INGRESS_REGISTRY,
|
||||
Name: "controller",
|
||||
Tag: newReleaseNotes.NewControllerVersion,
|
||||
}
|
||||
c2 := ControllerImage{
|
||||
Digest: controllerChrootDigest,
|
||||
Registry: INGRESS_REGISTRY,
|
||||
Name: "controller-chroot",
|
||||
Tag: newReleaseNotes.NewControllerVersion,
|
||||
}
|
||||
newReleaseNotes.ControllerImages = append(newReleaseNotes.ControllerImages, c1)
|
||||
newReleaseNotes.ControllerImages = append(newReleaseNotes.ControllerImages, c2)
|
||||
Debug("New Release Controller Images %s %s", newReleaseNotes.ControllerImages[0].Digest, newReleaseNotes.ControllerImages[1].Digest)
|
||||
|
||||
if DEBUG {
|
||||
newReleaseNotes.printRelease()
|
||||
}
|
||||
|
||||
//write it all out to the changelog file
|
||||
newReleaseNotes.template()
|
||||
|
||||
return &newReleaseNotes, nil
|
||||
}
|
||||
|
||||
func (i ControllerImage) print() string {
|
||||
return fmt.Sprintf("%s/%s:%s@%s", i.Registry, i.Name, i.Tag, i.Digest)
|
||||
}
|
||||
|
||||
func (r ReleaseNote) template() {
|
||||
// Files are provided as a slice of strings.
|
||||
changelogTemplate, err := os.ReadFile("Changelog.md.gotmpl")
|
||||
if err != nil {
|
||||
ErrorF("Could not read changelog template file %s", err)
|
||||
}
|
||||
Debug("ChangeLog Templates %s", string(changelogTemplate))
|
||||
t := template.Must(template.New("changelog").Parse(string(changelogTemplate)))
|
||||
// create a new file
|
||||
file, err := os.Create(fmt.Sprintf("changelog/Changelog-%s.md", r.Version))
|
||||
if err != nil {
|
||||
ErrorF("Could not create changelog file %s", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
err = t.Execute(file, r)
|
||||
if err != nil {
|
||||
ErrorF("executing template:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (r ReleaseNote) helmTemplate() {
|
||||
// Files are provided as a slice of strings.
|
||||
changelogTemplate, err := os.ReadFile("charts/ingress-nginx/changelog.md.gotmpl")
|
||||
if err != nil {
|
||||
ErrorF("Could not read changelog template file %s", err)
|
||||
}
|
||||
Debug("ChangeLog Templates %s", string(changelogTemplate))
|
||||
t := template.Must(template.New("changelog").Parse(string(changelogTemplate)))
|
||||
// create a new file
|
||||
file, err := os.Create(fmt.Sprintf("charts/ingress-nginx/changelog/Changelog-%s.md", r.Version))
|
||||
if err != nil {
|
||||
ErrorF("Could not create changelog file %s", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
err = t.Execute(file, r)
|
||||
if err != nil {
|
||||
ErrorF("executing template:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (r ReleaseNote) printRelease() {
|
||||
Info("Release Version: %v", r.NewControllerVersion)
|
||||
Info("Previous Version: %v", r.PreviousControllerVersion)
|
||||
Info("Controller Image: %v", r.ControllerImages[0].print())
|
||||
Info("Controller Chroot Image: %v", r.ControllerImages[1].print())
|
||||
for i := range r.Updates {
|
||||
Info("Update #%v - %v", i, r.Updates[i])
|
||||
}
|
||||
for j := range r.DepUpdates {
|
||||
Info("Dependabot Update #%v - %v", j, r.DepUpdates[j])
|
||||
}
|
||||
}
|
||||
|
||||
func findImageDigest(yaml ImageYamls, image, version string) string {
|
||||
version = fmt.Sprintf("v%s", version)
|
||||
Info("Searching Digest for %s:%s", image, version)
|
||||
for i := range yaml {
|
||||
if yaml[i].Name == image {
|
||||
for k, v := range yaml[i].Dmap {
|
||||
if v[0] == version {
|
||||
return k
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func downloadFile(url string) (string, error) {
|
||||
client := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 5 * time.Second,
|
||||
KeepAlive: 5 * time.Second,
|
||||
}).DialContext,
|
||||
TLSHandshakeTimeout: 5 * time.Second,
|
||||
ResponseHeaderTimeout: 5 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
MaxIdleConnsPerHost: -1,
|
||||
},
|
||||
}
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", errors.New(fmt.Sprintf("Could not retrieve file, response from server %s for file %s", resp.StatusCode, url))
|
||||
}
|
||||
bodyBytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
return string(bodyBytes), nil
|
||||
}
|
||||
|
||||
// Latest returns latest Github Release
|
||||
func (Release) Latest() error {
|
||||
r, _, err := latestRelease()
|
||||
if err != nil {
|
||||
ErrorF("Latest Release error %s", err)
|
||||
return err
|
||||
}
|
||||
Info("Latest Release %v", r.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Release) ReleaseByTag(tag string) error {
|
||||
r, _, err := releaseByTag(tag)
|
||||
if err != nil {
|
||||
ErrorF("Release retrieve tag error %s", tag, err)
|
||||
return err
|
||||
}
|
||||
|
||||
Info("Latest Release %v", r.String())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func releaseByTag(tag string) (*github.RepositoryRelease, *github.Response, error) {
|
||||
ghClient := githubClient()
|
||||
return ghClient.Repositories.GetReleaseByTag(ctx, INGRESS_ORG, INGRESS_REPO, tag)
|
||||
}
|
||||
|
||||
func latestRelease() (*github.RepositoryRelease, *github.Response, error) {
|
||||
ghClient := githubClient()
|
||||
return ghClient.Repositories.GetLatestRelease(ctx, INGRESS_ORG, INGRESS_REPO)
|
||||
}
|
||||
|
||||
// Copy Test function to copy a release
|
||||
func (Release) Copy() error {
|
||||
ghClient := githubClient()
|
||||
kRelease, _, err := ghClient.Repositories.GetLatestRelease(ctx, "kubernetes", "ingress-nginx")
|
||||
if err != nil {
|
||||
ErrorF("Get Release from kubernetes %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
sRelease := &github.RepositoryRelease{
|
||||
TagName: kRelease.TagName,
|
||||
Name: kRelease.Name,
|
||||
Body: kRelease.Body,
|
||||
Draft: kRelease.Draft,
|
||||
Prerelease: kRelease.GenerateReleaseNotes,
|
||||
DiscussionCategoryName: kRelease.DiscussionCategoryName,
|
||||
GenerateReleaseNotes: kRelease.GenerateReleaseNotes,
|
||||
}
|
||||
|
||||
sRelease, _, err = ghClient.Repositories.CreateRelease(ctx, "strongjz", "ingress-nginx", sRelease)
|
||||
if err != nil {
|
||||
ErrorF("Creating Strongjz release %s", err)
|
||||
return err
|
||||
}
|
||||
Info("Copied over Kubernetes Release %v to Strongjz %v", &kRelease.Name, &sRelease.Name)
|
||||
return nil
|
||||
}
|
146
magefiles/tags.go
Normal file
146
magefiles/tags.go
Normal file
|
@ -0,0 +1,146 @@
|
|||
//go:build mage
|
||||
|
||||
/*
|
||||
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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
semver "github.com/blang/semver/v4"
|
||||
"github.com/magefile/mage/mg"
|
||||
"github.com/magefile/mage/sh"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Tag mg.Namespace
|
||||
|
||||
var git = sh.OutCmd("git")
|
||||
|
||||
// Nginx returns the ingress-nginx current version
|
||||
func (Tag) Nginx() {
|
||||
tag, err := getIngressNGINXVersion()
|
||||
CheckIfError(err, "")
|
||||
fmt.Printf("%v", tag)
|
||||
}
|
||||
|
||||
func getIngressNGINXVersion() (string, error) {
|
||||
dat, err := os.ReadFile("TAG")
|
||||
CheckIfError(err, "Could not read TAG file")
|
||||
datString := string(dat)
|
||||
//remove newline
|
||||
datString = strings.Replace(datString, "\n", "", -1)
|
||||
return datString, nil
|
||||
}
|
||||
|
||||
func checkSemVer(currentVersion, newVersion string) bool {
|
||||
Info("Checking Sem Ver between current %s and new %s", currentVersion, newVersion)
|
||||
cVersion, err := semver.Make(currentVersion[1:])
|
||||
if err != nil {
|
||||
ErrorF("TAG Error Current Tag %v Making Semver : %v", currentVersion[1:], err)
|
||||
return false
|
||||
}
|
||||
nVersion, err := semver.Make(newVersion)
|
||||
if err != nil {
|
||||
ErrorF("TAG %v Error Making Semver %v \n", newVersion, err)
|
||||
return false
|
||||
}
|
||||
|
||||
err = nVersion.Validate()
|
||||
if err != nil {
|
||||
ErrorF("TAG %v not a valid Semver %v \n", newVersion, err)
|
||||
return false
|
||||
}
|
||||
|
||||
//The result will be
|
||||
//0 if newVersion == currentVersion
|
||||
//-1 if newVersion < currentVersion
|
||||
//+1 if newVersion > currentVersion.
|
||||
Info("TAG Comparing Old %s to New %s", cVersion.String(), nVersion.String())
|
||||
comp := nVersion.Compare(cVersion)
|
||||
if comp <= 0 {
|
||||
Warning("SemVer:%v is not an update\n", newVersion)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// BumpNginx will update the nginx TAG
|
||||
func (Tag) BumpNginx(newTag string) {
|
||||
Info("TAG BumpNginx version %v", newTag)
|
||||
currentTag, err := getIngressNGINXVersion()
|
||||
CheckIfError(err, "Getting Ingress-nginx Version")
|
||||
bump(currentTag, newTag)
|
||||
}
|
||||
|
||||
func bump(currentTag, newTag string) {
|
||||
//check if semver is valid
|
||||
if !checkSemVer(currentTag, newTag) {
|
||||
ErrorF("ERROR: Semver is not valid %v", newTag)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
Info("Updating Tag %v to %v", currentTag, newTag)
|
||||
err := os.WriteFile("TAG", []byte(newTag), 0666)
|
||||
CheckIfError(err, "Error Writing New Tag File")
|
||||
}
|
||||
|
||||
// Git Returns the latest git tag
|
||||
func (Tag) Git() {
|
||||
tag, err := getGitTag()
|
||||
CheckIfError(err, "Retrieving Git Tag")
|
||||
Info("Git tag: %v", tag)
|
||||
}
|
||||
|
||||
func getGitTag() (string, error) {
|
||||
return git("describe", "--tags", "--match", "controller-v*", "--abbrev=0")
|
||||
}
|
||||
|
||||
// ControllerTag Creates a new Git Tag for the ingress controller
|
||||
func (Tag) NewControllerTag(version string) {
|
||||
Info("Create Ingress Nginx Controller Tag v%s", version)
|
||||
tag, err := controllerTag(version)
|
||||
CheckIfError(err, "Creating git tag")
|
||||
Debug("Git Tag: %s", tag)
|
||||
}
|
||||
|
||||
func controllerTag(version string) (string, error) {
|
||||
return git("tag", "-a", "-m", fmt.Sprintf("-m \"Automated Controller release %v\"", version), fmt.Sprintf("controller-v%s", version))
|
||||
}
|
||||
|
||||
func (Tag) AllControllerTags() {
|
||||
tags := getAllControllerTags()
|
||||
for i, s := range tags {
|
||||
Info("#%v Version %v", i, s)
|
||||
}
|
||||
}
|
||||
|
||||
func getAllControllerTags() []string {
|
||||
allControllerTags, err := git("tag", "-l", "--sort=-v:refname", "controller-v*")
|
||||
CheckIfError(err, "Retrieving git tags")
|
||||
if !sh.CmdRan(err) {
|
||||
Warning("Issue Running Command")
|
||||
}
|
||||
if allControllerTags == "" {
|
||||
Warning("All Controller Tags is empty")
|
||||
}
|
||||
Debug("Controller Tags: %v", allControllerTags)
|
||||
|
||||
temp := strings.Split(allControllerTags, "\n")
|
||||
Debug("There are %v controller tags", len(temp))
|
||||
return temp
|
||||
}
|
19
magefiles/yaml.go
Normal file
19
magefiles/yaml.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
//go:build mage
|
||||
|
||||
/*
|
||||
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 main
|
|
@ -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,
|
||||
|
|
|
@ -59,11 +59,12 @@ func (p *TCPProxy) Get(host string) *TCPServer {
|
|||
// and open a connection to the passthrough server.
|
||||
func (p *TCPProxy) Handle(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
data := make([]byte, 4096)
|
||||
// See: https://www.ibm.com/docs/en/ztpf/1.1.0.15?topic=sessions-ssl-record-format
|
||||
data := make([]byte, 16384)
|
||||
|
||||
length, err := conn.Read(data)
|
||||
if err != nil {
|
||||
klog.V(4).ErrorS(err, "Error reading the first 4k of the connection")
|
||||
klog.V(4).ErrorS(err, "Error reading data from the connection")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -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,68 @@ 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, enablePathTypeValidation bool, pathAdditionalAllowedChars string) error {
|
||||
|
||||
if copyIng == nil {
|
||||
return nil
|
||||
}
|
||||
return pathAlphaNumeric(path)
|
||||
|
||||
escapedPathAdditionalAllowedChars := regexp.QuoteMeta(pathAdditionalAllowedChars)
|
||||
regexPath, err := regexp.Compile("^[" + alphaNumericChars + escapedPathAdditionalAllowedChars + "]*$")
|
||||
if err != nil {
|
||||
return fmt.Errorf("ingress has misconfigured validation regex on configmap: %s - %w", pathAdditionalAllowedChars, err)
|
||||
}
|
||||
|
||||
for _, rule := range copyIng.Spec.Rules {
|
||||
|
||||
if rule.HTTP == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := checkPath(rule.HTTP.Paths, enablePathTypeValidation, regexPath); err != nil {
|
||||
return fmt.Errorf("error validating ingressPath: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkPath(paths []networkingv1.HTTPIngressPath, enablePathTypeValidation bool, regexSpecificChars *regexp.Regexp) error {
|
||||
|
||||
for _, path := range paths {
|
||||
if path.PathType == nil {
|
||||
path.PathType = &defaultPathType
|
||||
}
|
||||
|
||||
klog.V(9).InfoS("PathType Validation", "enablePathTypeValidation", enablePathTypeValidation, "regexSpecificChars", regexSpecificChars.String(), "Path", path.Path)
|
||||
|
||||
switch pathType := *path.PathType; pathType {
|
||||
case networkingv1.PathTypeImplementationSpecific:
|
||||
if enablePathTypeValidation {
|
||||
//only match on regex chars per Ingress spec when path is implementation specific
|
||||
if !regexSpecificChars.MatchString(path.Path) {
|
||||
return fmt.Errorf("path %s of type %s contains invalid characters", path.Path, *path.PathType)
|
||||
}
|
||||
}
|
||||
|
||||
case networkingv1.PathTypeExact, networkingv1.PathTypePrefix:
|
||||
//enforce path type validation
|
||||
if enablePathTypeValidation {
|
||||
//only allow alphanumeric chars, no regex chars
|
||||
if !pathAlphaNumericRegex(path.Path) {
|
||||
return fmt.Errorf("path %s of type %s contains invalid characters", path.Path, *path.PathType)
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
//path validation is disabled, so we check what regex chars are allowed by user
|
||||
if !regexSpecificChars.MatchString(path.Path) {
|
||||
return fmt.Errorf("path %s of type %s contains invalid characters", path.Path, *path.PathType)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unknown path type %v on path %v", *path.PathType, path.Path)
|
||||
}
|
||||
}
|
||||
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,172 @@ 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
|
||||
EnablePathTypeValidation 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: "()",
|
||||
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,
|
||||
EnablePathTypeValidation: false,
|
||||
copyIng: generateDumbIngressforPathTest(&pathTypeImplSpecific, "/foo/bar/(.+)"),
|
||||
},
|
||||
{
|
||||
name: "should accept path with regex characters and pathType exact, but pathType validation disabled",
|
||||
wantErr: false,
|
||||
additionalChars: defaultAdditionalChars,
|
||||
EnablePathTypeValidation: false,
|
||||
copyIng: generateDumbIngressforPathTest(&pathTypeExact, "/foo/bar/(.+)"),
|
||||
},
|
||||
{
|
||||
name: "should reject path when the allowed additional set does not match",
|
||||
wantErr: true,
|
||||
additionalChars: "().?",
|
||||
EnablePathTypeValidation: true,
|
||||
copyIng: generateDumbIngressforPathTest(&pathTypeImplSpecific, "/foo/bar/(.+)"),
|
||||
},
|
||||
{
|
||||
name: "should accept path when the allowed additional set does match",
|
||||
wantErr: false,
|
||||
additionalChars: "().?",
|
||||
EnablePathTypeValidation: false,
|
||||
copyIng: generateDumbIngressforPathTest(&pathTypeImplSpecific, "/foo/bar/(.?)"),
|
||||
},
|
||||
{
|
||||
name: "should block if at least one path is bad",
|
||||
wantErr: true,
|
||||
EnablePathTypeValidation: false,
|
||||
copyIng: generateComplexIngress(generateDumbIngressforPathTest(&pathTypeExact, "/foo/bar/(.?)")),
|
||||
},
|
||||
{
|
||||
name: "should block if at least one path is bad",
|
||||
wantErr: true,
|
||||
EnablePathTypeValidation: 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.EnablePathTypeValidation, tt.additionalChars); (err != nil) != tt.wantErr {
|
||||
t.Errorf("ValidateIngressPath() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -345,6 +345,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 }};
|
||||
|
@ -1194,6 +1197,10 @@ stream {
|
|||
|
||||
add_header Set-Cookie $auth_cookie;
|
||||
|
||||
{{ if $location.CorsConfig.CorsEnabled }}
|
||||
{{ template "CORS" $location }}
|
||||
{{ end }}
|
||||
|
||||
# Ensure that modsecurity will not run on an internal location as this is not accessible from outside
|
||||
{{ if $all.Cfg.EnableModsecurity }}
|
||||
modsecurity off;
|
||||
|
|
|
@ -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,7 +160,35 @@ 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 return an error if there is a forbidden value in some annotation", func() {
|
||||
ginkgo.It("ADMISSION should not validate characters on ingress when validation of pathType is disabled", func() {
|
||||
host := "admission-test"
|
||||
|
||||
f.UpdateNginxConfigMapData("enable-pathtype-validation", "false")
|
||||
|
||||
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("ADMISSION should reject ingress with bad characters and pathType != ImplementationSpecific", func() {
|
||||
host := "admission-test"
|
||||
|
||||
f.UpdateNginxConfigMapData("enable-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.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("ADMISSION should return an error if there is a forbidden value in some annotation", func() {
|
||||
host := "admission-test"
|
||||
|
||||
annotations := map[string]string{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -720,6 +720,51 @@ http {
|
|||
})
|
||||
})
|
||||
|
||||
ginkgo.Context("when external authentication is configured along with CORS enabled", func() {
|
||||
host := "auth"
|
||||
var annotations map[string]string
|
||||
var ing *networking.Ingress
|
||||
|
||||
ginkgo.BeforeEach(func() {
|
||||
f.NewHttpbinDeployment()
|
||||
|
||||
var httpbinIP string
|
||||
|
||||
err := framework.WaitForEndpoints(f.KubeClientSet, framework.DefaultTimeout, framework.HTTPBinService, f.Namespace, 1)
|
||||
assert.Nil(ginkgo.GinkgoT(), err)
|
||||
|
||||
e, err := f.KubeClientSet.CoreV1().Endpoints(f.Namespace).Get(context.TODO(), framework.HTTPBinService, metav1.GetOptions{})
|
||||
assert.Nil(ginkgo.GinkgoT(), err)
|
||||
|
||||
httpbinIP = e.Subsets[0].Addresses[0].IP
|
||||
|
||||
annotations = map[string]string{
|
||||
"nginx.ingress.kubernetes.io/auth-url": fmt.Sprintf("http://%s/basic-auth/user/password", httpbinIP),
|
||||
"nginx.ingress.kubernetes.io/auth-signin": "http://$host/auth/start",
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
}
|
||||
|
||||
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, "server_name auth")
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.It("should redirect to signin url when not signed in along With CORS headers in response", func() {
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithQuery("a", "b").
|
||||
WithQuery("c", "d").
|
||||
Expect().
|
||||
Status(http.StatusFound).
|
||||
Header("Access-Control-Allow-Origin").Equal(fmt.Sprintf("*"))
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.Context("when external authentication with caching is configured", func() {
|
||||
thisHost := "auth"
|
||||
thatHost := "different"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -14,10 +14,16 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
if ! [ -z "$DEBUG" ]; then
|
||||
if [ -n "$DEBUG" ]; then
|
||||
set -x
|
||||
else
|
||||
trap cleanup EXIT
|
||||
fi
|
||||
|
||||
function cleanup {
|
||||
kubectl delete pod e2e 2>/dev/null || true
|
||||
}
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
@ -43,16 +49,11 @@ if [ "$missing" = true ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
function cleanup {
|
||||
kubectl delete pod e2e 2>/dev/null || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
E2E_CHECK_LEAKS=${E2E_CHECK_LEAKS:-}
|
||||
FOCUS=${FOCUS:-.*}
|
||||
|
||||
BASEDIR=$(dirname "$0")
|
||||
NGINX_BASE_IMAGE=$(cat $BASEDIR/../NGINX_BASE)
|
||||
NGINX_BASE_IMAGE=$(cat $BASEDIR/../../NGINX_BASE)
|
||||
|
||||
export E2E_CHECK_LEAKS
|
||||
export FOCUS
|
|
@ -14,13 +14,6 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
KIND_LOG_LEVEL="1"
|
||||
|
||||
if ! [ -z $DEBUG ]; then
|
||||
set -x
|
||||
KIND_LOG_LEVEL="6"
|
||||
fi
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
@ -31,45 +24,56 @@ cleanup() {
|
|||
fi
|
||||
|
||||
kind delete cluster \
|
||||
--verbosity=${KIND_LOG_LEVEL} \
|
||||
--name ${KIND_CLUSTER_NAME}
|
||||
--verbosity="${KIND_LOG_LEVEL}" \
|
||||
--name "${KIND_CLUSTER_NAME}"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
DEBUG=${DEBUG:=false}
|
||||
|
||||
if [ "${DEBUG}" = "true" ]; then
|
||||
set -x
|
||||
KIND_LOG_LEVEL="6"
|
||||
else
|
||||
trap cleanup EXIT
|
||||
fi
|
||||
|
||||
KIND_LOG_LEVEL="1"
|
||||
IS_CHROOT="${IS_CHROOT:-false}"
|
||||
export KIND_CLUSTER_NAME=${KIND_CLUSTER_NAME:-ingress-nginx-dev}
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
# Use 1.0.0-dev to make sure we use the latest configuration in the helm template
|
||||
export TAG=1.0.0-dev
|
||||
export ARCH=${ARCH:-amd64}
|
||||
export REGISTRY=ingress-controller
|
||||
NGINX_BASE_IMAGE=$(cat "$DIR"/../../NGINX_BASE)
|
||||
export NGINX_BASE_IMAGE=$NGINX_BASE_IMAGE
|
||||
export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
export KUBECONFIG="${KUBECONFIG:-$HOME/.kube/kind-config-$KIND_CLUSTER_NAME}"
|
||||
SKIP_INGRESS_IMAGE_CREATION="${SKIP_INGRESS_IMAGE_CREATION:-false}"
|
||||
SKIP_E2E_IMAGE_CREATION="${SKIP_E2E_IMAGE_CREATION:=false}"
|
||||
SKIP_CLUSTER_CREATION="${SKIP_CLUSTER_CREATION:-false}"
|
||||
|
||||
if ! command -v kind --version &> /dev/null; then
|
||||
echo "kind is not installed. Use the package manager or visit the official site https://kind.sigs.k8s.io/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
# Use 1.0.0-dev to make sure we use the latest configuration in the helm template
|
||||
export TAG=1.0.0-dev
|
||||
export ARCH=${ARCH:-amd64}
|
||||
export REGISTRY=ingress-controller
|
||||
|
||||
NGINX_BASE_IMAGE=$(cat $DIR/../../NGINX_BASE)
|
||||
|
||||
echo "Running e2e with nginx base image ${NGINX_BASE_IMAGE}"
|
||||
|
||||
export NGINX_BASE_IMAGE=$NGINX_BASE_IMAGE
|
||||
|
||||
export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
|
||||
export KUBECONFIG="${KUBECONFIG:-$HOME/.kube/kind-config-$KIND_CLUSTER_NAME}"
|
||||
|
||||
if [ "${SKIP_CLUSTER_CREATION:-false}" = "false" ]; then
|
||||
if [ "${SKIP_CLUSTER_CREATION}" = "false" ]; then
|
||||
echo "[dev-env] creating Kubernetes cluster with kind"
|
||||
|
||||
export K8S_VERSION=${K8S_VERSION:-v1.25.2@sha256:9be91e9e9cdf116809841fc77ebdb8845443c4c72fe5218f3ae9eb57fdb4bace}
|
||||
|
||||
# delete the cluster if it exists
|
||||
if kind get clusters | grep "${KIND_CLUSTER_NAME}"; then
|
||||
kind delete cluster --name "${KIND_CLUSTER_NAME}"
|
||||
fi
|
||||
|
||||
kind create cluster \
|
||||
--verbosity=${KIND_LOG_LEVEL} \
|
||||
--name ${KIND_CLUSTER_NAME} \
|
||||
--config ${DIR}/kind.yaml \
|
||||
--verbosity="${KIND_LOG_LEVEL}" \
|
||||
--name "${KIND_CLUSTER_NAME}" \
|
||||
--config "${DIR}"/kind.yaml \
|
||||
--retain \
|
||||
--image "kindest/node:${K8S_VERSION}"
|
||||
|
||||
|
@ -77,16 +81,26 @@ if [ "${SKIP_CLUSTER_CREATION:-false}" = "false" ]; then
|
|||
kubectl get nodes -o wide
|
||||
fi
|
||||
|
||||
if [ "${SKIP_IMAGE_CREATION:-false}" = "false" ]; then
|
||||
if [ "${SKIP_INGRESS_IMAGE_CREATION}" = "false" ]; then
|
||||
echo "[dev-env] building image"
|
||||
if [ "${IS_CHROOT}" = "true" ]; then
|
||||
make -C "${DIR}"/../../ clean-image build image-chroot
|
||||
docker tag ${REGISTRY}/controller-chroot:${TAG} ${REGISTRY}/controller:${TAG}
|
||||
else
|
||||
make -C "${DIR}"/../../ clean-image build image
|
||||
fi
|
||||
|
||||
echo "[dev-env] .. done building controller images"
|
||||
fi
|
||||
|
||||
if [ "${SKIP_E2E_IMAGE_CREATION}" = "false" ]; then
|
||||
if ! command -v ginkgo &> /dev/null; then
|
||||
go get github.com/onsi/ginkgo/v2/ginkgo@v2.6.1
|
||||
fi
|
||||
|
||||
echo "[dev-env] building image"
|
||||
make -C ${DIR}/../../ clean-image build image image-chroot
|
||||
echo "[dev-env] .. done building controller images"
|
||||
echo "[dev-env] now building e2e-image.."
|
||||
make -C ${DIR}/../e2e-image image
|
||||
make -C "${DIR}"/../e2e-image image
|
||||
echo "[dev-env] ..done building e2e-image"
|
||||
fi
|
||||
|
||||
|
@ -95,13 +109,7 @@ KIND_WORKERS=$(kind get nodes --name="${KIND_CLUSTER_NAME}" | grep worker | awk
|
|||
|
||||
echo "[dev-env] copying docker images to cluster..."
|
||||
|
||||
kind load docker-image --name="${KIND_CLUSTER_NAME}" --nodes=${KIND_WORKERS} nginx-ingress-controller:e2e
|
||||
|
||||
if [ "${IS_CHROOT:-false}" = "true" ]; then
|
||||
docker tag ${REGISTRY}/controller-chroot:${TAG} ${REGISTRY}/controller:${TAG}
|
||||
fi
|
||||
|
||||
kind load docker-image --name="${KIND_CLUSTER_NAME}" --nodes=${KIND_WORKERS} ${REGISTRY}/controller:${TAG}
|
||||
|
||||
kind load docker-image --name="${KIND_CLUSTER_NAME}" --nodes="${KIND_WORKERS}" nginx-ingress-controller:e2e
|
||||
kind load docker-image --name="${KIND_CLUSTER_NAME}" --nodes="${KIND_WORKERS}" "${REGISTRY}"/controller:"${TAG}"
|
||||
echo "[dev-env] running e2e tests..."
|
||||
make -C ${DIR}/../../ e2e-test
|
||||
make -C "${DIR}"/../../ e2e-test
|
|
@ -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