-
Notifications
You must be signed in to change notification settings - Fork 689
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add support for ingressv1.Spec.IngressClassName #2548
Conversation
I'm not in love with the package name |
Codecov Report
@@ Coverage Diff @@
## master #2548 +/- ##
==========================================
- Coverage 77.04% 76.94% -0.10%
==========================================
Files 72 72
Lines 5723 5757 +34
==========================================
+ Hits 4409 4430 +21
- Misses 1226 1238 +12
- Partials 88 89 +1
|
I took off the 1.15 milestone since this is not critical to land in that release. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I' reading this correctly, this change looks for an Ingress class string in the spec.ingressclassname field. However, in the v1 API, this string is the name of an object of type IngressClass which represents a deployed Contour control plane.
ha you're right @jpeach, I misread that spec. I'll get this fixed up. =) |
Marking this PR stale since there has been no activity for 14 days. It will be closed if there is no activity for another 90 days. |
e90e82a
to
4d8c977
Compare
4d8c977
to
102de6f
Compare
177b3b1
to
8b74bfb
Compare
6d1d7bb
to
9443d11
Compare
I'm not happy with the version check logic, going to look at implementing: #2219 |
#2668 adds a dynamic lookup for resources. Once that merges, I'll rebase this PR to include that portion. |
The current implementation checks if the This is for the use-case where a cluster doesn't have ingressClasses but a user tries to use them, which I think is an edge case but still valid. |
9443d11
to
d98dc6c
Compare
388cc95
to
f7f7e4a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a first pass over this. I think it would really help to sketch out how we think about IngressClass deployments and how we want them to evolve over time. That larger context would help illuminate the decisions in this PR.
func MatchesIngressClass(o metav1.ObjectMetaAccessor, ic string) bool { | ||
|
||
switch IngressClass(o) { | ||
func MatchesIngressClass(objectClass, ic string) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The purpose of this function is to capture the complexity around matching resources to ingress classes. Now, that is distributed across here, (*KubernetesCache) matchesIngressClass()
and (*StatusAddressUpdater) OnAdd()
. Can we bring is all back so that there is exactly one place that does the ingress class match?
return *obj.Spec.IngressClassName | ||
} | ||
return "" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what annotation.IngressClass()
should do - given a generic resource, figure out and return the ingress class that it belongs to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that we need to know if the annotation is defined at all, if it is then check if it matches. If it's not defined, then we can look at ingress class. That's why it's changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that having one function that returns an object's ingress class would be really helpful since the logic is spread around a bunch now. It may need to also return a bool indicating if the class came from Spec.IngressClassName or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that we need to know if the annotation is defined at all, if it is then check if it matches. If it's not defined, then we can look at ingress class. That's why it's changed.
I think that we can still have it in one place though. The logic for IngressClass
would be:
func IngressClass(o runtime.Object) string {
a := o.GetObjectMeta().GetAnnotations()
if class, ok := a["projectcontour.io/ingress.class"]; ok {
return class
}
if class, ok := a["contour.heptio.com/ingress.class"]; ok {
return class
}
if class, ok := a["kubernetes.io/ingress.class"]; ok {
return class
}
switch obj := obj.(type) {
case *v1beta1.Ingress:
return obj.Spec.IngressClassName
}
return ""
}
This treats the ingress class the same no matter how it is specified. Then we can treat the issue of whether the ingress class matches our configuration separately. We may not want to propagate the default Contour matching behaviour across the the IngressClass resource.
} | ||
if class, ok := a["kubernetes.io/ingress.class"]; ok { | ||
return class | ||
if class, ok := annotations["kubernetes.io/ingress.class"]; ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you are working in the area, suggest adopting the v1beta1.AnnotationIngressClass
constant.
} | ||
if obj.Spec.IngressClassName != nil { | ||
return *obj.Spec.IngressClassName | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO the Spec.IngressClassName
should take precedence since it's not deprecated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docs used to say that annotations were to take precedence over the ingressclass, but now I can't find that reference. I know @youngnick mentioned the same on a previous call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup you are right. From the spec:
// IngressClassName is the name of the IngressClass cluster resource. The
// associated IngressClass defines which controller will implement the
// resource. This replaces the deprecatedkubernetes.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.
Can we add a comment with the rationale and background?
@@ -139,13 +157,39 @@ func (kc *KubernetesCache) Insert(obj interface{}) bool { | |||
case *v1.Service: | |||
kc.services[k8s.NamespacedNameOf(obj)] = obj | |||
return kc.serviceTriggersRebuild(obj) | |||
case *v1beta1.IngressClass: | |||
// Match only ingress classes that Contour should be able to own. | |||
if obj.Spec.Controller == "projectcontour.io/ingress-controller" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"projectcontour.io/ingress-controller"
should be a named constant somewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this should be "projectcontour.io/contour"
🤷
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docs show it as ingress-controller
and I've seen other folks do the same: https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class
…gress objects Add support for IngressClass objects which match the controller name of 'projectcontour.io/ingress-controller'. Any Ingress object which defines an 'Spec.IngressClassName', Contour will validate that a corresponding IngressClass exists. Current ingress class logic for Contour is not affected and still take priority over any IngressClass logic. Signed-off-by: Steve Sloka <[email protected]>
f7f7e4a
to
f8a0325
Compare
👀 |
@@ -258,6 +258,13 @@ func doServe(log logrus.FieldLogger, ctx *serveContext) error { | |||
} | |||
} | |||
|
|||
// Check if the resource exists in the API server before setting up the informer. | |||
if !clients.ResourceExists(k8s.IngressClassResources()...) { | |||
log.WithField("InformOnResources", "Ingressclass Resources").Warnf("resources %v not found in api server", k8s.IngressClassResources()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should probably be info-level since it's not required / the user hasn't explicitly opted into using it (unlike the service API types just above)
} | ||
if obj.Spec.IngressClassName != nil { | ||
return *obj.Spec.IngressClassName | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if !annotation.MatchesIngressClass(typed, s.IngressClass) { | ||
// check if the object has an annotation, which take precedence over spec.ingressclass | ||
_, classAnnotation := annotation.IngressClass(typed.GetObjectMeta().GetAnnotations()) | ||
if !annotation.MatchesIngressClass(classAnnotation, s.IngressClass) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem like it'll correctly handle Ingresses with Spec.IngressClassName
specified -- for example, if s.IngressClass != ""
then won't all Ingresses that only have Spec.IngressClassName
(no annotation) be filtered out here?
|
||
switch IngressClass(o) { | ||
func MatchesIngressClass(objectClass, ic string) bool { | ||
switch objectClass { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not directly related to your PR, but I think this block of code would be easier to understand if we sort of inverted the logic, something like:
// if ic is specified, then the object's ingress class must match it
if ic != "" {
return objectClass == ic
}
// if ic is empty, then the object's ingress class can either be empty
// or DEFAULT_INGRESS_CLASS
return objectClass == "" || objectClass == DEFAULT_INGRESS_CLASS
May be a matter of personal preference though, so take it or leave it.
kc.WithField("name", om.GetName()). | ||
WithField("namespace", om.GetNamespace()). | ||
WithField("kind", kind). | ||
WithField("ingress-class", ic). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you want ic()
here
return *obj.Spec.IngressClassName | ||
} | ||
return "" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that having one function that returns an object's ingress class would be really helpful since the logic is spread around a bunch now. It may need to also return a bool indicating if the class came from Spec.IngressClassName or not.
// Check if this class matches a existing IngressClass. | ||
_, ok := kc.ingressclasses[*ingressClassName] | ||
return ok | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought I left a comment before, but I can't find it now :-/
IIUC, Contour will cache all IngressClass resources that match the controller name. Here, we will match any ingress class whose name matches the Spec.IngressClassName
. So the result of this is that Contour will accept all resources which map to a Contour IngressClass regardless of the class name.
Did I get that right?
Marking this PR stale since there has been no activity for 14 days. It will be closed if there is no activity for another 90 days. |
I think this one won't be implementable until we've settled on a decision in #2809. |
Fixes #2146 by adding support for ingressv1.Spec.IngressClassName.
Signed-off-by: Steve Sloka [email protected]