Skip to content

Commit

Permalink
Support IngressClassName in TransportServer
Browse files Browse the repository at this point in the history
Co-authored-by: Luca Comellini <[email protected]>
  • Loading branch information
pleshakov and lucacome authored Mar 5, 2021
1 parent f7c6433 commit da5df32
Show file tree
Hide file tree
Showing 15 changed files with 171 additions and 100 deletions.
7 changes: 4 additions & 3 deletions cmd/nginx-ingress/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,13 @@ var (
the Ingress Controller will fail to start.
The Ingress controller only processes resources that belong to its class - i.e. have the "ingressClassName" field resource equal to the class.
For Kubernetes < 1.18, the Ingress Controller only processes resources that belong to its class
- i.e have the annotation "kubernetes.io/ingress.class" equal to the class.
For Kubernetes < 1.18, the Ingress Controller only processes resources that belong to its class -
i.e have the annotation "kubernetes.io/ingress.class" (for Ingress resources)
or field "ingressClassName" (for VirtualServer/VirtualServerRoute/TransportServer resources) equal to the class.
Additionally, the Ingress Controller processes resources that do not have the class set,
which can be disabled by setting the "-use-ingress-class-only" flag
The Ingress Controller processes all the VirtualServer/VirtualServerRoute resources that do not have the "ingressClassName" field for all versions of kubernetes.`)
The Ingress Controller processes all the VirtualServer/VirtualServerRoute/TransportServer resources that do not have the "ingressClassName" field for all versions of kubernetes.`)

