-
Notifications
You must be signed in to change notification settings - Fork 363
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
feat(translator): implement backend API #3495
Conversation
fe6d28d
to
9fe20b9
Compare
Signed-off-by: Guy Daich <[email protected]>
/retest |
internal/gatewayapi/route.go
Outdated
@@ -1176,6 +1178,17 @@ func (t *Translator) processDestination(backendRefContext BackendRefContext, | |||
Endpoints: endpoints, | |||
AddressType: addrType, | |||
} | |||
// TODO: support mixed endpointslice address type for the same backendRef |
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.
can we move this out of switch
to make it common amongst all backend types ?
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 condition is slightly different for Backend
vs. the native K8s resources (depending on EndpointRouting toggle) and so is the message. I'll split the validation and status update.
case true: | ||
return newCondition(string(egv1a1.BackendReasonInvalid), metav1.ConditionTrue, | ||
string(egv1a1.BackendConditionAccepted), | ||
"The Backend was accepted Envoy Gateway", time.Now(), be.Generation) |
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 Backend was accepted Envoy Gateway", time.Now(), be.Generation) | |
"The Backend was accepted by Envoy Gateway", time.Now(), be.Generation) |
"The Backend was accepted Envoy Gateway", time.Now(), be.Generation) | |
"The Backend was accepted Envoy Gateway", time.Now(), be.Generation) |
case true: | ||
return newCondition(string(egv1a1.BackendReasonInvalid), metav1.ConditionTrue, | ||
string(egv1a1.BackendConditionAccepted), | ||
"The Backend was accepted Envoy Gateway", time.Now(), be.Generation) |
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.
do we need the "Envoy Gateway" suffix?
// Watch Backend CRUDs and process affected *Route objects. | ||
if r.envoyGateway.ExtensionAPIs != nil && r.envoyGateway.ExtensionAPIs.EnableBackend { | ||
backendPredicates := []predicate.TypedPredicate[*egv1a1.Backend]{ | ||
predicate.NewTypedPredicateFuncs[*egv1a1.Backend](func(be *egv1a1.Backend) 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.
ObservedGeneration predicate ? we haven't added the ObjectMeta
yet so it won't work
the issue I see here is constant reconciling -
- reconcile backend
- translate backend and update status
- translate again (may be stopped by watchable layer which checks for equality)
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.
gateway/internal/gatewayapi/resource.go
Line 172 in 44330ef
return reflect.DeepEqual(c, y) |
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.
Can you elaborate on why TypedGenerationChangedPredicate
won't work here?
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.
nvm it will, took a look at the struct
gateway/api/v1alpha1/backend_types.go
Line 43 in 6f30397
metav1.ObjectMeta `json:"metadata,omitempty"` |
and you've added
ObjectMeta
, so should work, lets add it
Signed-off-by: Guy Daich <[email protected]>
Signed-off-by: Guy Daich <[email protected]>
/retest |
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.
LGTM thanks for implementing this and making it easier to route to non k8s endpoints !
can we document the remaining items (disallowing localhost
, other xRoute backend) as subtasks ?
Signed-off-by: Guy Daich <[email protected]>
/retest |
Signed-off-by: Guy Daich <[email protected]>
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.
Looking at this carefully again, I think maybe it would make sense to rename the IPv4
field in BackendEndpoint
to IP
since using IPv6 addresses would probably already just work.
} | ||
} else { // IP or FQDN | ||
err := validation.IsDNS1123Subdomain(d.Host) | ||
_, pErr := netip.ParseAddr(d.Host) |
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.
Even though the field is called "ipv4", I think IPv6 addresses would still work here. netip.ParseAddr
has no issue with IPv6 addresses.
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 enforced with CEL at the moment:
gateway/api/v1alpha1/backend_types.go
Line 84 in 7f2038f
// +kubebuilder:validation:Pattern=`^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$` |
internal/gatewayapi/validate.go
Outdated
unsupportedRef = true | ||
case bep.FQDN != nil && bep.FQDN.Hostname == "localhost": | ||
unsupportedRef = true | ||
case bep.IPv4 != nil && bep.IPv4.Address == "127.0.0.1": |
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.
Even though the field is called IPv4
, there's nothing that really prevents IPv6 addresses from being specified here as far as I can tell.
Consider also rejecting the IPv6 localhost address ? ::1
?
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.
Also, localhost on Linux systems is not just 127.0.0.1
. It's 127.0.0.1/8
, which means that this check is wrong.
The correct way to check this would be to check if the provided address is contained in 127.0.0.0/8
, not to string-compare to 127.0.0.1
.
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.
yea, good point, we just discussed this in slack. I'll update the validation to comply with the K8s one for EP Slices that checks for the entire range.
internal/gatewayapi/validate.go
Outdated
switch { | ||
case bep.Unix != nil: | ||
unsupportedRef = true | ||
case bep.FQDN != nil && bep.FQDN.Hostname == "localhost": |
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 the intent is to prevent localhost from being the target, in case of an FQDN the better approach would be to try to resolve the hostname and see that it doesn't resolve to the localhost.
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.
What would happen if somebody were to use an IP in the FQDN
field of BackendEndpoint
? I think it would just work, except that it would be possible to use 127.0.0.1
or ::1
here.
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 the intent is to prevent localhost from being the target, in case of an FQDN the better approach would be to try to resolve the hostname and see that it doesn't resolve to the localhost.
Users can change the DNS record this after the resource is accepted. Then, it becomes a race with the next translation until the config is rejected. So, it's still possible that there's a time window where localhost routing is possible.
We discussed this concern here: #3063 (comment). I'm not sure that there really is a good solution for that. The compromise is to enforce validations equivalent to what K8s allows in EP slices, and make users aware of the risk...
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.
What would happen if somebody were to use an IP in the FQDN field of BackendEndpoint?
There's a CEL validation that will probably reject IPv6 Addresses (as ":" is nto supported). But, IPv4 addresses are actually accepted by this validation. I'll add additional programatic validations.
gateway/api/v1alpha1/backend_types.go
Line 103 in 7f2038f
// +kubebuilder:validation:Pattern=`^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` |
/retest |
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.
a non-blocking comment:
func isStatusEqual(objA, objB interface{}) bool { |
func kindOf(obj interface{}) string { |
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.
good catch, thanks, done!
|
||
for _, ap := range backend.Spec.AppProtocols { | ||
if ap == v1alpha1.AppProtocolTypeH2C { | ||
dstProtocol = ir.HTTP2 |
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.
need a break here?
internal/gatewayapi/route.go
Outdated
} | ||
|
||
ds.Weight = &weight | ||
return ds | ||
} | ||
|
||
func validateDestinationSettings(destinationSettings *ir.DestinationSetting, endpointRoutingDisabled bool, kind *gwapiv1.Kind) (bool, string) { |
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.
instead of string
, can we return an error
here? then we can use error.Error()
to retrieve the string of this error later.
Signed-off-by: Guy Daich <[email protected]>
IP:
FQDN:
|
Signed-off-by: Guy Daich <[email protected]>
Signed-off-by: Guy Daich <[email protected]>
This one is huge :-) It would be easier to review and quicker to merge if it could be split into multiple PRs. |
I don’t mean this one, as it’s already under review, but in the future, it might be helpful to split large PRs into multiple smaller ones for easier and quicker reviews. |
|
||
// computeBackendAcceptedCondition computes the Backend Accepted status condition. | ||
func computeBackendAcceptedCondition(be *egv1a1.Backend, accepted bool, msg string) metav1.Condition { | ||
switch accepted { |
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.
why not use the simple if..else
for this boolean ?
What this PR does / why we need it:
Implements backend API
fqdn
,ip
andunix
endpoints in IR and XDSHTTPRoute
andEnvoyExtensionPolicy
references toBackend
BackendTLSPolicy
translation tests forHTTPRoute
andBackend
use casesWhich issue(s) this PR fixes:
Fixes #2997
Relates to #36