Release v1 (#7470)

* Drop v1beta1 from ingress nginx (#7156)

* Drop v1beta1 from ingress nginx

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Fix intorstr logic in controller

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* fixing admission

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* more intorstr fixing

* correct template rendering

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Fix e2e tests for v1 api

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Fix gofmt errors

* This is finally working...almost there...

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Re-add removed validation of AdmissionReview

* Prepare for v1.0.0-alpha.1 release

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Update changelog and matrix table for v1.0.0-alpha.1 (#7274)

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* add docs for syslog feature (#7219)

* Fix link to e2e-tests.md in developer-guide (#7201)

* Use ENV expansion for namespace in args (#7146)

Update the DaemonSet namespace references to use the `POD_NAMESPACE` environment variable in the same way that the Deployment does.

* chart: using Helm builtin capabilities check (#7190)

Signed-off-by: Jintao Zhang <zhangjintao9020@gmail.com>

* Update proper default value for HTTP2MaxConcurrentStreams in Docs (#6944)

It should be 128 as documented in https://github.com/kubernetes/ingress-nginx/blob/master/internal/ingress/controller/config/config.go#L780

* Fix MaxWorkerOpenFiles calculation on high cores nodes (#7107)

* Fix MaxWorkerOpenFiles calculation on high cores nodes

* Add e2e test for rlimit_nofile

* Fix doc for max-worker-open-files

* ingress/tcp: add additional error logging on failed (#7208)

* Add file containing stable release (#7313)

* Handle named (non-numeric) ports correctly (#7311)

Signed-off-by: Carlos Panato <ctadeu@gmail.com>

* Updated v1beta1 to v1 as its deprecated (#7308)

* remove mercurial from build (#7031)

* Retry to download maxmind DB if it fails (#7242)

* Retry to download maxmind DB if it fails.

Signed-off-by: Sergey Shakuto <sshakuto@infoblox.com>

* Add retries count arg, move retry logic into DownloadGeoLite2DB function

Signed-off-by: Sergey Shakuto <sshakuto@infoblox.com>

* Reorder parameters in DownloadGeoLite2DB

Signed-off-by: Sergey Shakuto <sshakuto@infoblox.com>

* Remove hardcoded value

Signed-off-by: Sergey Shakuto <sshakuto@infoblox.com>

* Release v1.0.0-alpha.1

* Add changelog for v1.0.0-alpha.2

* controller: ignore non-service backends (#7332)

* controller: ignore non-service backends

Signed-off-by: Carlos Panato <ctadeu@gmail.com>

* update per feedback

Signed-off-by: Carlos Panato <ctadeu@gmail.com>

* fix: allow scope/tcp/udp configmap namespace to altered (#7161)

* Lower webhook timeout for digital ocean (#7319)

* Lower webhook timeout for digital ocean

* Set Digital Ocean value controller.admissionWebhooks.timeoutSeconds to 29

* update OWNERS and aliases files (#7365) (#7366)

Signed-off-by: Carlos Panato <ctadeu@gmail.com>

* Downgrade Lua modules for s390x (#7355)

Downgrade Lua modules to last known working version.

* Fix IngressClass logic for newer releases (#7341)

* Fix IngressClass logic for newer releases

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Change e2e tests for the new IngressClass presence

* Fix chart and admission tests

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Fix helm chart test

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Fix reviews

* Remove ingressclass code from admission

* update tag to v1.0.0-beta.1

* update readme and changelog for v1.0.0-beta.1

* Release v1.0.0-beta.1 - helm and manifests (#7422)

* Change the order of annotation just to trigger a new helm release (#7425)

* [cherry-pick] Add dev-v1 branch into helm releaser (#7428)

* Add dev-v1 branch into helm releaser (#7424)

* chore: add link for artifacthub.io/prerelease annotations

Signed-off-by: Jintao Zhang <zhangjintao9020@gmail.com>

Co-authored-by: Ricardo Katz <rikatz@users.noreply.github.com>

* k8s job ci pipeline for dev-v1 br v1.22.0 (#7453)

* k8s job ci pipeline for dev-v1 br v1.22.0

Signed-off-by: Neha Lohia <nehapithadiya444@gmail.com>

* k8s job ci pipeline for dev-v1 br v1.21.2

Signed-off-by: Neha Lohia <nehapithadiya444@gmail.com>

* remove v1.21.1 version

Signed-off-by: Neha Lohia <nehapithadiya444@gmail.com>

* Add controller.watchIngressWithoutClass config option (#7459)

Signed-off-by: Akshit Grover <akshit.grover2016@gmail.com>

* Release new helm chart with certgen fixed (#7478)

* Update go version, modules and remove ioutil

* Release new helm chart with certgen fixed

* changed appversion, chartversion, TAG, image (#7490)

* Fix CI conflict

* Fix CI conflict

* Fix build.sh from rebase process

* Fix controller_test post rebase

Co-authored-by: Tianhao Guo <rggth09@gmail.com>
Co-authored-by: Ray <61553+rctay@users.noreply.github.com>
Co-authored-by: Bill Cassidy <cassid4@gmail.com>
Co-authored-by: Jintao Zhang <tao12345666333@163.com>
Co-authored-by: Sathish Ramani <rsathishx87@gmail.com>
Co-authored-by: Mansur Marvanov <nanorobocop@gmail.com>
Co-authored-by: Matt1360 <568198+Matt1360@users.noreply.github.com>
Co-authored-by: Carlos Tadeu Panato Junior <ctadeu@gmail.com>
Co-authored-by: Kundan Kumar <kundan.kumar@india.nec.com>
Co-authored-by: Tom Hayward <thayward@infoblox.com>
Co-authored-by: Sergey Shakuto <sshakuto@infoblox.com>
Co-authored-by: Tore <tore.lonoy@gmail.com>
Co-authored-by: Bouke Versteegh <info@boukeversteegh.nl>
Co-authored-by: Shahid <shahid@us.ibm.com>
Co-authored-by: James Strong <strong.james.e@gmail.com>
Co-authored-by: Long Wu Yuan <longwuyuan@gmail.com>
Co-authored-by: Jintao Zhang <zhangjintao9020@gmail.com>
Co-authored-by: Neha Lohia <nehapithadiya444@gmail.com>
Co-authored-by: Akshit Grover <akshit.grover2016@gmail.com>
This commit is contained in:
Ricardo Katz 2021-08-21 17:42:00 -03:00 committed by GitHub
parent f3c50698d9
commit 90c79689c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
226 changed files with 3518 additions and 1940 deletions

View file

@ -24,7 +24,7 @@ import (
"github.com/pkg/errors"
apiv1 "k8s.io/api/core/v1"
networking "k8s.io/api/networking/v1beta1"
networking "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/ingress-nginx/internal/file"

View file

@ -17,7 +17,7 @@ limitations under the License.
package store
import (
networking "k8s.io/api/networking/v1beta1"
networking "k8s.io/api/networking/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/ingress-nginx/internal/ingress"
)

View file

@ -0,0 +1,39 @@
/*
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 store
import (
networking "k8s.io/api/networking/v1"
"k8s.io/client-go/tools/cache"
)
// IngressClassLister makes a Store that lists IngressClass.
type IngressClassLister struct {
cache.Store
}
// ByKey returns the Ingress matching key in the local Ingress Store.
func (il IngressClassLister) ByKey(key string) (*networking.IngressClass, error) {
i, exists, err := il.GetByKey(key)
if err != nil {
return nil, err
}
if !exists {
return nil, NotExistsError(key)
}
return i.(*networking.IngressClass), nil
}

View file

@ -28,7 +28,7 @@ import (
"github.com/eapache/channels"
corev1 "k8s.io/api/core/v1"
networkingv1beta1 "k8s.io/api/networking/v1beta1"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
@ -41,14 +41,13 @@ import (
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"k8s.io/klog/v2"
"k8s.io/utils/pointer"
"k8s.io/ingress-nginx/internal/file"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations"
"k8s.io/ingress-nginx/internal/ingress/annotations/class"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
"k8s.io/ingress-nginx/internal/ingress/controller/ingressclass"
ngx_template "k8s.io/ingress-nginx/internal/ingress/controller/template"
"k8s.io/ingress-nginx/internal/ingress/defaults"
"k8s.io/ingress-nginx/internal/ingress/errors"
@ -121,16 +120,18 @@ type Event struct {
// Informer defines the required SharedIndexInformers that interact with the API server.
type Informer struct {
Ingress cache.SharedIndexInformer
Endpoint cache.SharedIndexInformer
Service cache.SharedIndexInformer
Secret cache.SharedIndexInformer
ConfigMap cache.SharedIndexInformer
Ingress cache.SharedIndexInformer
IngressClass cache.SharedIndexInformer
Endpoint cache.SharedIndexInformer
Service cache.SharedIndexInformer
Secret cache.SharedIndexInformer
ConfigMap cache.SharedIndexInformer
}
// Lister contains object listers (stores).
type Lister struct {
Ingress IngressLister
IngressClass IngressClassLister
Service ServiceLister
Endpoint EndpointLister
Secret SecretLister
@ -150,6 +151,7 @@ func (e NotExistsError) Error() string {
func (i *Informer) Run(stopCh chan struct{}) {
go i.Secret.Run(stopCh)
go i.Endpoint.Run(stopCh)
go i.IngressClass.Run(stopCh)
go i.Service.Run(stopCh)
go i.ConfigMap.Run(stopCh)
@ -157,6 +159,7 @@ func (i *Informer) Run(stopCh chan struct{}) {
// from the queue
if !cache.WaitForCacheSync(stopCh,
i.Endpoint.HasSynced,
i.IngressClass.HasSynced,
i.Service.HasSynced,
i.Secret.HasSynced,
i.ConfigMap.HasSynced,
@ -221,7 +224,8 @@ func New(
resyncPeriod time.Duration,
client clientset.Interface,
updateCh *channels.RingChannel,
disableCatchAll bool) Storer {
disableCatchAll bool,
icConfig *ingressclass.IngressClassConfiguration) Storer {
store := &k8sStore{
informers: &Informer{},
@ -293,9 +297,12 @@ func New(
informers.WithTweakListOptions(secretsTweakListOptionsFunc),
)
store.informers.Ingress = infFactory.Networking().V1beta1().Ingresses().Informer()
store.informers.Ingress = infFactory.Networking().V1().Ingresses().Informer()
store.listers.Ingress.Store = store.informers.Ingress.GetStore()
store.informers.IngressClass = infFactory.Networking().V1().IngressClasses().Informer()
store.listers.IngressClass.Store = cache.NewStore(cache.MetaNamespaceKeyFunc)
store.informers.Endpoint = infFactory.Core().V1().Endpoints().Informer()
store.listers.Endpoint.Store = store.informers.Endpoint.GetStore()
@ -317,14 +324,16 @@ func New(
klog.ErrorS(nil, "Error obtaining object from tombstone", "key", obj)
return
}
ing, ok = tombstone.Obj.(*networkingv1beta1.Ingress)
ing, ok = tombstone.Obj.(*networkingv1.Ingress)
if !ok {
klog.Errorf("Tombstone contained object that is not an Ingress: %#v", obj)
return
}
}
if !class.IsValid(ing) {
_, err := store.GetIngressClass(ing, icConfig)
if err != nil {
klog.InfoS("Ignoring ingress because of error while validating ingress class", "ingress", klog.KObj(ing), "error", err)
return
}
@ -347,12 +356,14 @@ func New(
ingEventHandler := cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
ing, _ := toIngress(obj)
if !class.IsValid(ing) {
ingressClass, _ := parser.GetStringAnnotation(class.IngressKey, ing)
klog.InfoS("Ignoring ingress", "ingress", klog.KObj(ing), "kubernetes.io/ingress.class", ingressClass, "ingressClassName", pointer.StringPtrDerefOr(ing.Spec.IngressClassName, ""))
ic, err := store.GetIngressClass(ing, icConfig)
if err != nil {
klog.InfoS("Ignoring ingress because of error while validating ingress class", "ingress", klog.KObj(ing), "error", err)
return
}
klog.InfoS("Found valid IngressClass", "ingress", klog.KObj(ing), "ingressclass", ic)
if hasCatchAllIngressRule(ing.Spec) && disableCatchAll {
klog.InfoS("Ignoring add for catch-all ingress because of --disable-catch-all", "ingress", klog.KObj(ing))
return
@ -374,21 +385,21 @@ func New(
oldIng, _ := toIngress(old)
curIng, _ := toIngress(cur)
validOld := class.IsValid(oldIng)
validCur := class.IsValid(curIng)
if !validOld && validCur {
_, errOld := store.GetIngressClass(oldIng, icConfig)
classCur, errCur := store.GetIngressClass(curIng, icConfig)
if errOld != nil && errCur == nil {
if hasCatchAllIngressRule(curIng.Spec) && disableCatchAll {
klog.InfoS("ignoring update for catch-all ingress because of --disable-catch-all", "ingress", klog.KObj(curIng))
return
}
klog.InfoS("creating ingress", "ingress", klog.KObj(curIng), "class", class.IngressKey)
klog.InfoS("creating ingress", "ingress", klog.KObj(curIng), "ingressclass", classCur)
recorder.Eventf(curIng, corev1.EventTypeNormal, "Sync", "Scheduled for sync")
} else if validOld && !validCur {
klog.InfoS("removing ingress", "ingress", klog.KObj(curIng), "class", class.IngressKey)
} else if errOld == nil && errCur != nil {
klog.InfoS("removing ingress because of unknown ingressclass", "ingress", klog.KObj(curIng))
ingDeleteHandler(old)
return
} else if validCur && !reflect.DeepEqual(old, cur) {
} else if errCur == nil && !reflect.DeepEqual(old, cur) {
if hasCatchAllIngressRule(curIng.Spec) && disableCatchAll {
klog.InfoS("ignoring update for catch-all ingress and delete old one because of --disable-catch-all", "ingress", klog.KObj(curIng))
ingDeleteHandler(old)
@ -412,6 +423,63 @@ func New(
},
}
ingressClassEventHandler := cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
ingressclass := obj.(*networkingv1.IngressClass)
if ingressclass.Spec.Controller != icConfig.Controller {
klog.InfoS("ignoring ingressclass as the spec.controller is not the same of this ingress", "ingressclass", klog.KObj(ingressclass))
return
}
err := store.listers.IngressClass.Add(ingressclass)
if err != nil {
klog.InfoS("error adding ingressclass to store", "ingressclass", klog.KObj(ingressclass), "error", err)
return
}
updateCh.In() <- Event{
Type: CreateEvent,
Obj: obj,
}
},
DeleteFunc: func(obj interface{}) {
ingressclass := obj.(*networkingv1.IngressClass)
if ingressclass.Spec.Controller != icConfig.Controller {
klog.InfoS("ignoring ingressclass as the spec.controller is not the same of this ingress", "ingressclass", klog.KObj(ingressclass))
return
}
err := store.listers.IngressClass.Delete(ingressclass)
if err != nil {
klog.InfoS("error removing ingressclass from store", "ingressclass", klog.KObj(ingressclass), "error", err)
return
}
updateCh.In() <- Event{
Type: DeleteEvent,
Obj: obj,
}
},
UpdateFunc: func(old, cur interface{}) {
oic := old.(*networkingv1.IngressClass)
cic := cur.(*networkingv1.IngressClass)
if cic.Spec.Controller != icConfig.Controller {
klog.InfoS("ignoring ingressclass as the spec.controller is not the same of this ingress", "ingressclass", klog.KObj(cic))
return
}
// TODO: In a future we might be interested in parse parameters and use as
// current IngressClass for this case, crossing with configmap
if !reflect.DeepEqual(cic.Spec.Parameters, oic.Spec.Parameters) {
err := store.listers.IngressClass.Update(cic)
if err != nil {
klog.InfoS("error updating ingressclass in store", "ingressclass", klog.KObj(cic), "error", err)
return
}
updateCh.In() <- Event{
Type: UpdateEvent,
Obj: cur,
}
}
},
}
secrEventHandler := cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
sec := obj.(*corev1.Secret)
@ -608,6 +676,7 @@ func New(
}
store.informers.Ingress.AddEventHandler(ingEventHandler)
store.informers.IngressClass.AddEventHandler(ingressClassEventHandler)
store.informers.Endpoint.AddEventHandler(epEventHandler)
store.informers.Secret.AddEventHandler(secrEventHandler)
store.informers.ConfigMap.AddEventHandler(cmEventHandler)
@ -626,17 +695,17 @@ func New(
// hasCatchAllIngressRule returns whether or not an ingress produces a
// catch-all server, and so should be ignored when --disable-catch-all is set
func hasCatchAllIngressRule(spec networkingv1beta1.IngressSpec) bool {
return spec.Backend != nil
func hasCatchAllIngressRule(spec networkingv1.IngressSpec) bool {
return spec.DefaultBackend != nil
}
// syncIngress parses ingress annotations converting the value of the
// annotation to a go struct
func (s *k8sStore) syncIngress(ing *networkingv1beta1.Ingress) {
func (s *k8sStore) syncIngress(ing *networkingv1.Ingress) {
key := k8s.MetaNamespaceKey(ing)
klog.V(3).Infof("updating annotations information for ingress %v", key)
copyIng := &networkingv1beta1.Ingress{}
copyIng := &networkingv1.Ingress{}
ing.ObjectMeta.DeepCopyInto(&copyIng.ObjectMeta)
ing.Spec.DeepCopyInto(&copyIng.Spec)
ing.Status.DeepCopyInto(&copyIng.Status)
@ -666,7 +735,7 @@ func (s *k8sStore) syncIngress(ing *networkingv1beta1.Ingress) {
// updateSecretIngressMap takes an Ingress and updates all Secret objects it
// references in secretIngressMap.
func (s *k8sStore) updateSecretIngressMap(ing *networkingv1beta1.Ingress) {
func (s *k8sStore) updateSecretIngressMap(ing *networkingv1.Ingress) {
key := k8s.MetaNamespaceKey(ing)
klog.V(3).Infof("updating references to secrets for ingress %v", key)
@ -710,7 +779,7 @@ func (s *k8sStore) updateSecretIngressMap(ing *networkingv1beta1.Ingress) {
// objectRefAnnotationNsKey returns an object reference formatted as a
// 'namespace/name' key from the given annotation name.
func objectRefAnnotationNsKey(ann string, ing *networkingv1beta1.Ingress) (string, error) {
func objectRefAnnotationNsKey(ann string, ing *networkingv1.Ingress) (string, error) {
annValue, err := parser.GetStringAnnotation(ann, ing)
if err != nil {
return "", err
@ -729,7 +798,7 @@ func objectRefAnnotationNsKey(ann string, ing *networkingv1beta1.Ingress) (strin
// syncSecrets synchronizes data from all Secrets referenced by the given
// Ingress with the local store and file system.
func (s *k8sStore) syncSecrets(ing *networkingv1beta1.Ingress) {
func (s *k8sStore) syncSecrets(ing *networkingv1.Ingress) {
key := k8s.MetaNamespaceKey(ing)
for _, secrKey := range s.secretIngressMap.ReferencedBy(key) {
s.syncSecret(secrKey)
@ -758,8 +827,34 @@ func (s *k8sStore) GetService(key string) (*corev1.Service, error) {
return s.listers.Service.ByKey(key)
}
func (s *k8sStore) GetIngressClass(ing *networkingv1.Ingress, icConfig *ingressclass.IngressClassConfiguration) (string, error) {
// First we try ingressClassName
if ing.Spec.IngressClassName != nil {
iclass, err := s.listers.IngressClass.ByKey(*ing.Spec.IngressClassName)
if err != nil {
return "", err
}
return iclass.Name, nil
}
// Then we try annotation
if ingressclass, ok := ing.GetAnnotations()[ingressclass.IngressKey]; ok {
if ingressclass != icConfig.AnnotationValue {
return "", fmt.Errorf("ingress class annotation is not equal to the expected by Ingress Controller")
}
return ingressclass, nil
}
// Then we accept if the WithoutClass is enabled
if icConfig.WatchWithoutClass {
// Reserving "_" as a "wildcard" name
return "_", nil
}
return "", fmt.Errorf("ingress does not contain a valid IngressClass")
}
// getIngress returns the Ingress matching key.
func (s *k8sStore) getIngress(key string) (*networkingv1beta1.Ingress, error) {
func (s *k8sStore) getIngress(key string) (*networkingv1.Ingress, error) {
ing, err := s.listers.IngressWithAnnotation.ByKey(key)
if err != nil {
return nil, err
@ -900,11 +995,11 @@ func (s *k8sStore) Run(stopCh chan struct{}) {
var runtimeScheme = k8sruntime.NewScheme()
func init() {
utilruntime.Must(networkingv1beta1.AddToScheme(runtimeScheme))
utilruntime.Must(networkingv1.AddToScheme(runtimeScheme))
}
func toIngress(obj interface{}) (*networkingv1beta1.Ingress, bool) {
if ing, ok := obj.(*networkingv1beta1.Ingress); ok {
func toIngress(obj interface{}) (*networkingv1.Ingress, bool) {
if ing, ok := obj.(*networkingv1.Ingress); ok {
k8s.SetDefaultNGINXPathType(ing)
return ing, true
}

View file

@ -28,24 +28,61 @@ import (
"github.com/eapache/channels"
v1 "k8s.io/api/core/v1"
networking "k8s.io/api/networking/v1beta1"
networking "k8s.io/api/networking/v1"
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations/class"
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
"k8s.io/ingress-nginx/internal/ingress/controller/ingressclass"
"k8s.io/ingress-nginx/test/e2e/framework"
)
var pathPrefix networking.PathType = networking.PathTypePrefix
var DefaultClassConfig = &ingressclass.IngressClassConfiguration{
Controller: ingressclass.DefaultControllerName,
AnnotationValue: ingressclass.DefaultAnnotationValue,
WatchWithoutClass: false,
}
var (
commonIngressSpec = networking.IngressSpec{
Rules: []networking.IngressRule{
{
Host: "dummy",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/",
PathType: &pathPrefix,
Backend: networking.IngressBackend{
Service: &networking.IngressServiceBackend{
Name: "http-svc",
Port: networking.ServiceBackendPort{
Number: 80,
},
},
},
},
},
},
},
},
},
}
)
func TestStore(t *testing.T) {
//TODO: move env definition to docker image?
os.Setenv("KUBEBUILDER_ASSETS", "/usr/local/bin")
pathPrefix = networking.PathTypePrefix
te := &envtest.Environment{}
cfg, err := te.Start()
if err != nil {
@ -82,7 +119,8 @@ func TestStore(t *testing.T) {
10*time.Minute,
clientSet,
updateCh,
false)
false,
DefaultClassConfig)
storer.Run(stopCh)
@ -108,13 +146,14 @@ func TestStore(t *testing.T) {
t.Errorf("expected an error but none returned")
}
if svc != nil {
t.Errorf("expected an Ingres but none returned")
t.Errorf("expected an Ingress but none returned")
}
})
t.Run("should return one event for add, update and delete of ingress", func(t *testing.T) {
t.Run("should return no event for add, update and delete of ingress as the existing ingressclass is not the expected", func(t *testing.T) {
ns := createNamespace(clientSet, t)
defer deleteNamespace(ns, clientSet, t)
createConfigMap(clientSet, ns, t)
stopCh := make(chan struct{})
@ -159,35 +198,20 @@ func TestStore(t *testing.T) {
10*time.Minute,
clientSet,
updateCh,
false)
false,
DefaultClassConfig)
storer.Run(stopCh)
ic := createIngressClass(clientSet, t, "not-k8s.io/not-ingress-nginx")
defer deleteIngressClass(ic, clientSet, t)
validSpec := commonIngressSpec
validSpec.IngressClassName = &ic
ing := ensureIngress(&networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "dummy",
Name: "dummy-no-class",
Namespace: ns,
},
Spec: networking.IngressSpec{
Rules: []networking.IngressRule{
{
Host: "dummy",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/",
Backend: networking.IngressBackend{
ServiceName: "http-svc",
ServicePort: intstr.FromInt(80),
},
},
},
},
},
},
},
},
Spec: validSpec,
}, clientSet, t)
err := framework.WaitForIngressInNamespace(clientSet, ns, ing.Name)
@ -196,35 +220,113 @@ func TestStore(t *testing.T) {
}
time.Sleep(1 * time.Second)
// create an invalid ingress (different class)
ni := ing.DeepCopy()
ni.Spec.Rules[0].Host = "update-dummy"
_ = ensureIngress(ni, clientSet, t)
if err != nil {
t.Errorf("error creating ingress: %v", err)
}
// Secret takes a bit to update
time.Sleep(3 * time.Second)
err = clientSet.NetworkingV1().Ingresses(ni.Namespace).Delete(context.TODO(), ni.Name, metav1.DeleteOptions{})
if err != nil {
t.Errorf("error deleting ingress: %v", err)
}
err = framework.WaitForNoIngressInNamespace(clientSet, ni.Namespace, ni.Name)
if err != nil {
t.Errorf("error waiting for secret: %v", err)
}
time.Sleep(1 * time.Second)
if atomic.LoadUint64(&add) != 0 {
t.Errorf("expected 0 event of type Create but %v occurred", add)
}
if atomic.LoadUint64(&upd) != 0 {
t.Errorf("expected 0 event of type Update but %v occurred", upd)
}
if atomic.LoadUint64(&del) != 0 {
t.Errorf("expected 0 event of type Delete but %v occurred", del)
}
})
t.Run("should return one event for add, update and delete of ingress", func(t *testing.T) {
ns := createNamespace(clientSet, t)
defer deleteNamespace(ns, clientSet, t)
ic := createIngressClass(clientSet, t, ingressclass.DefaultControllerName)
defer deleteIngressClass(ic, clientSet, t)
createConfigMap(clientSet, ns, t)
stopCh := make(chan struct{})
updateCh := channels.NewRingChannel(1024)
var add uint64
var upd uint64
var del uint64
go func(ch *channels.RingChannel) {
for {
evt, ok := <-ch.Out()
if !ok {
return
}
e := evt.(Event)
if e.Obj == nil {
continue
}
if _, ok := e.Obj.(*networking.Ingress); !ok {
continue
}
switch e.Type {
case CreateEvent:
atomic.AddUint64(&add, 1)
case UpdateEvent:
atomic.AddUint64(&upd, 1)
case DeleteEvent:
atomic.AddUint64(&del, 1)
}
}
}(updateCh)
storer := New(
ns,
fmt.Sprintf("%v/config", ns),
fmt.Sprintf("%v/tcp", ns),
fmt.Sprintf("%v/udp", ns),
"",
10*time.Minute,
clientSet,
updateCh,
false,
DefaultClassConfig)
storer.Run(stopCh)
validSpec := commonIngressSpec
validSpec.IngressClassName = &ic
ing := ensureIngress(&networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "dummy-class",
Namespace: ns,
},
Spec: validSpec,
}, clientSet, t)
err := framework.WaitForIngressInNamespace(clientSet, ns, ing.Name)
if err != nil {
t.Errorf("error waiting for secret: %v", err)
}
time.Sleep(1 * time.Second)
// create an invalid ingress (no ingress class and no watchWithoutClass config)
invalidIngress := ensureIngress(&networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-class",
Name: "no-class",
Namespace: ns,
Annotations: map[string]string{
class.IngressKey: "something",
},
},
Spec: networking.IngressSpec{
Rules: []networking.IngressRule{
{
Host: "dummy",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/",
Backend: networking.IngressBackend{
ServiceName: "http-svc",
ServicePort: intstr.FromInt(80),
},
},
},
},
},
},
},
},
Spec: commonIngressSpec,
}, clientSet, t)
defer deleteIngress(invalidIngress, clientSet, t)
@ -237,9 +339,9 @@ func TestStore(t *testing.T) {
// Secret takes a bit to update
time.Sleep(3 * time.Second)
err = clientSet.NetworkingV1beta1().Ingresses(ni.Namespace).Delete(context.TODO(), ni.Name, metav1.DeleteOptions{})
err = clientSet.NetworkingV1().Ingresses(ni.Namespace).Delete(context.TODO(), ni.Name, metav1.DeleteOptions{})
if err != nil {
t.Errorf("error creating ingress: %v", err)
t.Errorf("error deleting ingress: %v", err)
}
err = framework.WaitForNoIngressInNamespace(clientSet, ni.Namespace, ni.Name)
@ -259,7 +361,7 @@ func TestStore(t *testing.T) {
}
})
t.Run("should not receive updates for ingress with invalid class", func(t *testing.T) {
t.Run("should return two events for add and delete and one for update of ingress and watch-without-class", func(t *testing.T) {
ns := createNamespace(clientSet, t)
defer deleteNamespace(ns, clientSet, t)
createConfigMap(clientSet, ns, t)
@ -297,6 +399,224 @@ func TestStore(t *testing.T) {
}
}(updateCh)
ingressClassconfig := &ingressclass.IngressClassConfiguration{
Controller: ingressclass.DefaultControllerName,
AnnotationValue: ingressclass.DefaultAnnotationValue,
WatchWithoutClass: true,
}
storer := New(
ns,
fmt.Sprintf("%v/config", ns),
fmt.Sprintf("%v/tcp", ns),
fmt.Sprintf("%v/udp", ns),
"",
10*time.Minute,
clientSet,
updateCh,
false,
ingressClassconfig)
storer.Run(stopCh)
validIngress1 := ensureIngress(&networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "ing1",
Namespace: ns,
},
Spec: commonIngressSpec,
}, clientSet, t)
err := framework.WaitForIngressInNamespace(clientSet, ns, validIngress1.Name)
if err != nil {
t.Errorf("error waiting for ingress: %v", err)
}
otherIngress := commonIngressSpec
otherIngress.Rules[0].Host = "other-ingress"
validIngress2 := ensureIngress(&networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "ing2",
Namespace: ns,
},
Spec: otherIngress,
}, clientSet, t)
err = framework.WaitForIngressInNamespace(clientSet, ns, validIngress2.Name)
if err != nil {
t.Errorf("error waiting for ingress: %v", err)
}
time.Sleep(1 * time.Second)
validIngressUpdated := validIngress1.DeepCopy()
validIngressUpdated.Spec.Rules[0].Host = "update-dummy"
_ = ensureIngress(validIngressUpdated, clientSet, t)
if err != nil {
t.Errorf("error updating ingress: %v", err)
}
// Secret takes a bit to update
time.Sleep(3 * time.Second)
err = clientSet.NetworkingV1().Ingresses(validIngressUpdated.Namespace).Delete(context.TODO(), validIngressUpdated.Name, metav1.DeleteOptions{})
if err != nil {
t.Errorf("error deleting ingress: %v", err)
}
err = clientSet.NetworkingV1().Ingresses(validIngress2.Namespace).Delete(context.TODO(), validIngress2.Name, metav1.DeleteOptions{})
if err != nil {
t.Errorf("error deleting ingress: %v", err)
}
err = framework.WaitForNoIngressInNamespace(clientSet, validIngressUpdated.Namespace, validIngressUpdated.Name)
if err != nil {
t.Errorf("error waiting for ingress deletion: %v", err)
}
err = framework.WaitForNoIngressInNamespace(clientSet, validIngress2.Namespace, validIngress2.Name)
if err != nil {
t.Errorf("error waiting for ingress deletion: %v", err)
}
time.Sleep(1 * time.Second)
if atomic.LoadUint64(&add) != 2 {
t.Errorf("expected 0 event of type Create but %v occurred", add)
}
if atomic.LoadUint64(&upd) != 1 {
t.Errorf("expected 0 event of type Update but %v occurred", upd)
}
if atomic.LoadUint64(&del) != 2 {
t.Errorf("expected 0 event of type Delete but %v occurred", del)
}
})
t.Run("should not receive updates for ingress with invalid class annotation", func(t *testing.T) {
ns := createNamespace(clientSet, t)
defer deleteNamespace(ns, clientSet, t)
createConfigMap(clientSet, ns, t)
stopCh := make(chan struct{})
updateCh := channels.NewRingChannel(1024)
var add uint64
var upd uint64
var del uint64
// TODO: This repeats a lot, transform in a local function
go func(ch *channels.RingChannel) {
for {
evt, ok := <-ch.Out()
if !ok {
return
}
e := evt.(Event)
if e.Obj == nil {
continue
}
if _, ok := e.Obj.(*networking.Ingress); !ok {
continue
}
switch e.Type {
case CreateEvent:
atomic.AddUint64(&add, 1)
case UpdateEvent:
atomic.AddUint64(&upd, 1)
case DeleteEvent:
atomic.AddUint64(&del, 1)
}
}
}(updateCh)
storer := New(
ns,
fmt.Sprintf("%v/config", ns),
fmt.Sprintf("%v/tcp", ns),
fmt.Sprintf("%v/udp", ns),
"",
10*time.Minute,
clientSet,
updateCh,
false,
DefaultClassConfig)
storer.Run(stopCh)
// create an invalid ingress (different class)
invalidIngress := ensureIngress(&networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-class",
Namespace: ns,
Annotations: map[string]string{
ingressclass.IngressKey: "something",
},
},
Spec: commonIngressSpec,
}, clientSet, t)
err := framework.WaitForIngressInNamespace(clientSet, ns, invalidIngress.Name)
if err != nil {
t.Errorf("error waiting for ingress: %v", err)
}
time.Sleep(1 * time.Second)
invalidIngressUpdated := invalidIngress.DeepCopy()
invalidIngressUpdated.Spec.Rules[0].Host = "update-dummy"
_ = ensureIngress(invalidIngressUpdated, clientSet, t)
if err != nil {
t.Errorf("error creating ingress: %v", err)
}
// Secret takes a bit to update
time.Sleep(3 * time.Second)
if atomic.LoadUint64(&add) != 0 {
t.Errorf("expected 0 event of type Create but %v occurred", add)
}
if atomic.LoadUint64(&upd) != 0 {
t.Errorf("expected 0 event of type Update but %v occurred", upd)
}
if atomic.LoadUint64(&del) != 0 {
t.Errorf("expected 0 event of type Delete but %v occurred", del)
}
})
t.Run("should not receive updates for ingress with invalid class specification", func(t *testing.T) {
ns := createNamespace(clientSet, t)
defer deleteNamespace(ns, clientSet, t)
ic := createIngressClass(clientSet, t, ingressclass.DefaultControllerName)
defer deleteIngressClass(ic, clientSet, t)
createConfigMap(clientSet, ns, t)
stopCh := make(chan struct{})
updateCh := channels.NewRingChannel(1024)
var add uint64
var upd uint64
var del uint64
go func(ch *channels.RingChannel) {
for {
evt, ok := <-ch.Out()
if !ok {
return
}
e := evt.(Event)
if e.Obj == nil {
continue
}
if _, ok := e.Obj.(*networking.Ingress); !ok {
continue
}
switch e.Type {
case CreateEvent:
atomic.AddUint64(&add, 1)
case UpdateEvent:
atomic.AddUint64(&upd, 1)
case DeleteEvent:
atomic.AddUint64(&del, 1)
}
}
}(updateCh)
storer := New(
ns,
fmt.Sprintf("%v/config", ns),
@ -306,39 +626,20 @@ func TestStore(t *testing.T) {
10*time.Minute,
clientSet,
updateCh,
false)
false,
DefaultClassConfig)
storer.Run(stopCh)
invalidSpec := commonIngressSpec
invalidClassName := "blo123"
invalidSpec.IngressClassName = &invalidClassName
// create an invalid ingress (different class)
invalidIngress := ensureIngress(&networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "custom-class",
Namespace: ns,
Annotations: map[string]string{
class.IngressKey: "something",
},
},
Spec: networking.IngressSpec{
Rules: []networking.IngressRule{
{
Host: "dummy",
IngressRuleValue: networking.IngressRuleValue{
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/",
Backend: networking.IngressBackend{
ServiceName: "http-svc",
ServicePort: intstr.FromInt(80),
},
},
},
},
},
},
},
},
Spec: invalidSpec,
}, clientSet, t)
err := framework.WaitForIngressInNamespace(clientSet, ns, invalidIngress.Name)
if err != nil {
@ -409,7 +710,8 @@ func TestStore(t *testing.T) {
10*time.Minute,
clientSet,
updateCh,
false)
false,
DefaultClassConfig)
storer.Run(stopCh)
@ -455,6 +757,8 @@ func TestStore(t *testing.T) {
t.Run("should receive events from secret referenced from ingress", func(t *testing.T) {
ns := createNamespace(clientSet, t)
defer deleteNamespace(ns, clientSet, t)
ic := createIngressClass(clientSet, t, ingressclass.DefaultControllerName)
defer deleteIngressClass(ic, clientSet, t)
createConfigMap(clientSet, ns, t)
stopCh := make(chan struct{})
@ -475,6 +779,11 @@ func TestStore(t *testing.T) {
if e.Obj == nil {
continue
}
// We should skip IngressClass events
if _, ok := e.Obj.(*networking.IngressClass); ok {
continue
}
switch e.Type {
case CreateEvent:
atomic.AddUint64(&add, 1)
@ -495,7 +804,8 @@ func TestStore(t *testing.T) {
10*time.Minute,
clientSet,
updateCh,
false)
false,
DefaultClassConfig)
storer.Run(stopCh)
@ -508,14 +818,19 @@ func TestStore(t *testing.T) {
Namespace: ns,
},
Spec: networking.IngressSpec{
IngressClassName: &ic,
TLS: []networking.IngressTLS{
{
SecretName: secretName,
},
},
Backend: &networking.IngressBackend{
ServiceName: "http-svc",
ServicePort: intstr.FromInt(80),
DefaultBackend: &networking.IngressBackend{
Service: &networking.IngressServiceBackend{
Name: "http-svc",
Port: networking.ServiceBackendPort{
Number: 80,
},
},
},
},
}, clientSet, t)
@ -563,6 +878,8 @@ func TestStore(t *testing.T) {
t.Run("should create an ingress with a secret which does not exist", func(t *testing.T) {
ns := createNamespace(clientSet, t)
defer deleteNamespace(ns, clientSet, t)
ic := createIngressClass(clientSet, t, ingressclass.DefaultControllerName)
defer deleteIngressClass(ic, clientSet, t)
createConfigMap(clientSet, ns, t)
stopCh := make(chan struct{})
@ -583,6 +900,12 @@ func TestStore(t *testing.T) {
if e.Obj == nil {
continue
}
// We should skip IngressClass objects here
if _, ok := e.Obj.(*networking.IngressClass); ok {
continue
}
switch e.Type {
case CreateEvent:
atomic.AddUint64(&add, 1)
@ -603,7 +926,8 @@ func TestStore(t *testing.T) {
10*time.Minute,
clientSet,
updateCh,
false)
false,
DefaultClassConfig)
storer.Run(stopCh)
@ -616,6 +940,7 @@ func TestStore(t *testing.T) {
Namespace: ns,
},
Spec: networking.IngressSpec{
IngressClassName: &ic,
TLS: []networking.IngressTLS{
{
Hosts: secretHosts,
@ -629,10 +954,15 @@ func TestStore(t *testing.T) {
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/",
Path: "/",
PathType: &pathPrefix,
Backend: networking.IngressBackend{
ServiceName: "http-svc",
ServicePort: intstr.FromInt(80),
Service: &networking.IngressServiceBackend{
Name: "http-svc",
Port: networking.ServiceBackendPort{
Number: 80,
},
},
},
},
},
@ -705,6 +1035,33 @@ func deleteNamespace(ns string, clientSet kubernetes.Interface, t *testing.T) {
}
}
func createIngressClass(clientSet kubernetes.Interface, t *testing.T, controller string) string {
t.Helper()
ingressclass := &networking.IngressClass{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("ingress-nginx-%v", time.Now().Unix()),
//Namespace: "xpto" // TODO: We don't support namespaced ingress-class yet
},
Spec: networking.IngressClassSpec{
Controller: controller,
},
}
ic, err := clientSet.NetworkingV1().IngressClasses().Create(context.TODO(), ingressclass, metav1.CreateOptions{})
if err != nil {
t.Errorf("error creating ingress class: %v", err)
}
return ic.Name
}
func deleteIngressClass(ic string, clientSet kubernetes.Interface, t *testing.T) {
t.Helper()
err := clientSet.NetworkingV1().IngressClasses().Delete(context.TODO(), ic, metav1.DeleteOptions{})
if err != nil {
t.Errorf("error deleting the ingress class: %v", err)
}
}
func createConfigMap(clientSet kubernetes.Interface, ns string, t *testing.T) string {
t.Helper()
@ -724,13 +1081,13 @@ func createConfigMap(clientSet kubernetes.Interface, ns string, t *testing.T) st
func ensureIngress(ingress *networking.Ingress, clientSet kubernetes.Interface, t *testing.T) *networking.Ingress {
t.Helper()
ing, err := clientSet.NetworkingV1beta1().Ingresses(ingress.Namespace).Update(context.TODO(), ingress, metav1.UpdateOptions{})
ing, err := clientSet.NetworkingV1().Ingresses(ingress.Namespace).Update(context.TODO(), ingress, metav1.UpdateOptions{})
if err != nil {
if k8sErrors.IsNotFound(err) {
t.Logf("Ingress %v not found, creating", ingress)
ing, err = clientSet.NetworkingV1beta1().Ingresses(ingress.Namespace).Create(context.TODO(), ingress, metav1.CreateOptions{})
ing, err = clientSet.NetworkingV1().Ingresses(ingress.Namespace).Create(context.TODO(), ingress, metav1.CreateOptions{})
if err != nil {
t.Fatalf("error creating ingress %+v: %v", ingress, err)
}
@ -747,7 +1104,7 @@ func ensureIngress(ingress *networking.Ingress, clientSet kubernetes.Interface,
func deleteIngress(ingress *networking.Ingress, clientSet kubernetes.Interface, t *testing.T) {
t.Helper()
err := clientSet.NetworkingV1beta1().Ingresses(ingress.Namespace).Delete(context.TODO(), ingress.Name, metav1.DeleteOptions{})
err := clientSet.NetworkingV1().Ingresses(ingress.Namespace).Delete(context.TODO(), ingress.Name, metav1.DeleteOptions{})
if err != nil {
t.Errorf("failed to delete ingress %+v: %v", ingress, err)
@ -762,6 +1119,7 @@ func newStore(t *testing.T) *k8sStore {
return &k8sStore{
listers: &Lister{
// add more listers if needed
IngressClass: IngressClassLister{cache.NewStore(cache.MetaNamespaceKeyFunc)},
Ingress: IngressLister{cache.NewStore(cache.MetaNamespaceKeyFunc)},
IngressWithAnnotation: IngressWithAnnotationsLister{cache.NewStore(cache.DeletionHandlingMetaNamespaceKeyFunc)},
},
@ -839,21 +1197,25 @@ func TestUpdateSecretIngressMap(t *testing.T) {
func TestListIngresses(t *testing.T) {
s := newStore(t)
invalidIngressClass := "something"
validIngressClass := ingressclass.DefaultControllerName
ingressToIgnore := &ingress.Ingress{
Ingress: networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "test-2",
Namespace: "testns",
Annotations: map[string]string{
class.IngressKey: "something",
},
Name: "test-2",
Namespace: "testns",
CreationTimestamp: metav1.NewTime(time.Now()),
},
Spec: networking.IngressSpec{
Backend: &networking.IngressBackend{
ServiceName: "demo",
ServicePort: intstr.FromInt(80),
IngressClassName: &invalidIngressClass,
DefaultBackend: &networking.IngressBackend{
Service: &networking.IngressServiceBackend{
Name: "demo",
Port: networking.ServiceBackendPort{
Number: 80,
},
},
},
},
},
@ -868,6 +1230,7 @@ func TestListIngresses(t *testing.T) {
CreationTimestamp: metav1.NewTime(time.Now()),
},
Spec: networking.IngressSpec{
IngressClassName: &validIngressClass,
Rules: []networking.IngressRule{
{
Host: "foo.bar",
@ -876,8 +1239,12 @@ func TestListIngresses(t *testing.T) {
Paths: []networking.HTTPIngressPath{
{
Backend: networking.IngressBackend{
ServiceName: "demo",
ServicePort: intstr.FromInt(80),
Service: &networking.IngressServiceBackend{
Name: "demo",
Port: networking.ServiceBackendPort{
Number: 80,
},
},
},
},
},
@ -890,13 +1257,13 @@ func TestListIngresses(t *testing.T) {
}
s.listers.IngressWithAnnotation.Add(ingressWithoutPath)
ingressWithNginxClass := &ingress.Ingress{
ingressWithNginxClassAnnotation := &ingress.Ingress{
Ingress: networking.Ingress{
ObjectMeta: metav1.ObjectMeta{
Name: "test-4",
Namespace: "testns",
Annotations: map[string]string{
class.IngressKey: "nginx",
ingressclass.IngressKey: ingressclass.DefaultAnnotationValue,
},
CreationTimestamp: metav1.NewTime(time.Now()),
},
@ -908,10 +1275,15 @@ func TestListIngresses(t *testing.T) {
HTTP: &networking.HTTPIngressRuleValue{
Paths: []networking.HTTPIngressPath{
{
Path: "/demo",
Path: "/demo",
PathType: &pathPrefix,
Backend: networking.IngressBackend{
ServiceName: "demo",
ServicePort: intstr.FromInt(80),
Service: &networking.IngressServiceBackend{
Name: "demo",
Port: networking.ServiceBackendPort{
Number: 80,
},
},
},
},
},
@ -922,7 +1294,7 @@ func TestListIngresses(t *testing.T) {
},
},
}
s.listers.IngressWithAnnotation.Add(ingressWithNginxClass)
s.listers.IngressWithAnnotation.Add(ingressWithNginxClassAnnotation)
ingresses := s.ListIngresses()