useIngressClassOnly = flag.Bool("use-ingress-class-only", false,
`For kubernetes versions >= 1.18 this flag will be IGNORED.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ spec:
type: string
host:
type: string
ingressClassName:
type: string
listener:
description: TransportServerListener defines a listener for a TransportServer.
type: object
Expand Down
2 changes: 2 additions & 0 deletions deployments/common/crds/k8s.nginx.org_transportservers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ spec:
type: string
host:
type: string
ingressClassName:
type: string
listener:
description: TransportServerListener defines a listener for a TransportServer.
type: object
Expand Down
2 changes: 1 addition & 1 deletion deployments/helm-chart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ Parameter | Description | Default
`controller.volumeMounts` | The volumeMounts of the Ingress controller pods. | []
`controller.resources` | The resources of the Ingress controller pods. | {}
`controller.replicaCount` | The number of replicas of the Ingress controller deployment. | 1
`controller.ingressClass` | A class of the Ingress controller. For Kubernetes >= 1.18, the Ingress controller only processes resources that belong to its class - i.e. have the "ingressClassName" field resource equal to the class. Additionally the Ingress Controller processes all the VirtualServer/VirtualServerRoute resources that do not have the "ingressClassName" field. For Kubernetes < 1.18, the Ingress Controller only processes resources that belong to its class - i.e have the annotation "kubernetes.io/ingress.class" (for Ingress resources) or field "ingressClassName" (for VirtualServer/VirtualServerRoute resources) equal to the class. Additionally, the Ingress Controller processes resources that do not have the class set, which can be disabled by setting the "-use-ingress-class-only" flag. | nginx
`controller.ingressClass` | A class of the Ingress controller. For Kubernetes >= 1.18, a corresponding IngressClass resource with the name equal to the class must be deployed. Otherwise, the Ingress Controller will fail to start. The Ingress controller only processes resources that belong to its class - i.e. have the "ingressClassName" field resource equal to the class. For Kubernetes < 1.18, the Ingress Controller only processes resources that belong to its class - i.e have the annotation "kubernetes.io/ingress.class" (for Ingress resources) or field "ingressClassName" (for VirtualServer/VirtualServerRoute/TransportServer resources) equal to the class. Additionally, the Ingress Controller processes resources that do not have the class set, which can be disabled by setting the `controller.useIngressClassOnly` parameter to `true`. The Ingress Controller processes all the VirtualServer/VirtualServerRoute/TransportServer resources that do not have the "ingressClassName" field for all versions of kubernetes. | nginx
`controller.useIngressClassOnly` | Ignore Ingress resources without the `"kubernetes.io/ingress.class"` annotation. For kubernetes versions >= 1.18 this flag will be IGNORED. | false
`controller.setAsDefaultIngress` | New Ingresses without an `"ingressClassName"` field specified will be assigned the class specified in `controller.ingressClass`. Only for kubernetes versions >= 1.18. | false
`controller.watchNamespace` | Namespace to watch for Ingress resources. By default the Ingress controller watches all namespaces. | ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ spec:
type: string
host:
type: string
ingressClassName:
type: string
listener:
description: TransportServerListener defines a listener for a TransportServer.
type: object
Expand Down
10 changes: 6 additions & 4 deletions deployments/helm-chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,13 @@ controller:
## the Ingress Controller will fail to start.
## The Ingress controller only processes resources that belong to its class - i.e. have the "ingressClassName" field resource equal to the class.

## For Kubernetes < 1.18, the Ingress Controller only processes resources that belong to its class
## - i.e have the annotation "kubernetes.io/ingress.class" equal to the class.
## Additionally, the Ingress Controller processes resources that do not have the class set, which can be disabled by setting the "-use-ingress-class-only" flag
## For Kubernetes < 1.18, the Ingress Controller only processes resources that belong to its class -
## i.e have the annotation "kubernetes.io/ingress.class" (for Ingress resources)
## or field "ingressClassName" (for VirtualServer/VirtualServerRoute/TransportServer resources) equal to the class.
## Additionally, the Ingress Controller processes resources that do not have the class set,
## which can be disabled by setting the controller.useIngressClassOnly parameter to true.

## The Ingress Controller processes all the VirtualServer/VirtualServerRoute resources that do not have the "ingressClassName" field for all versions of kubernetes.
## The Ingress Controller processes all the VirtualServer/VirtualServerRoute/TransportServer resources that do not have the "ingressClassName" field for all versions of kubernetes.
ingressClass: nginx

## For kubernetes versions >= 1.18 this flag will be IGNORED.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,10 @@ Below we describe the available command-line arguments:
For Kubernetes >= 1.18, a corresponding IngressClass resource with the name equal to the class must be deployed. Otherwise, the Ingress Controller will fail to start.
The Ingress controller only processes resources that belong to its class - i.e. have the "ingressClassName" field resource equal to the class.
For Kubernetes < 1.18, the Ingress Controller only processes resources that belong to its class - i.e have the annotation "kubernetes.io/ingress.class" (for Ingress resources) or field "ingressClassName" (for VirtualServer/VirtualServerRoute resources) equal to the class.
For Kubernetes < 1.18, the Ingress Controller only processes resources that belong to its class - i.e have the annotation "kubernetes.io/ingress.class" (for Ingress resources) or field "ingressClassName" (for VirtualServer/VirtualServerRoute/TransportServer resources) equal to the class.
Additionally, the Ingress Controller processes resources that do not have the class set, which can be disabled by setting the "-use-ingress-class-only" flag.
The Ingress Controller processes all the VirtualServer/VirtualServerRoute resources that do not have the "ingressClassName" field.
The Ingress Controller processes all the VirtualServer/VirtualServerRoute/TransportServer resources that do not have the "ingressClassName" field.
(default "nginx")
Expand Down
4 changes: 4 additions & 0 deletions docs-web/configuration/transportserver-resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ The TransportServer resource defines load balancing configuration for TCP, UDP,
- The action to perform for a client connection/datagram.
- `action <#action>`_
- Yes
* - ``ingressClassName``
- Specifies which Ingress Controller must handle the TransportServer resource.
- ``string``
- No
```
\* -- Required for TLS Passthrough load balancing.
Expand Down
2 changes: 1 addition & 1 deletion docs-web/installation/installation-with-helm.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ The following tables lists the configurable parameters of the NGINX Ingress cont
- The number of replicas of the Ingress controller deployment.
- 1
* - ``controller.ingressClass``
- A class of the Ingress controller. For Kubernetes >= 1.18, the Ingress controller only processes resources that belong to its class - i.e. have the ``"ingressClassName"`` field resource equal to the class. For Kubernetes < 1.18, the Ingress Controller only processes resources that belong to its class - i.e have the annotation ``"kubernetes.io/ingress.class"`` equal to the class. Additionally, the Ingress Controller processes resources that do not have the class set, which can be disabled by setting the ``controller.useIngressClassOnly`` flag. The Ingress Controller processes all the VirtualServer/VirtualServerRoute resources that do not have the ``"ingressClassName"`` field for all versions of kubernetes.
- A class of the Ingress controller. For Kubernetes >= 1.18, a corresponding IngressClass resource with the name equal to the class must be deployed. Otherwise, the Ingress Controller will fail to start. The Ingress controller only processes resources that belong to its class - i.e. have the ``"ingressClassName"`` field resource equal to the class. For Kubernetes < 1.18, the Ingress Controller only processes resources that belong to its class - i.e have the annotation ``"kubernetes.io/ingress.class"`` (for Ingress resources) or field ``"ingressClassName"`` (for VirtualServer/VirtualServerRoute/TransportServer resources) equal to the class. Additionally, the Ingress Controller processes resources that do not have the class set, which can be disabled by setting the ``controller.useIngressClassOnly`` parameter to ``true``. The Ingress Controller processes all the VirtualServer/VirtualServerRoute/TransportServer resources that do not have the ``"ingressClassName"`` field for all versions of kubernetes.
- nginx
* - ``controller.useIngressClassOnly``
- Ignore Ingress resources without the ``"kubernetes.io/ingress.class"`` annotation. For kubernetes versions >= 1.18 this flag will be IGNORED.
Expand Down
6 changes: 3 additions & 3 deletions docs-web/installation/running-multiple-ingress-controllers.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ This document explains the following topics:
* How to run NGINX Ingress Controller in the same cluster with another Ingress Controller, such as an Ingress Controller for a cloud HTTP load balancer, and prevent any conflicts between the Ingress Controllers.
* How to run multiple NGINX Ingress Controllers.

**Note**: In this document we refer to Ingress, VirtualServer and VirtualServerRoute resources as configuration resources.
**Note**: In this document we refer to Ingress, VirtualServer, VirtualServerRoute, and TransportServer resources as configuration resources.

## Ingress Class

The smooth coexistence of multiple Ingress Controllers in one cluster is provided by the Ingress class concept, which mandates the following:
* Every Ingress Controller must only handle Ingress resources for its particular class.
* For Kubernetes < 1.18, Ingress resources should be annotated with the `kubernetes.io/ingress.class` annotation set to the value, which corresponds to the class of the Ingress Controller the user wants to use.
* When using versions of Kubernetes >= 1.18, Ingress resources should have the `ingressClassName` field set to the value, which corresponds to the class of the Ingress Controller the user wants to use.
* VirtualServer and VirtualServerRoute resources should have the `ingressClassName` field set to the value, which corresponds to the class of the Ingress Controller the user wants to use.
* VirtualServer, VirtualServerRoute and TransportServer resources should have the `ingressClassName` field set to the value, which corresponds to the class of the Ingress Controller the user wants to use.

### Configuring Ingress Class

Expand All @@ -22,7 +22,7 @@ The default Ingress class of NGINX Ingress Controller is `nginx`, which means th
**Notes**:
* For Kubernetes < 1.18, if the class is not set in an Ingress configuration resource, the Ingress Controller will handle the resource. This is controlled via the `-use-ingress-class-only` argument.
* For Kubernetes >= 1.18, if the class is not set in an Ingress resource, Kubernetes will set it to the class of the default Ingress Controller. To make the Ingress Controller the default one, the `ingressclass.kubernetes.io/is-default-class` must be set on the IngressClass resource. See Step 3 *Create an IngressClass resource* of the [Create Common Resources](/nginx-ingress-controller/installation/installation-with-manifests/#create-common-resources) section.
* For VirtualServer and VirtualServerRoute resources, the Ingress Controller will always handle resources with an empty class.
* For VirtualServer, VirtualServerRoute and TransportServer resources the Ingress Controller will always handle resources with an empty class.

## Running NGINX Ingress Controller and Another Ingress Controller

Expand Down
11 changes: 8 additions & 3 deletions internal/k8s/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -601,12 +601,17 @@ func (c *Configuration) AddOrUpdateTransportServer(ts *conf_v1alpha1.TransportSe
defer c.lock.Unlock()

key := getResourceKey(&ts.ObjectMeta)
var validationErr error

validationErr := c.transportServerValidator.ValidateTransportServer(ts)
if validationErr != nil {
if !c.hasCorrectIngressClass(ts) {
delete(c.transportServers, key)
} else {
c.transportServers[key] = ts
validationErr = c.transportServerValidator.ValidateTransportServer(ts)
if validationErr != nil {
delete(c.transportServers, key)
} else {
c.transportServers[key] = ts
}
}

changes, problems := c.rebuildListeners()
Expand Down
64 changes: 64 additions & 0 deletions internal/k8s/configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2171,6 +2171,70 @@ func TestAddInvalidTransportServer(t *testing.T) {
}
}

func TestAddTransportServerWithIncorrectClass(t *testing.T) {
configuration := createTestConfiguration()

// Add TransportServer with incorrect class

ts := createTestTLSPassthroughTransportServer("transportserver", "foo.example.com")
ts.Spec.IngressClass = "someproxy"

var expectedProblems []ConfigurationProblem
var expectedChanges []ResourceChange

changes, problems := configuration.AddOrUpdateTransportServer(ts)
if diff := cmp.Diff(expectedChanges, changes); diff != "" {
t.Errorf("AddOrUpdateTransportServer() returned unexpected result (-want +got):\n%s", diff)
}
if diff := cmp.Diff(expectedProblems, problems); diff != "" {
t.Errorf("AddOrUpdateTransportServer() returned unexpected result (-want +got):\n%s", diff)
}

// Make the class correct

updatedTS := ts.DeepCopy()
updatedTS.Generation++
updatedTS.Spec.IngressClass = "nginx"

expectedChanges = []ResourceChange{
{
Op: AddOrUpdate,
Resource: &TransportServerConfiguration{
TransportServer: updatedTS,
},
},
}
expectedProblems = nil

changes, problems = configuration.AddOrUpdateTransportServer(updatedTS)
if diff := cmp.Diff(expectedChanges, changes); diff != "" {
t.Errorf("AddOrUpdateTransportServer() returned unexpected result (-want +got):\n%s", diff)
}
if diff := cmp.Diff(expectedProblems, problems); diff != "" {
t.Errorf("AddOrUpdateTransportServer() returned unexpected result (-want +got):\n%s", diff)
}

// Make the class incorrect

expectedChanges = []ResourceChange{
{
Op: Delete,
Resource: &TransportServerConfiguration{
TransportServer: updatedTS,
},
},
}
expectedProblems = nil

changes, problems = configuration.AddOrUpdateTransportServer(ts)
if diff := cmp.Diff(expectedChanges, changes); diff != "" {
t.Errorf("AddOrUpdateTransportServer() returned unexpected result (-want +got):\n%s", diff)
}
if diff := cmp.Diff(expectedProblems, problems); diff != "" {
t.Errorf("AddOrUpdateTransportServer() returned unexpected result (-want +got):\n%s", diff)
}
}

func TestAddTransportServerWithNonExistingListener(t *testing.T) {
configuration := createTestConfiguration()

Expand Down
3 changes: 2 additions & 1 deletion internal/k8s/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1247,7 +1247,6 @@ func (lbc *LoadBalancerController) updateTransportServerEventsOnDelete(tsConfig
// we don't need to report anything if eventWarningMessage is empty
// in that case, the resource was deleted because its class became incorrect
// (some other Ingress Controller will handle it)
// This check will become necessary when TransportServer supports IngressClass

if eventWarningMessage != "" {
if deleteErr != nil {
Expand Down Expand Up @@ -2960,6 +2959,8 @@ func (lbc *LoadBalancerController) HasCorrectIngressClass(obj interface{}) bool
class = obj.Spec.IngressClass
case *conf_v1.VirtualServerRoute:
class = obj.Spec.IngressClass
case *conf_v1alpha1.TransportServer:
class = obj.Spec.IngressClass
case *networking.Ingress:
isIngress = true
class = obj.Annotations[ingressClassKey]
Expand Down
Loading

0 comments on commit da5df32

Please sign in to comment.