Skip to content
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 EgressNetwork and routes statuses #13181

Merged
merged 5 commits into from
Oct 19, 2024
Merged

Conversation

zaharidichev
Copy link
Member

@zaharidichev zaharidichev commented Oct 14, 2024

This PR adds an EgressNetwork CRD, which purpose is to describe networks that are external to the cluster.
In addition to that it also adds TLSRoute and TCPRoute gateway api CRDs.

Most of the work in this change is focused on introducing these CRDs and correctly setting their status based on route specificity rules described in: https://gateway-api.sigs.k8s.io/geps/gep-1426/#route-types.

Notable changes include:

  • ability to attach TCP and TLS routes to both EgressNetworks and Service objects
  • implemented conflict resolutions between routes
  • admission validation on the newly introduced resources
  • module + integration tests

Signed-off-by: Zahari Dichev zaharidichev@gmail.com

Signed-off-by: Zahari Dichev <zaharidichev@gmail.com>
@zaharidichev zaharidichev requested a review from a team as a code owner October 14, 2024 11:27
Signed-off-by: Zahari Dichev <zaharidichev@gmail.com>
Comment on lines 55 to 56
- AllowAll
- DenyAll
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming bikeshed: I think "Allow" and "Deny" are better here. I don't think the word "All" is semantically meaningful, especially considering that the behavior can be changed by matching an attached route.

i.e. the "Deny" policy doesn't deny ALL traffic, it denies traffic that doesn't match any attached routes.

@@ -1 +1,3 @@
enableHttpRoutes: true
enableTlsRoutes: true
enableTcpRoutes: true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing trailing newline

@@ -1 +1,3 @@
enableHttpRoutes: true
enableTlsRoutes: true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a little weird that enableHttpRoutes controls both the HTTPRoute and GRPCRoute CRDs but then TLSRoute and TCPRoute each get their own value. but this is probably fine, more flexibility probably doesn't hurt.

UnknownKind,
}

#[derive(Clone, Eq, PartialEq)]
pub enum BackendReference {
Service(ResourceId),
EgressNetwork(ResourceId),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think an EgressNetwork can be a backend.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say an EgressNetwork has to be able to be a backend. The reason for that is that if you look at the TCPRoute and TLSRoute CRD definitions, you will notice that they mandate that there should be at least 1 rule with at least 1 backend.

If that is a requirement and a user wants to attach a TCPRoute to an EgressNetwork, then what backend would it specify explicitly? Well, it has to be the EgressNetwork itself then. And an EgressNetwork backend in our proxy world will build a Forward stack?

I would argue that... it does not make sense for a route that is attached to a Service to have an EgressNetwork backend, although I cannot come up with a strong argument apart from.. "it does not make sense to do that". But in general.. I do not see a way around having an EgressNetwork work as a backend for EgressNetwork parents.

Does that make sense?

For context: https://github.com/kubernetes-sigs/gateway-api/blob/main/config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml#L436

@@ -945,3 +1316,21 @@ fn eq_time_insensitive(
})
})
}

fn eq_time_insensitive_conditions(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use this function in the above eq_time_insensitive_route_parent_statuses to avoid repetition?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good one.

// attach to has any routes attached that are in conflict with the one
// that we are about to attach. This is done following the logs outlined in:
// https://gateway-api.sigs.k8s.io/geps/gep-1426/#route-types
pub(super) fn parent_has_conflicting_routes<'p>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIOLI but I golfed this down a bit. Same idea but with an inline if instead of building a HashSet

pub(super) fn parent_has_conflicting_routes<'p>(
    existing_routes: impl Iterator<Item = (&'p NamespaceGroupKindName, &'p RouteRef)>,
    parent_ref: &routes::ParentReference,
    candidate_kind: &str,
) -> bool {
    let grpc_kind = k8s_gateway_api::GrpcRoute::kind(&());
    let http_kind = k8s_gateway_api::HttpRoute::kind(&());
    let tls_kind = k8s_gateway_api::TlsRoute::kind(&());
    let tcp_kind = k8s_gateway_api::TcpRoute::kind(&());

    let mut siblings = existing_routes.filter(|(_, route)| route.parents.contains(parent_ref));
    siblings.any(|(id, _sibling)| {
        if *candidate_kind == grpc_kind {
            false
        } else if *candidate_kind == http_kind {
            id.gkn.kind == grpc_kind
        } else if *candidate_kind == tls_kind {
            id.gkn.kind == grpc_kind || id.gkn.kind == http_kind
        } else if *candidate_kind == tcp_kind {
            id.gkn.kind == grpc_kind || id.gkn.kind == http_kind || id.gkn.kind == tls_kind
        } else {
            false
        }
    })
}

@@ -73,8 +91,32 @@ impl BackendReference {
namespace.to_string(),
backend_ref.name.clone(),
))
} else if linkerd_k8s_api::httproute::backend_ref_targets_kind::<
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is valid.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left a more detailed comment on the matter here: #13181 (comment)

impl EgressNetworkRef {
fn is_accepted(&self) -> bool {
self.status_conditions.iter().any(|c| {
c.type_ == conditions::ACCEPTED.to_string()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some clippy warnings here

&& l.observed_generation == r.observed_generation
&& l.reason == r.reason
&& l.status == r.status
&& l.type_ == r.type_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some clippy warnings here

Signed-off-by: Zahari Dichev <zaharidichev@gmail.com>
Comment on lines 532 to 534
routes::BackendReference::EgressNetwork(egress_net) => {
self.egress_networks.contains_key(egress_net)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this where we should validate that the EgressNetwork backend must be equal to the parent?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, correct. Except for the fact that we now need to compute the backend status per parent because the backend status is dependent on the parent type. Namely, you can have an EgressNetwork parent with a Service backend but not the other way around.

Signed-off-by: Zahari Dichev <zaharidichev@gmail.com>
Copy link
Member

@adleong adleong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM modulo stray println and clippy wanring.

}
}
routes::BackendReference::EgressNetwork(egress_net) => {
println!("backend is a net");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stray println

Signed-off-by: Zahari Dichev <zaharidichev@gmail.com>
@zaharidichev zaharidichev merged commit 3e2f31d into main Oct 19, 2024
46 checks passed
@zaharidichev zaharidichev deleted the zd/egress-network-statuses branch October 19, 2024 15:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants