Skip to content

Commit

Permalink
feat: initial support for gateway grpcroute
Browse files Browse the repository at this point in the history
Signed-off-by: Mark S <[email protected]>
  • Loading branch information
the-wondersmith committed Apr 25, 2024
1 parent dad392f commit 2800b51
Show file tree
Hide file tree
Showing 11 changed files with 1,102 additions and 327 deletions.
317 changes: 210 additions & 107 deletions policy-controller/k8s/status/src/index.rs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion policy-controller/k8s/status/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
mod http_route;
mod index;
mod resource_id;
mod routes;
mod service;

#[cfg(test)]
Expand Down
19 changes: 19 additions & 0 deletions policy-controller/k8s/status/src/resource_id.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
use crate::index::{GATEWAY_API_GROUP, POLICY_API_GROUP};
use linkerd_policy_controller_core::http_route::GroupKindName;
use linkerd_policy_controller_k8s_api::{
gateway as k8s_gateway_api, policy as linkerd_k8s_api, Resource,
};
use std::borrow::Cow;

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct ResourceId {
Expand All @@ -17,3 +22,17 @@ pub struct NamespaceGroupKindName {
pub namespace: String,
pub gkn: GroupKindName,
}

impl NamespaceGroupKindName {
pub fn api_version(&self) -> Result<Cow<'static, str>, String> {
match (self.gkn.group.as_ref(), self.gkn.kind.as_ref()) {
(POLICY_API_GROUP, "HTTPRoute") => Ok(linkerd_k8s_api::HttpRoute::api_version(&())),
(GATEWAY_API_GROUP, "HTTPRoute") => Ok(k8s_gateway_api::HttpRoute::api_version(&())),
(GATEWAY_API_GROUP, "GRPCRoute") => Ok(k8s_gateway_api::GrpcRoute::api_version(&())),
(group, kind) => Err(format!(
"unknown group + kind combination: ({}, {})",
group, kind
)),
}
}
}
173 changes: 173 additions & 0 deletions policy-controller/k8s/status/src/routes/grpc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
use super::BackendReference;
use linkerd_policy_controller_k8s_api::gateway as k8s_gateway_api;

pub(crate) fn make_backends(
namespace: &str,
backends: impl Iterator<Item = k8s_gateway_api::GrpcRouteBackendRef>,
) -> Vec<BackendReference> {
backends
.map(|backend_ref| BackendReference::from_backend_ref(&backend_ref.inner, namespace))
.collect()
}

#[cfg(test)]
mod test {
use super::*;
use crate::index::POLICY_API_GROUP;
use linkerd_policy_controller_k8s_api::{self as k8s_core_api, gateway as k8s_gateway_api};

fn default_grpc_backends(
backend_refs: Vec<k8s_gateway_api::BackendObjectReference>,
) -> Option<Vec<k8s_gateway_api::GrpcRouteBackendRef>> {
Some(
backend_refs
.into_iter()
.map(|backend_ref| k8s_gateway_api::GrpcRouteBackendRef {
inner: backend_ref,
weight: None,
filters: None,
})
.collect(),
)
}

#[test]
fn backendrefs_from_route() {
let route = k8s_gateway_api::GrpcRoute {
metadata: k8s_core_api::ObjectMeta {
namespace: Some("foo".to_string()),
name: Some("foo".to_string()),
..Default::default()
},
spec: k8s_gateway_api::GrpcRouteSpec {
inner: k8s_gateway_api::CommonRouteSpec { parent_refs: None },
hostnames: None,
rules: Some(vec![
k8s_gateway_api::GrpcRouteRule {
matches: None,
filters: None,
backend_refs: default_grpc_backends(vec![
k8s_gateway_api::BackendObjectReference {
group: None,
kind: None,
name: "ref-1".to_string(),
namespace: Some("default".to_string()),
port: None,
},
k8s_gateway_api::BackendObjectReference {
group: None,
kind: None,
name: "ref-2".to_string(),
namespace: None,
port: None,
},
]),
},
k8s_gateway_api::GrpcRouteRule {
matches: None,
filters: None,
backend_refs: default_grpc_backends(vec![
k8s_gateway_api::BackendObjectReference {
group: Some("Core".to_string()),
kind: Some("Service".to_string()),
name: "ref-3".to_string(),
namespace: Some("default".to_string()),
port: None,
},
]),
},
k8s_gateway_api::GrpcRouteRule {
matches: None,
filters: None,
backend_refs: None,
},
]),
},
status: None,
};

let result = make_backends(
route
.metadata
.namespace
.as_deref()
.expect("GrpcRoute must have namespace"),
route
.spec
.rules
.into_iter()
.flatten()
.flat_map(|rule| rule.backend_refs)
.flatten(),
);
assert_eq!(
3,
result.len(),
"expected only three BackendReferences from route"
);
result.into_iter().for_each(|backend_ref| {
assert!(matches!(backend_ref, BackendReference::Service(_)));
})
}

#[test]
fn backendrefs_from_multiple_types() {
let route = k8s_gateway_api::GrpcRoute {
metadata: k8s_core_api::ObjectMeta {
namespace: Some("default".to_string()),
name: Some("foo".to_string()),
..Default::default()
},
spec: k8s_gateway_api::GrpcRouteSpec {
inner: k8s_gateway_api::CommonRouteSpec { parent_refs: None },
hostnames: None,
rules: Some(vec![k8s_gateway_api::GrpcRouteRule {
matches: None,
filters: None,
backend_refs: default_grpc_backends(vec![
k8s_gateway_api::BackendObjectReference {
group: None,
kind: None,
name: "ref-1".to_string(),
namespace: None,
port: None,
},
k8s_gateway_api::BackendObjectReference {
group: Some(POLICY_API_GROUP.to_string()),
kind: Some("Server".to_string()),
name: "ref-2".to_string(),
namespace: None,
port: None,
},
]),
}]),
},
status: None,
};

let result = make_backends(
route
.metadata
.namespace
.as_deref()
.expect("GrpcRoute must have namespace"),
route
.spec
.rules
.into_iter()
.flatten()
.flat_map(|rule| rule.backend_refs)
.flatten(),
);
assert_eq!(
2,
result.len(),
"expected only two BackendReferences from route"
);
let mut iter = result.into_iter();
let known = iter.next().unwrap();
assert!(matches!(known, BackendReference::Service(_)));
let unknown = iter.next().unwrap();
assert!(matches!(unknown, BackendReference::Unknown))
}
}
Loading

0 comments on commit 2800b51

Please sign in to comment.