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

refactor(policy): generalize route types in outbound index #12664

Conversation

the-wondersmith
Copy link
Contributor

@the-wondersmith the-wondersmith commented May 30, 2024

Subject

Prepare to expand the subset of Gateway API route types linkerd supports driving outbound traffic with in linkerd-policy-controller-k8s-index.

Problem

Currently, the policy controller's index component is written with HTTPRoute support (effectively) exclusively, both in its structure/organization as well as its naming (e.g. HttpRoute as a primary type name, convert_http_route as a method name, etc...).

In order to expand the subset of route types defined by the Gateway API that linkerd supports for driving outbound traffic policy, the policy controller's index component needs to be made more generic in both respects.

Solution

NOTE: PR is branched from the policy-refactor-core-grpc-generalize-route-types branch, so the diff will be appear larger than it actually is until after #12662 has been merged.

PR introduces structural and naming changes making the codebase generic with respect to the type of route being handled (e.g. HTTPRoute -> Route). Changes are largely cosmetic, with no behavioral changes introduced by any functional refactoring.

Validation

  • maintainer review
  • tests pass

Screenshot 2024-05-30 at 7 26 34 PM

Fixes Lays Groundwork For Addressing

Signed-off-by: Mark S <the@wondersmith.dev>
Signed-off-by: Mark S <the@wondersmith.dev>
Signed-off-by: Mark S <the@wondersmith.dev>
Signed-off-by: Mark S <the@wondersmith.dev>
@the-wondersmith the-wondersmith requested a review from a team as a code owner May 30, 2024 23:26
@the-wondersmith the-wondersmith changed the title Policy refactor index outbound generalize route types refactor(policy): generalize route types in outbound index May 31, 2024
Copy link
Member

@olix0r olix0r left a comment

Choose a reason for hiding this comment

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

It looks like Cargo.lock is updating many dependencies. Is that required for this change? Otherwise, we should update them with our normal dependency update process.

@the-wondersmith
Copy link
Contributor Author

the-wondersmith commented Jun 3, 2024

It looks like Cargo.lock is updating many dependencies. Is that required for this change? ...

The itertools crate offers some conveniences that let me simplify a couple of spots. Luckily, itertools is already a transient dependency from prost-derive [ref] so it's not a new addition to the lock file 🙂.

The changes in the lockfile should be correct now though:

  • adding itertools to linkerd-policy-controller-grpc
  • removing k8s-gateway-api from linkerd-policy-controller-k8s-index

Signed-off-by: Mark S <the@wondersmith.dev>
Signed-off-by: Mark S <the@wondersmith.dev>
Signed-off-by: Mark S <the@wondersmith.dev>
(None, Some(_)) => return std::cmp::Ordering::Greater,
};
by_ts.then_with(|| a_name.name.cmp(&b_name.name))
let accrual = outbound.accrual.map(|accrual| outbound::FailureAccrual {
Copy link
Member

Choose a reason for hiding this comment

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

is there a reason this was moved up? can we keep it where it was to minimize noise in the diff and the git history?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It was moved up because the value is used in the match outbound.routes arms below it, so it needs to be bound before that match is evaluated.

policy-controller/grpc/src/outbound.rs Outdated Show resolved Hide resolved

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum OutboundRouteCollection {
Http(HashMap<GroupKindNamespaceName, OutboundRoute<HttpRouteMatch>>),
Copy link
Member

Choose a reason for hiding this comment

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

What do you think of adding an Empty variant to this enum and then making routes an OutboundRouteCollection instead of an Option<OutboundRouteCollection>. (we would use OutboundRouteCollection::Empty instead of None)

The advantage of this is it lets this type internalize more of the state logic. E.g. calling insert with an HttpRoute while in the Empty state transitions to the OutboundRouteCollection::Http state. Calling insert with a GrpcRoute while in the Http state returns an error. Calling remove which causes the HashMap to become empty transitions it to the Empty state. etc. etc.

Internalizing this state logic lets us get rid of functions like default_collection_for.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree with all of that. I went the Option route to reduce the diff, the amount of additional/future code maintenance introduced, etc...

If there's buy in for it, I think your suggestion would for sure be a more polished way to go

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@adleong implemented and pushed the changes to make this happen. Looking forward to your thoughts

None => {}
Some(OutboundRouteCollection::Http(routes)) => {
service_routes
.insert_producer_and_consumer_routes(routes, self.namespace.as_str());
Copy link
Member

Choose a reason for hiding this comment

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

what's the motivation for moving this into a function?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Code duplication reduction. It doesn't happen here (yet) because there's only one variant of OutboundRouteCollection, but once the Grpc variant is introduced all the code that's now inside insert_producer_and_consumer_routes would be duplicated otherwise.

policy-controller/k8s/index/src/outbound/index.rs Outdated Show resolved Hide resolved
policy-controller/k8s/index/src/outbound/index.rs Outdated Show resolved Hide resolved
…efactor-index-outbound-generalize-route-types

Signed-off-by: Mark S <the@wondersmith.dev>

# Conflicts:
#	policy-controller/core/src/outbound.rs
#	policy-controller/grpc/src/outbound.rs
#	policy-controller/k8s/index/src/http_route.rs
#	policy-controller/k8s/index/src/inbound/http_route.rs
#	policy-controller/k8s/index/src/inbound/tests/authorization_policy.rs
#	policy-controller/k8s/index/src/outbound/index.rs
#	policy-controller/k8s/index/src/outbound/tests/routes/http.rs
#	policy-controller/k8s/status/src/index.rs
#	policy-controller/k8s/status/src/resource_id.rs
#	policy-controller/k8s/status/src/tests/http_routes.rs
Signed-off-by: Mark S <the@wondersmith.dev>
Signed-off-by: Mark S <the@wondersmith.dev>
Signed-off-by: Mark S <the@wondersmith.dev>
Signed-off-by: Mark S <the@wondersmith.dev>
@adleong
Copy link
Member

adleong commented Jun 4, 2024

What do you think about something like this? https://github.com/linkerd/linkerd2/compare/alex/std-mem-i-dont-know-her?expand=1

I replaced std::mem::replace with simple assignment. I also made it an invariant that we cannot be in a non-Empty state with an empty map so that we don't have two different states which represent the same thing. And combined a couple of match statements to tighten things up. LMK what you think.

Signed-off-by: Mark S <the@wondersmith.dev>
policy-controller/core/src/outbound.rs Outdated Show resolved Hide resolved
policy-controller/grpc/src/outbound.rs Outdated Show resolved Hide resolved
policy-controller/k8s/index/src/outbound/index.rs Outdated Show resolved Hide resolved
@the-wondersmith
Copy link
Contributor Author

What do you think about something like this? https://github.com/linkerd/linkerd2/compare/alex/std-mem-i-dont-know-her?expand=1

I replaced std::mem::replace with simple assignment. I also made it an invariant that we cannot be in a non-Empty state with an empty map so that we don't have two different states which represent the same thing. And combined a couple of match statements to tighten things up. LMK what you think.

Love it, love everything about it (especially the branch name). Irritatingly, when I originally tried to implement the internal transition to and from Empty as *self = Self::Empty the compiler just straight up refused to cooperate with anything other than replace (no idea why). Your version is way better 😅.

I pulled the changes over and pushed them up 😁

Signed-off-by: Mark S <the@wondersmith.dev>
Signed-off-by: Mark S <the@wondersmith.dev>
Signed-off-by: Mark S <the@wondersmith.dev>
@adleong adleong merged commit d734df0 into linkerd:main Jun 5, 2024
27 checks passed
@the-wondersmith the-wondersmith deleted the policy-refactor-index-outbound-generalize-route-types branch June 5, 2024 18:29
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.

3 participants