diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index bb3d444..9e38f8a 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -45,7 +45,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 with: repository: kubernetes-sigs/gateway-api - ref: a0684982eddeb0360e215e0de322c3210ac49bb9 # v1.0.0 + ref: 4f86f0bd65173b04dadb558f63fbbd53330736d2 # 0.5.0-rc1 path: gateway-api - run: kubectl apply -k gateway-api/config/crd/experimental/ - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7508d99..6750417 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,7 +17,7 @@ env: jobs: lint: - timeout-minutes: 20 + timeout-minutes: 5 runs-on: ubuntu-latest container: docker://ghcr.io/linkerd/dev:v42-rust steps: diff --git a/Cargo.toml b/Cargo.toml index 43f4d9f..8324df3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,6 @@ k8s-openapi = { version = "0.20", features = ["schemars"] } schemars = { version = "0.8", features = ["derive"] } serde = { version = "1", features = ["derive"] } serde_json = "1" -thiserror = "1" [dev-dependencies.k8s-openapi] version = "0.20" diff --git a/README.md b/README.md index 8dfcd70..b77d750 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ (Unofficial) Rust bindings for the [Kubernetes Gateway API][site]. -Based on [gateway-api-v1.0.0]. +Based on [gateway-api-v0.5.0-rc1]. [![Crates.io][crate-badge]][crate-url] [![Documentation][docs-badge]][docs-url] @@ -20,7 +20,7 @@ the *v1alpha2* types when the `experimental` feature is enabled. * Express validation constraints * Rustify/Linkify documentation -[gateway-api-v1.0.0]: https://github.com/kubernetes-sigs/gateway-api/tree/a0684982eddeb0360e215e0de322c3210ac49bb9 +[gateway-api-v0.5.0-rc1]: https://github.com/kubernetes-sigs/gateway-api/tree/4f86f0bd65173b04dadb558f63fbbd53330736d2 [site]: https://gateway-api.sigs.k8s.io/ [crate-badge]: https://img.shields.io/crates/v/k8s-gateway-api.svg [crate-url]: https://crates.io/crates/k8s-gateway-api diff --git a/integration/tests/gateway.rs b/integration/tests/gateway.rs index 418f60a..672cfed 100644 --- a/integration/tests/gateway.rs +++ b/integration/tests/gateway.rs @@ -19,7 +19,6 @@ async fn round_trip() { }, spec: GatewaySpec { gateway_class_name: "acme-lb".to_string(), - infrastructure: None, listeners: vec![Listener { protocol: "HTTPS".to_string(), port: 443, diff --git a/integration/tests/httproute.rs b/integration/tests/httproute.rs index 93a3ee1..8742691 100644 --- a/integration/tests/httproute.rs +++ b/integration/tests/httproute.rs @@ -41,7 +41,6 @@ async fn round_trip() { ]), filters: None, matches: None, - timeouts: None, }, HttpRouteRule { matches: Some(vec![HttpRouteMatch { @@ -59,7 +58,6 @@ async fn round_trip() { filters: None, }]), filters: None, - timeouts: None, }, ]), ..HttpRouteSpec::default() diff --git a/src/duration.rs b/src/duration.rs deleted file mode 100644 index 969ec9e..0000000 --- a/src/duration.rs +++ /dev/null @@ -1,354 +0,0 @@ -use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -use std::{fmt, str::FromStr, time::Duration}; - -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct K8sDuration { - duration: Duration, - is_negative: bool, -} - -#[derive(Debug, thiserror::Error, Eq, PartialEq)] -#[non_exhaustive] -pub enum ParseError { - #[error("invalid unit: {}", EXPECTED_UNITS)] - InvalidUnit, - - #[error("missing a unit: {}", EXPECTED_UNITS)] - NoUnit, - - #[error("invalid floating-point number: {}", .0)] - NotANumber(#[from] std::num::ParseFloatError), -} - -const EXPECTED_UNITS: &str = "expected one of 'ns', 'us', '\u{00b5}s', 'ms', 's', 'm', or 'h'"; - -impl From for K8sDuration { - fn from(duration: Duration) -> Self { - Self { - duration, - is_negative: false, - } - } -} - -impl From for Duration { - fn from(K8sDuration { duration, .. }: K8sDuration) -> Self { - duration - } -} - -impl K8sDuration { - #[inline] - #[must_use] - pub fn is_negative(&self) -> bool { - self.is_negative - } -} - -impl fmt::Debug for K8sDuration { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use std::fmt::Write; - if self.is_negative { - f.write_char('-')?; - } - fmt::Debug::fmt(&self.duration, f) - } -} - -impl fmt::Display for K8sDuration { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use std::fmt::Write; - if self.is_negative { - f.write_char('-')?; - } - fmt::Debug::fmt(&self.duration, f) - } -} - -impl FromStr for K8sDuration { - type Err = ParseError; - - fn from_str(mut s: &str) -> Result { - // implements the same format as - // https://cs.opensource.google/go/go/+/refs/tags/go1.20.4:src/time/format.go;l=1589 - - fn duration_from_units(val: f64, unit: &str) -> Result { - const MINUTE: Duration = Duration::from_secs(60); - // https://cs.opensource.google/go/go/+/refs/tags/go1.20.4:src/time/format.go;l=1573 - let base = match unit { - "ns" => Duration::from_nanos(1), - // U+00B5 is the "micro sign" while U+03BC is "Greek letter mu" - "us" | "\u{00b5}s" | "\u{03bc}s" => Duration::from_micros(1), - "ms" => Duration::from_millis(1), - "s" => Duration::from_secs(1), - "m" => MINUTE, - "h" => MINUTE * 60, - _ => return Err(ParseError::InvalidUnit), - }; - Ok(base.mul_f64(val)) - } - - // Go durations are signed. Rust durations aren't. So we need to ignore - // this for now. - let is_negative = s.starts_with('-'); - s = s.trim_start_matches('+').trim_start_matches('-'); - - let mut total = Duration::from_secs(0); - while !s.is_empty() { - if let Some(unit_start) = s.find(|c: char| c.is_alphabetic()) { - let (val, rest) = s.split_at(unit_start); - let val = val.parse::()?; - let unit = if let Some(next_numeric_start) = rest.find(|c: char| !c.is_alphabetic()) - { - let (unit, rest) = rest.split_at(next_numeric_start); - s = rest; - unit - } else { - s = ""; - rest - }; - total += duration_from_units(val, unit)?; - } else if s == "0" { - return Ok(K8sDuration { - duration: Duration::from_secs(0), - is_negative, - }); - } else { - return Err(ParseError::NoUnit); - } - } - - Ok(K8sDuration { - duration: total, - is_negative, - }) - } -} - -impl Serialize for K8sDuration { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.collect_str(self) - } -} - -impl<'de> Deserialize<'de> for K8sDuration { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct Visitor; - impl<'de> de::Visitor<'de> for Visitor { - type Value = K8sDuration; - - fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("a string in Go `time.Duration.String()` format") - } - - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - let val = value.parse::().map_err(de::Error::custom)?; - Ok(val) - } - } - deserializer.deserialize_str(Visitor) - } -} - -impl schemars::JsonSchema for K8sDuration { - // see - // https://github.com/kubernetes/apimachinery/blob/756e2227bf3a486098f504af1a0ffb736ad16f4c/pkg/apis/meta/v1/duration.go#L61 - fn schema_name() -> String { - "K8sDuration".to_owned() - } - - fn is_referenceable() -> bool { - false - } - - fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { - schemars::schema::SchemaObject { - instance_type: Some(schemars::schema::InstanceType::String.into()), - // the format should *not* be "duration", because "duration" means - // the duration is formatted in ISO 8601, as described here: - // https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-02#section-7.3.1 - format: None, - ..Default::default() - } - .into() - } -} -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn parses_the_same_as_go() { - const MINUTE: Duration = Duration::from_secs(60); - const HOUR: Duration = Duration::from_secs(60 * 60); - // from Go: - // https://cs.opensource.google/go/go/+/refs/tags/go1.20.4:src/time/time_test.go;l=891-951 - // ``` - // var parseDurationTests = []struct { - // in string - // want Duration - // }{ - let cases: &[(&str, K8sDuration)] = &[ - // // simple - // {"0", 0}, - ("0", Duration::from_secs(0).into()), - // {"5s", 5 * Second}, - ("5s", Duration::from_secs(5).into()), - // {"30s", 30 * Second}, - ("30s", Duration::from_secs(30).into()), - // {"1478s", 1478 * Second}, - ("1478s", Duration::from_secs(1478).into()), - // // sign - // {"-5s", -5 * Second}, - ( - "-5s", - K8sDuration { - duration: Duration::from_secs(5), - is_negative: true, - }, - ), - // {"+5s", 5 * Second}, - ("+5s", Duration::from_secs(5).into()), - // {"-0", 0}, - ( - "-0", - K8sDuration { - duration: Duration::from_secs(0), - is_negative: true, - }, - ), - // {"+0", 0}, - ("+0", Duration::from_secs(0).into()), - // // decimal - // {"5.0s", 5 * Second}, - ("5s", Duration::from_secs(5).into()), - // {"5.6s", 5*Second + 600*Millisecond}, - ( - "5.6s", - (Duration::from_secs(5) + Duration::from_millis(600)).into(), - ), - // {"5.s", 5 * Second}, - ("5.s", Duration::from_secs(5).into()), - // {".5s", 500 * Millisecond}, - (".5s", Duration::from_millis(500).into()), - // {"1.0s", 1 * Second}, - ("1.0s", Duration::from_secs(1).into()), - // {"1.00s", 1 * Second}, - ("1.00s", Duration::from_secs(1).into()), - // {"1.004s", 1*Second + 4*Millisecond}, - ( - "1.004s", - (Duration::from_secs(1) + Duration::from_millis(4)).into(), - ), - // {"1.0040s", 1*Second + 4*Millisecond}, - ( - "1.0040s", - (Duration::from_secs(1) + Duration::from_millis(4)).into(), - ), - // {"100.00100s", 100*Second + 1*Millisecond}, - ( - "100.00100s", - (Duration::from_secs(100) + Duration::from_millis(1)).into(), - ), - // // different units - // {"10ns", 10 * Nanosecond}, - ("10ns", Duration::from_nanos(10).into()), - // {"11us", 11 * Microsecond}, - ("11us", Duration::from_micros(11).into()), - // {"12µs", 12 * Microsecond}, // U+00B5 - ("12µs", Duration::from_micros(12).into()), - // {"12μs", 12 * Microsecond}, // U+03BC - ("12μs", Duration::from_micros(12).into()), - // {"13ms", 13 * Millisecond}, - ("13ms", Duration::from_millis(13).into()), - // {"14s", 14 * Second}, - ("14s", Duration::from_secs(14).into()), - // {"15m", 15 * Minute}, - ("15m", (15 * MINUTE).into()), - // {"16h", 16 * Hour}, - ("16h", (16 * HOUR).into()), - // // composite durations - // {"3h30m", 3*Hour + 30*Minute}, - ("3h30m", (3 * HOUR + 30 * MINUTE).into()), - // {"10.5s4m", 4*Minute + 10*Second + 500*Millisecond}, - ( - "10.5s4m", - (4 * MINUTE + Duration::from_secs(10) + Duration::from_millis(500)).into(), - ), - // {"-2m3.4s", -(2*Minute + 3*Second + 400*Millisecond)}, - ( - "-2m3.4s", - K8sDuration { - duration: 2 * MINUTE + Duration::from_secs(3) + Duration::from_millis(400), - is_negative: true, - }, - ), - // {"1h2m3s4ms5us6ns", 1*Hour + 2*Minute + 3*Second + 4*Millisecond + 5*Microsecond + 6*Nanosecond}, - ( - "1h2m3s4ms5us6ns", - (1 * HOUR - + 2 * MINUTE - + Duration::from_secs(3) - + Duration::from_millis(4) - + Duration::from_micros(5) - + Duration::from_nanos(6)) - .into(), - ), - // {"39h9m14.425s", 39*Hour + 9*Minute + 14*Second + 425*Millisecond}, - ( - "39h9m14.425s", - (39 * HOUR + 9 * MINUTE + Duration::from_secs(14) + Duration::from_millis(425)) - .into(), - ), - // // large value - // {"52763797000ns", 52763797000 * Nanosecond}, - ("52763797000ns", Duration::from_nanos(52763797000).into()), - // // more than 9 digits after decimal point, see https://golang.org/issue/6617 - // {"0.3333333333333333333h", 20 * Minute}, - ("0.3333333333333333333h", (20 * MINUTE).into()), - // // 9007199254740993 = 1<<53+1 cannot be stored precisely in a float64 - // {"9007199254740993ns", (1<<53 + 1) * Nanosecond}, - ( - "9007199254740993ns", - Duration::from_nanos((1 << 53) + 1).into(), - ), - // Rust Durations can handle larger durations than Go's - // representation, so skip these tests for their precision limits - - // // largest duration that can be represented by int64 in nanoseconds - // {"9223372036854775807ns", (1<<63 - 1) * Nanosecond}, - // ("9223372036854775807ns", Duration::from_nanos((1 << 63) - 1).into()), - // {"9223372036854775.807us", (1<<63 - 1) * Nanosecond}, - // ("9223372036854775.807us", Duration::from_nanos((1 << 63) - 1).into()), - // {"9223372036s854ms775us807ns", (1<<63 - 1) * Nanosecond}, - // {"-9223372036854775808ns", -1 << 63 * Nanosecond}, - // {"-9223372036854775.808us", -1 << 63 * Nanosecond}, - // {"-9223372036s854ms775us808ns", -1 << 63 * Nanosecond}, - // // largest negative value - // {"-9223372036854775808ns", -1 << 63 * Nanosecond}, - // // largest negative round trip value, see https://golang.org/issue/48629 - // {"-2562047h47m16.854775808s", -1 << 63 * Nanosecond}, - - // // huge string; issue 15011. - // {"0.100000000000000000000h", 6 * Minute}, - ("0.100000000000000000000h", (6 * MINUTE).into()), // // This value tests the first overflow check in leadingFraction. - // {"0.830103483285477580700h", 49*Minute + 48*Second + 372539827*Nanosecond}, - // } - // ``` - ]; - - for (input, expected) in cases { - let parsed = dbg!(input).parse::().unwrap(); - assert_eq!(&dbg!(parsed), expected); - } - } -} diff --git a/src/gateway.rs b/src/gateway.rs index 8bd6db6..d19c525 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -9,7 +9,7 @@ use std::collections::BTreeMap; )] #[kube( group = "gateway.networking.k8s.io", - version = "v1", + version = "v1beta1", kind = "Gateway", status = "GatewayStatus", namespaced @@ -20,121 +20,42 @@ pub struct GatewaySpec { /// GatewayClass resource. pub gateway_class_name: ObjectName, - /// Listeners associated with this Gateway. Listeners define - /// logical endpoints that are bound on this Gateway's addresses. - /// At least one Listener MUST be specified. - /// - /// Each Listener in a set of Listeners (for example, in a single Gateway) - /// MUST be _distinct_, in that a traffic flow MUST be able to be assigned to - /// exactly one listener. (This section uses "set of Listeners" rather than - /// "Listeners in a single Gateway" because implementations MAY merge configuration - /// from multiple Gateways onto a single data plane, and these rules _also_ - /// apply in that case). - /// - /// Practically, this means that each listener in a set MUST have a unique - /// combination of Port, Protocol, and, if supported by the protocol, Hostname. - /// - /// Some combinations of port, protocol, and TLS settings are considered - /// Core support and MUST be supported by implementations based on their - /// targeted conformance profile: - /// - /// HTTP Profile - /// - /// 1. HTTPRoute, Port: 80, Protocol: HTTP - /// 2. HTTPRoute, Port: 443, Protocol: HTTPS, TLS Mode: Terminate, TLS keypair provided - /// - /// TLS Profile - /// - /// 1. TLSRoute, Port: 443, Protocol: TLS, TLS Mode: Passthrough - /// - // /"Distinct" Listeners have the following property: - /// - /// The implementation can match inbound requests to a single distinct - /// Listener. When multiple Listeners share values for fields (for - /// example, two Listeners with the same Port value), the implementation - /// can match requests to only one of the Listeners using other - /// Listener fields. - /// - /// For example, the following Listener scenarios are distinct: - /// - /// 1. Multiple Listeners with the same Port that all use the "HTTP" - /// Protocol that all have unique Hostname values. - /// 2. Multiple Listeners with the same Port that use either the "HTTPS" or - /// "TLS" Protocol that all have unique Hostname values. - /// 3. A mixture of "TCP" and "UDP" Protocol Listeners, where no Listener - /// with the same Protocol has the same Port value. - /// - /// Some fields in the Listener struct have possible values that affect - /// whether the Listener is distinct. Hostname is particularly relevant - /// for HTTP or HTTPS protocols. - /// - /// When using the Hostname value to select between same-Port, same-Protocol - /// Listeners, the Hostname value must be different on each Listener for the - /// Listener to be distinct. - /// - /// When the Listeners are distinct based on Hostname, inbound request - /// hostnames MUST match from the most specific to least specific Hostname - /// values to choose the correct Listener and its associated set of Routes. - /// - /// Exact matches must be processed before wildcard matches, and wildcard - /// matches must be processed before fallback (empty Hostname value) - /// matches. For example, `"foo.example.com"` takes precedence over - /// `"*.example.com"`, and `"*.example.com"` takes precedence over `""`. - /// - /// Additionally, if there are multiple wildcard entries, more specific - /// wildcard entries must be processed before less specific wildcard entries. - /// For example, `"*.foo.example.com"` takes precedence over `"*.example.com"`. - /// The precise definition here is that the higher the number of dots in the - /// hostname to the right of the wildcard character, the higher the precedence. - /// - /// The wildcard character will match any number of characters _and dots_ to - /// the left, however, so `"*.example.com"` will match both - /// `"foo.bar.example.com"` _and_ `"bar.example.com"`. - /// - /// If a set of Listeners contains Listeners that are not distinct, then those - /// Listeners are Conflicted, and the implementation MUST set the "Conflicted" - /// condition in the Listener Status to "True". - /// - /// Implementations MAY choose to accept a Gateway with some Conflicted - /// Listeners only if they only accept the partial Listener set that contains - /// no Conflicted Listeners. To put this another way, implementations may - /// accept a partial Listener set only if they throw out *all* the conflicting - /// Listeners. No picking one of the conflicting listeners as the winner. - /// This also means that the Gateway must have at least one non-conflicting - /// Listener in this case, otherwise it violates the requirement that at - /// least one Listener must be present. - /// - /// The implementation MUST set a "ListenersNotValid" condition on the - /// Gateway Status when the Gateway contains Conflicted Listeners whether or - /// not they accept the Gateway. That Condition SHOULD clearly - /// indicate in the Message which Listeners are conflicted, and which are - /// Accepted. Additionally, the Listener status for those listeners SHOULD - /// indicate which Listeners are conflicted and not Accepted. - /// - /// A Gateway's Listeners are considered "compatible" if: - /// - /// 1. They are distinct. - /// 2. The implementation can serve them in compliance with the Addresses - /// requirement that all Listeners are available on all assigned - /// addresses. - /// - /// Compatible combinations in Extended support are expected to vary across - /// implementations. A combination that is compatible for one implementation - /// may not be compatible for another. - /// - /// For example, an implementation that cannot serve both TCP and UDP listeners - /// on the same address, or cannot mix HTTPS and generic TLS listens on the same port - /// would not consider those cases compatible, even though they are distinct. - /// - /// Note that requests SHOULD match at most one Listener. For example, if - /// Listeners are defined for "foo.example.com" and "*.example.com", a - /// request to "foo.example.com" SHOULD only be routed using routes attached - /// to the "foo.example.com" Listener (and not the "*.example.com" Listener). - /// This concept is known as "Listener Isolation". Implementations that do - /// not support Listener Isolation MUST clearly document this. - /// - /// Implementations MAY merge separate Gateways onto a single set of - /// Addresses if all Listeners across all Gateways are compatible. + /// Listeners associated with this Gateway. Listeners define logical + /// endpoints that are bound on this Gateway's addresses. At least one + /// Listener MUST be specified. + /// + /// Each listener in a Gateway must have a unique combination of Hostname, + /// Port, and Protocol. + /// + /// An implementation MAY group Listeners by Port and then collapse each + /// group of Listeners into a single Listener if the implementation + /// determines that the Listeners in the group are "compatible". An + /// implementation MAY also group together and collapse compatible Listeners + /// belonging to different Gateways. + /// + /// For example, an implementation might consider Listeners to be compatible + /// with each other if all of the following conditions are met: + /// + /// 1. Either each Listener within the group specifies the "HTTP" Protocol or + /// each Listener within the group specifies either the "HTTPS" or "TLS" + /// Protocol. + /// + /// 2. Each Listener within the group specifies a Hostname that is unique + /// within the group. + /// + /// 3. As a special case, one Listener within a group may omit Hostname, in + /// which case this Listener matches when no other Listener matches. + /// + /// If the implementation does collapse compatible Listeners, the hostname + /// provided in the incoming client request MUST be matched to a Listener to + /// find the correct set of Routes. The incoming hostname MUST be matched + /// using the Hostname field for each Listener in order of most to least + /// specific. That is, exact matches must be processed before wildcard + /// matches. + /// + /// If this field specifies multiple Listeners that have the same Port value + /// but are not compatible, the implementation must raise a "Conflicted" + /// condition in the Listener status. /// /// Support: Core pub listeners: Vec, @@ -150,6 +71,9 @@ pub struct GatewaySpec { /// other networking infrastructure, or some other address that traffic will /// be sent to. /// + /// The .listener.hostname field is used to route traffic that has already + /// arrived at the Gateway to the correct in-cluster destination. + /// /// If no Addresses are specified, the implementation MAY schedule the /// Gateway in an implementation-specific manner, assigning an appropriate /// set of Addresses. @@ -160,11 +84,6 @@ pub struct GatewaySpec { /// /// Support: Extended pub addresses: Option>, - - /// Infrastructure defines infrastructure level attributes about this Gateway instance. - /// - /// Support: Core - pub infrastructure: Option, } /// Listener embodies the concept of a logical endpoint where a Gateway accepts @@ -186,12 +105,12 @@ pub struct Listener { /// Implementations MUST apply Hostname matching appropriately for each of /// the following protocols: /// - /// * TLS: The Listener Hostname MUST match the SNI. - /// * HTTP: The Listener Hostname MUST match the Host header of the request. - /// * HTTPS: The Listener Hostname SHOULD match at both the TLS and HTTP - /// protocol layers as described above. If an implementation does not - /// ensure that both the SNI and Host header match the Listener hostname, - /// it MUST clearly document that. + /// * TLS: The Listener Hostname MUST match the SNI. * HTTP: The Listener + /// Hostname MUST match the Host header of the request. * HTTPS: The + /// Listener Hostname SHOULD match at both the TLS and HTTP protocol layers + /// as described above. If an implementation does not ensure that both the + /// SNI and Host header match the Listener hostname, it MUST clearly document + /// that. /// /// For HTTPRoute and TLSRoute resources, there is an interaction with the /// `spec.hostnames` array. When both listener and route specify hostnames, @@ -199,10 +118,6 @@ pub struct Listener { /// accepted. For more information, refer to the Route specific Hostnames /// documentation. /// - /// Hostnames that are prefixed with a wildcard label (`*.`) are interpreted - /// as a suffix match. That means that a match for `*.example.com` would match - /// both `test.example.com`, and `foo.test.example.com`, but not `example.com`. - /// /// Support: Core pub hostname: Option, @@ -222,8 +137,8 @@ pub struct Listener { /// The association of SNIs to Certificate defined in GatewayTLSConfig is /// defined based on the Hostname field for this listener. /// - /// The GatewayClass MUST use the longest matching SNI out of all - /// available certificates for any TLS handshake. + /// The GatewayClass MUST use the longest matching SNI out of all available + /// certificates for any TLS handshake. /// /// Support: Core pub tls: Option, @@ -237,16 +152,16 @@ pub struct Listener { /// determined in order of the following criteria: /// /// * The most specific match as defined by the Route type. - /// * The oldest Route based on creation timestamp. For example, a Route with - /// a creation timestamp of "2020-09-08 01:02:03" is given precedence over - /// a Route with a creation timestamp of "2020-09-08 01:02:04". + /// * The oldest Route based on creation timestamp. For example, a Route + /// with a creation timestamp of "2020-09-08 01:02:03" is given precedence + /// over a Route with a creation timestamp of "2020-09-08 01:02:04". /// * If everything else is equivalent, the Route appearing first in /// alphabetical order (namespace/name) should be given precedence. For /// example, foo/bar is given precedence over foo/baz. /// /// All valid rules within a Route attached to this Listener should be - /// implemented. Invalid Route rules can be ignored (sometimes that will mean - /// the full Route). If a Route rule transitions from valid to invalid, + /// implemented. Invalid Route rules can be ignored (sometimes that will + /// mean the full Route). If a Route rule transitions from valid to invalid, /// support for that Route rule should be dropped to ensure consistency. For /// example, even if a filter specified by a Route rule is invalid, the rest /// of the rules within that Route should still be supported. @@ -256,18 +171,18 @@ pub struct Listener { } /// ProtocolType defines the application protocol accepted by a Listener. -/// Implementations are not required to accept all the defined protocols. If an -/// implementation does not support a specified protocol, it MUST set the -/// "Accepted" condition to False for the affected Listener with a reason of -/// "UnsupportedProtocol". +/// Implementations are not required to accept all the defined protocols. +/// If an implementation does not support a specified protocol, it +/// should raise a "Detached" condition for the affected Listener with +/// a reason of "UnsupportedProtocol". /// /// Core ProtocolType values are listed in the table below. /// /// Implementations can define their own protocols if a core ProtocolType does not /// exist. Such definitions must use prefixed name, such as /// `mycompany.com/my-custom-protocol`. Un-prefixed names are reserved for core -/// protocols. Any protocol defined by implementations will fall under -/// Implementation-specific conformance. +/// protocols. Any protocol defined by implementations will fall under custom +/// conformance. /// /// Valid values include: /// @@ -278,6 +193,7 @@ pub struct Listener { /// /// * "example.com" - must include path if domain is used /// * "foo.example.com" - must include path if domain is used +/// pub type ProtocolType = String; /// GatewayTLSConfig describes a TLS configuration. @@ -286,34 +202,34 @@ pub type ProtocolType = String; )] #[serde(rename_all = "camelCase")] pub struct GatewayTlsConfig { - /// Mode defines the TLS behavior for the TLS session initiated by the client. - /// There are two possible modes: + /// Mode defines the TLS behavior for the TLS session initiated by the + /// client. There are two possible modes: /// - /// - Terminate: The TLS session between the downstream client - /// and the Gateway is terminated at the Gateway. This mode requires + /// - Terminate: The TLS session between the downstream client and the + /// Gateway is terminated at the Gateway. This mode requires /// certificateRefs to be set and contain at least one element. /// - Passthrough: The TLS session is NOT terminated by the Gateway. This - /// implies that the Gateway can't decipher the TLS stream except for - /// the ClientHello message of the TLS protocol. - /// CertificateRefs field is ignored in this mode. + /// implies that the Gateway can't decipher the TLS stream except for the + /// ClientHello message of the TLS protocol. CertificateRefs field is + /// ignored in this mode. /// /// Support: Core pub mode: Option, - /// CertificateRefs contains a series of references to Kubernetes objects that - /// contains TLS certificates and private keys. These certificates are used to - /// establish a TLS handshake for requests that match the hostname of the - /// associated listener. + /// CertificateRefs contains a series of references to Kubernetes objects + /// that contains TLS certificates and private keys. These certificates are + /// used to establish a TLS handshake for requests that match the hostname + /// of the associated listener. /// /// A single CertificateRef to a Kubernetes Secret has "Core" support. /// Implementations MAY choose to support attaching multiple certificates to /// a Listener, but this behavior is implementation-specific. /// /// References to a resource in different namespace are invalid UNLESS there - /// is a ReferenceGrant in the target namespace that allows the certificate - /// to be attached. If a ReferenceGrant does not allow this reference, the + /// is a ReferencePolicy in the target namespace that allows the certificate + /// to be attached. If a ReferencePolicy does not allow this reference, the /// "ResolvedRefs" condition MUST be set to False for this listener with the - /// "RefNotPermitted" reason. + /// "InvalidCertificateRef" reason. /// /// This field is required to have at least one element when the mode is set /// to "Terminate" (default) and is optional otherwise. @@ -321,9 +237,11 @@ pub struct GatewayTlsConfig { /// CertificateRefs can reference to standard Kubernetes resources, i.e. /// Secret, or implementation-specific custom resources. /// - /// Support: Core - A single reference to a Kubernetes Secret of type kubernetes.io/tls + /// Support: Core - A single reference to a Kubernetes Secret of type + /// kubernetes.io/tls /// - /// Support: Implementation-specific (More than one reference or other resource types) + /// Support: Implementation-specific (More than one reference or other + /// resource types) pub certificate_refs: Option>, /// Options are a list of key/value pairs to enable extended TLS @@ -422,61 +340,28 @@ pub struct GatewayAddress { /// GatewayStatus defines the observed state of Gateway. #[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema)] pub struct GatewayStatus { - /// Addresses lists the network addresses that have been bound to the - /// Gateway. - /// - /// This list may differ from the addresses provided in the spec under some - /// conditions: - /// - /// * no addresses are specified, all addresses are dynamically assigned - /// * a combination of specified and dynamic addresses are assigned - /// * a specified address was unusable (e.g. already in use) + /// Addresses lists the IP addresses that have actually been bound to the + /// Gateway. These addresses may differ from the addresses in the Spec, e.g. + /// if the Gateway automatically assigns an address from a reserved pool. pub addresses: Option>, /// Conditions describe the current conditions of the Gateway. /// - /// Implementations should prefer to express Gateway conditions - /// using the `GatewayConditionType` and `GatewayConditionReason` - /// constants so that operators and tools can converge on a common - /// vocabulary to describe Gateway state. + /// Implementations should prefer to express Gateway conditions using the + /// `GatewayConditionType` and `GatewayConditionReason` constants so that + /// operators and tools can converge on a common vocabulary to describe + /// Gateway state. /// /// Known condition types are: /// - /// * "Accepted" - /// * "Programmed" + /// * "Scheduled" /// * "Ready" pub conditions: Option>, - /// Listeners provide status for each unique listener port defined in the Spec. + /// Routes is a list of routes bound to the Gateway. pub listeners: Option>, } -/// GatewayInfrastructure defines infrastructure level attributes about a Gateway instance. -#[derive( - Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema, -)] -pub struct GatewayInfrastructure { - /// Labels that SHOULD be applied to any resources created in response to this Gateway. - /// - /// For implementations creating other Kubernetes objects, this should be the `metadata.labels` field on resources. - /// For other implementations, this refers to any relevant (implementation specific) "labels" concepts. - /// - /// An implementation may chose to add additional implementation-specific labels as they see fit. - /// - /// Support: Extended - pub labels: Option>, - - /// Annotations that SHOULD be applied to any resources created in response to this Gateway. - /// - /// For implementations creating other Kubernetes objects, this should be the `metadata.annotations` field on resources. - /// For other implementations, this refers to any relevant (implementation specific) "annotations" concepts. - /// - /// An implementation may chose to add additional implementation-specific annotations as they see fit. - /// - /// Support: Extended - pub annotations: Option>, -} - /// GatewayConditionType is a type of condition associated with a /// Gateway. This type should be used with the GatewayStatus.Conditions /// field. @@ -506,21 +391,6 @@ pub struct ListenerStatus { /// AttachedRoutes represents the total number of Routes that have been /// successfully attached to this Listener. - /// - /// Successful attachment of a Route to a Listener is based solely on the - /// combination of the AllowedRoutes field on the corresponding Listener - /// and the Route's ParentRefs field. A Route is successfully attached to - /// a Listener when it is selected by the Listener's AllowedRoutes field - /// AND the Route has a valid ParentRef selecting the whole Gateway - /// resource or a specific Listener as a parent resource (more detail on - /// attachment semantics can be found in the documentation on the various - /// Route kinds ParentRefs fields). Listener or Route status does not impact - /// successful attachment, i.e. the AttachedRoutes field count MUST be set - /// for Listeners with condition Accepted: false and MUST count successfully - /// attached Routes that may themselves have Accepted: false conditions. - /// - /// Uses for this field include troubleshooting Route attachment and - /// measuring blast radius/impact of changes to a Listener. pub attached_routes: u16, /// Conditions describe the current condition of this listener. diff --git a/src/gatewayclass.rs b/src/gatewayclass.rs index af8ee06..a17d43e 100644 --- a/src/gatewayclass.rs +++ b/src/gatewayclass.rs @@ -1,29 +1,29 @@ use crate::*; use k8s_openapi::apimachinery::pkg::apis::meta::v1 as metav1; -/// GatewayClass describes a class of Gateways available to the user for creating -/// Gateway resources. -/// -/// It is recommended that this resource be used as a template for Gateways. This -/// means that a Gateway is based on the state of the GatewayClass at the time it -/// was created and changes to the GatewayClass or associated parameters are not -/// propagated down to existing Gateways. This recommendation is intended to -/// limit the blast radius of changes to GatewayClass or associated parameters. -/// If implementations choose to propagate GatewayClass changes to existing -/// Gateways, that MUST be clearly documented by the implementation. -/// -/// Whenever one or more Gateways are using a GatewayClass, implementations SHOULD -/// add the `gateway-exists-finalizer.gateway.networking.k8s.io` finalizer on the -/// associated GatewayClass. This ensures that a GatewayClass associated with a -/// Gateway is not deleted while in use. -/// -/// GatewayClass is a Cluster level resource. +// GatewayClass describes a class of Gateways available to the user for creating +// Gateway resources. +// +// It is recommended that this resource be used as a template for Gateways. This +// means that a Gateway is based on the state of the GatewayClass at the time it +// was created and changes to the GatewayClass or associated parameters are not +// propagated down to existing Gateways. This recommendation is intended to +// limit the blast radius of changes to GatewayClass or associated parameters. +// If implementations choose to propagate GatewayClass changes to existing +// Gateways, that MUST be clearly documented by the implementation. +// +// Whenever one or more Gateways are using a GatewayClass, implementations MUST +// add the `gateway-exists-finalizer.gateway.networking.k8s.io` finalizer on the +// associated GatewayClass. This ensures that a GatewayClass associated with a +// Gateway is not deleted while in use. +// +// GatewayClass is a Cluster level resource. #[derive( Clone, Debug, kube::CustomResource, serde::Deserialize, serde::Serialize, schemars::JsonSchema, )] #[kube( group = "gateway.networking.k8s.io", - version = "v1", + version = "v1beta1", kind = "GatewayClass", status = "GatewayClassStatus" )] @@ -35,8 +35,6 @@ pub struct GatewayClassSpec { /// Example: "example.net/gateway-controller". /// /// This field is not mutable and cannot be empty. - /// - /// Support: Core pub controller_name: GatewayController, /// ParametersRef is a reference to a resource that contains the @@ -51,7 +49,7 @@ pub struct GatewayClassSpec { /// If the referent cannot be found, the GatewayClass's "InvalidParameters" /// status condition will be true. /// - /// Support: Implementation-specific + /// Support: Custom pub paramters_ref: Option, /// Description helps describe a GatewayClass with more details. @@ -98,12 +96,4 @@ pub struct GatewayClassStatus { /// Controllers should prefer to publish conditions using values of /// GatewayClassConditionType for the type of each Condition. pub conditions: Option>, - - /// SupportedFeatures is the set of features the GatewayClass support. - /// It MUST be sorted in ascending alphabetical order. - pub supported_features: Option>, } - -/// SupportedFeature is used to describe distinct features that are covered by -/// conformance tests. -pub type SupportedFeature = String; diff --git a/src/httproute.rs b/src/httproute.rs index 973367d..2ee7ac3 100644 --- a/src/httproute.rs +++ b/src/httproute.rs @@ -15,7 +15,7 @@ use crate::*; )] #[kube( group = "gateway.networking.k8s.io", - version = "v1", + version = "v1beta1", kind = "HTTPRoute", root = "HttpRoute", status = "HttpRouteStatus", @@ -26,14 +26,9 @@ pub struct HttpRouteSpec { #[serde(flatten)] pub inner: CommonRouteSpec, - /// Hostnames defines a set of hostnames that should match against the HTTP Host - /// header to select a HTTPRoute used to process the request. Implementations - /// MUST ignore any port value specified in the HTTP Host header while - /// performing a match and (absent of any applicable header modification - /// configuration) MUST forward this header unmodified to the backend. - /// - /// Valid values for Hostnames are determined by RFC 1123 definition of a - /// hostname with 2 notable exceptions: + /// Hostnames defines a set of hostname that should match against the HTTP + /// Host header to select a HTTPRoute to process the request. This matches + /// the RFC 1123 definition of a hostname with 2 notable exceptions: /// /// 1. IPs are not allowed. /// 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard @@ -49,13 +44,8 @@ pub struct HttpRouteSpec { /// * A Listener with `*.example.com` as the hostname matches HTTPRoutes /// that have either not specified any hostnames or have specified at least /// one hostname that matches the Listener hostname. For example, - /// `*.example.com`, `test.example.com`, and `foo.test.example.com` would - /// all match. On the other hand, `example.com` and `test.example.net` would - /// not match. - /// - /// Hostnames that are prefixed with a wildcard label (`*.`) are interpreted - /// as a suffix match. That means that a match for `*.example.com` would match - /// both `test.example.com`, and `foo.test.example.com`, but not `example.com`. + /// `test.example.com` and `*.example.com` would both match. On the other + /// hand, `example.com` and `test.example.net` would not match. /// /// If both the Listener and HTTPRoute have specified hostnames, any /// HTTPRoute hostnames that do not match the Listener hostname MUST be @@ -68,16 +58,6 @@ pub struct HttpRouteSpec { /// implementation must raise an 'Accepted' Condition with a status of /// `False` in the corresponding RouteParentStatus. /// - /// In the event that multiple HTTPRoutes specify intersecting hostnames (e.g. - /// overlapping wildcard matching and exact matching hostnames), precedence must - /// be given to rules from the HTTPRoute with the largest number of: - /// - /// * Characters in a matching non-wildcard hostname. - /// * Characters in a matching hostname. - /// - /// If ties exist across multiple Routes, the matching precedence rules for - /// HTTPRouteMatches takes over. - /// /// Support: Core pub hostnames: Option>, @@ -124,17 +104,15 @@ pub struct HttpRouteRule { /// HTTP request. /// /// Proxy or Load Balancer routing configuration generated from HTTPRoutes - /// MUST prioritize matches based on the following criteria, continuing on - /// ties. Across all rules specified on applicable Routes, precedence must be - /// given to the match having: - /// - /// * "Exact" path match. - /// * "Prefix" path match with largest number of characters. - /// * Method match. - /// * Largest number of header matches. - /// * Largest number of query param matches. + /// MUST prioritize rules based on the following criteria, continuing on + /// ties. Precedence must be given to the the Rule with the largest number + /// of: /// - /// Note: The precedence of RegularExpression path matches are implementation-specific. + /// * Characters in a matching non-wildcard hostname. + /// * Characters in a matching hostname. + /// * Characters in a matching path. + /// * Header matches. + /// * Query param matches. /// /// If ties still exist across multiple Routes, matching precedence MUST be /// determined in order of the following criteria, continuing on ties: @@ -143,37 +121,30 @@ pub struct HttpRouteRule { /// * The Route appearing first in alphabetical order by /// "{namespace}/{name}". /// - /// If ties still exist within an HTTPRoute, matching precedence MUST be granted - /// to the FIRST matching rule (in list order) with a match meeting the above - /// criteria. + /// If ties still exist within the Route that has been given precedence, + /// matching precedence MUST be granted to the first matching rule meeting + /// the above criteria. /// /// When no rules matching a request have been successfully attached to the /// parent a request is coming from, a HTTP 404 status code MUST be returned. pub matches: Option>, - /// Filters define the filters that are applied to requests that match - /// this rule. + /// Filters define the filters that are applied to requests that match this + /// rule. /// /// The effects of ordering of multiple behaviors are currently unspecified. /// This can change in the future based on feedback during the alpha stage. /// - /// Conformance-levels at this level are defined based on the type of filter: + /// Conformance-levels at this level are defined based on the type of + /// filter: /// /// - ALL core filters MUST be supported by all implementations. /// - Implementers are encouraged to support extended filters. /// - Implementation-specific custom filters have no API guarantees across /// implementations. /// - /// Specifying the same filter multiple times is not supported unless explicitly - /// indicated in the filter. - /// - /// All filters are expected to be compatible with each other except for the - /// URLRewrite and RequestRedirect filters, which may not be combined. If an - /// implementation can not support other combinations of filters, they must clearly - /// document that limitation. In cases where incompatible or unsupported - /// filters are specified and cause the `Accepted` condition to be set to status - /// `False`, implementations may use the `IncompatibleFilters` reason to specify - /// this configuration error. + /// Specifying a core filter multiple times has unspecified or custom + /// conformance. /// /// Support: Core pub filters: Option>, @@ -181,80 +152,30 @@ pub struct HttpRouteRule { /// BackendRefs defines the backend(s) where matching requests should be /// sent. /// - /// Failure behavior here depends on how many BackendRefs are specified and - /// how many are invalid. + /// A 500 status code MUST be returned if there are no BackendRefs or + /// filters specified that would result in a response being sent. /// - /// If *all* entries in BackendRefs are invalid, and there are also no filters - /// specified in this route rule, *all* traffic which matches this rule MUST - /// receive a 500 status code. + /// A BackendRef is considered invalid when it refers to: /// - /// See the HTTPBackendRef definition for the rules about what makes a single - /// HTTPBackendRef invalid. + /// * an unknown or unsupported kind of resource + /// * a resource that does not exist + /// * a resource in another namespace when the reference has not been + /// explicitly allowed by a ReferencePolicy (or equivalent concept). /// - /// When a HTTPBackendRef is invalid, 500 status codes MUST be returned for + /// When a BackendRef is invalid, 500 status codes MUST be returned for /// requests that would have otherwise been routed to an invalid backend. If /// multiple backends are specified, and some are invalid, the proportion of /// requests that would otherwise have been routed to an invalid backend /// MUST receive a 500 status code. /// - /// For example, if two backends are specified with equal weights, and one is - /// invalid, 50 percent of traffic must receive a 500. Implementations may - /// choose how that 50 percent is determined. + /// When a BackendRef refers to a Service that has no ready endpoints, it is + /// recommended to return a 503 status code. /// /// Support: Core for Kubernetes Service - /// - /// Support: Extended for Kubernetes ServiceImport - /// - /// Support: Implementation-specific for any other resource + /// Support: Custom for any other resource /// /// Support for weight: Core pub backend_refs: Option>, - - // Timeouts defines the timeouts that can be configured for an HTTP request. - // - // Support: Extended - pub timeouts: Option, -} - -/// HTTPRouteTimeouts defines timeouts that can be configured for an HTTPRoute. -/// Timeout values are represented with Gateway API Duration formatting. -/// Specifying a zero value such as "0s" is interpreted as no timeout. -#[derive( - Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize, schemars::JsonSchema, -)] -#[serde(rename_all = "camelCase")] -pub struct HttpRouteTimeouts { - /// Request specifies the maximum duration for a gateway to respond to an HTTP request. - /// If the gateway has not been able to respond before this deadline is met, the gateway - /// MUST return a timeout error. - /// - /// For example, setting the `rules.timeouts.request` field to the value `10s` in an - /// `HTTPRoute` will cause a timeout if a client request is taking longer than 10 seconds - /// to complete. - /// - /// This timeout is intended to cover as close to the whole request-response transaction - /// as possible although an implementation MAY choose to start the timeout after the entire - /// request stream has been received instead of immediately after the transaction is - /// initiated by the client. - /// - /// When this field is unspecified, request timeout behavior is implementation-specific. - /// - /// Support: Extended - pub request: Option, - - /// BackendRequest specifies a timeout for an individual request from the gateway - /// to a backend. This covers the time from when the request first starts being - /// sent from the gateway to when the full response has been received from the backend. - /// - /// An entire client HTTP transaction with a gateway, covered by the Request timeout, - /// may result in more than one call from the gateway to the destination backend, - /// for example, if automatic retries are supported. - /// - /// Because the Request timeout encompasses the BackendRequest timeout, the value of - /// BackendRequest must be <= the value of Request timeout. - /// - /// Support: Extended - pub backend_request: Option, } /// HTTPRouteMatch defines the predicate used to match requests to a given @@ -289,11 +210,10 @@ pub struct HttpRouteMatch { /// QueryParams specifies HTTP query parameter matchers. Multiple match /// values are ANDed together, meaning, a request must match all the /// specified query parameters to select the route. - /// - /// Support: Extended pub query_params: Option>, /// Method specifies HTTP method matcher. + /// /// When specified, this route will be matched only if the request has the /// specified method. /// @@ -398,8 +318,8 @@ pub type HttpMethod = String; /// HTTPRouteFilter defines processing steps that must be completed during the /// request or response lifecycle. HTTPRouteFilters are meant as an extension -/// point to express processing that may be done in Gateway implementations. Some -/// examples include request or response modification, implementing +/// point to express processing that may be done in Gateway implementations. +/// Some examples include request or response modification, implementing /// authentication strategies, rate-limiting, and traffic shaping. API /// guarantee/conformance is defined based on the type of the filter. /// @@ -414,8 +334,7 @@ pub type HttpMethod = String; /// "Support: Extended" in this package, e.g. "RequestMirror". Implementers /// are encouraged to support extended filters. /// -/// - Implementation-specific: Filters that are defined and supported by -/// specific vendors. +/// - Custom: Filters that are defined and supported by specific vendors. /// In the future, filters showing convergence in behavior across multiple /// implementations will be considered for inclusion in extended or core /// conformance levels. Filter-specific configuration for such filters @@ -455,10 +374,6 @@ pub enum HttpRouteFilter { /// Requests are sent to the specified destination, but responses from /// that destination are ignored. /// - /// This filter can be used multiple times within the same rule. Note that - /// not all implementations will be able to support mirroring to multiple - /// backends. - /// /// Support: Extended #[serde(rename_all = "camelCase")] RequestMirror { @@ -485,8 +400,6 @@ pub enum HttpRouteFilter { /// "networking.example.net"). ExtensionRef MUST NOT be used for core and /// extended filters. /// - /// This filter can be used multiple times within the same rule. - /// /// Support: Implementation-specific #[serde(rename_all = "camelCase")] ExtensionRef { extension_ref: LocalObjectReference }, @@ -588,32 +501,7 @@ pub enum HttpPathModifier { /// ReplacePrefixMatch specifies the value with which to replace the prefix /// match of a request during a rewrite or redirect. For example, a request - /// to "/foo/bar" with a prefix match of "/foo" and a ReplacePrefixMatch - /// of "/xyz" would be modified to "/xyz/bar". - /// - /// Note that this matches the behavior of the PathPrefix match type. This - /// matches full path elements. A path element refers to the list of labels - /// in the path split by the `/` separator. When specified, a trailing `/` is - /// ignored. For example, the paths `/abc`, `/abc/`, and `/abc/def` would all - /// match the prefix `/abc`, but the path `/abcd` would not. - /// - /// ReplacePrefixMatch is only compatible with a `PathPrefix` HTTPRouteMatch. - /// Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in - /// the implementation setting the Accepted Condition for the Route to `status: False`. - /// - /// Request Path | Prefix Match | Replace Prefix | Modified Path - /// -------------|--------------|----------------|---------- - /// /foo/bar | /foo | /xyz | /xyz/bar - /// /foo/bar | /foo | /xyz/ | /xyz/bar - /// /foo/bar | /foo/ | /xyz | /xyz/bar - /// /foo/bar | /foo/ | /xyz/ | /xyz/bar - /// /foo | /foo | /xyz | /xyz - /// /foo/ | /foo | /xyz | /xyz/ - /// /foo/bar | /foo | _empty string_ | /bar - /// /foo/ | /foo | _empty string_ | / - /// /foo | /foo | _empty string_ | / - /// /foo/ | /foo | / | / - /// /foo | /foo | / | / + /// to "/foo/bar" with a prefix match of "/foo" would be modified to "/bar". #[serde(rename_all = "camelCase")] ReplacePrefixMatch { replace_prefix_match: String }, } @@ -629,15 +517,13 @@ pub struct HttpRequestRedirectFilter { /// header in the response. /// When empty, the scheme of the request is used. /// - /// Scheme redirects can affect the port of the redirect, for more information, - /// refer to the documentation for the port field of this filter. - /// /// Support: Extended pub scheme: Option, /// Hostname is the hostname to be used in the value of the `Location` /// header in the response. - /// When empty, the hostname in the `Host` header of the request is used. + /// + /// When empty, the hostname of the request is used. /// /// Support: Core pub hostname: Option, @@ -651,24 +537,7 @@ pub struct HttpRequestRedirectFilter { /// Port is the port to be used in the value of the `Location` /// header in the response. - /// - /// If no port is specified, the redirect port MUST be derived using the - /// following rules: - /// - /// * If redirect scheme is not-empty, the redirect port MUST be the well-known - /// port associated with the redirect scheme. Specifically "http" to port 80 - /// and "https" to port 443. If the redirect scheme does not have a - /// well-known port, the listener port of the Gateway SHOULD be used. - /// * If redirect scheme is empty, the redirect port MUST be the Gateway - /// Listener port. - /// - /// Implementations SHOULD NOT add the port number in the 'Location' - /// header in the following cases: - /// - /// * A Location header that will use HTTP (whether that is determined via - /// the Listener protocol or the Scheme field) _and_ use port 80. - /// * A Location header that will use HTTPS (whether that is determined via - /// the Listener protocol or the Scheme field) _and_ use port 443. + /// When empty, port (if specified) of the request is used. /// /// Support: Extended pub port: Option, @@ -709,17 +578,13 @@ pub struct HttpUrlRewriteFilter { pub struct HttpRequestMirrorFilter { /// BackendRef references a resource where mirrored requests are sent. /// - /// Mirrored requests must be sent only to a single destination endpoint - /// within this BackendRef, irrespective of how many endpoints are present - /// within this BackendRef. - /// /// If the referent cannot be found, this BackendRef is invalid and must be /// dropped from the Gateway. The controller must ensure the "ResolvedRefs" /// condition on the Route status is set to `status: False` and not configure /// this backend in the underlying implementation. /// /// If there is a cross-namespace reference to an *existing* object - /// that is not allowed by a ReferenceGrant, the controller must ensure the + /// that is not allowed by a ReferencePolicy, the controller must ensure the /// "ResolvedRefs" condition on the Route is set to `status: False`, /// with the "RefNotPermitted" reason and not configure this backend in the /// underlying implementation. @@ -728,31 +593,11 @@ pub struct HttpRequestMirrorFilter { /// should be used to provide more detail about the problem. /// /// Support: Extended for Kubernetes Service - /// - /// Support: Implementation-specific for any other resource + /// Support: Custom for any other resource pub backend_ref: BackendObjectReference, } -/// HTTPBackendRef defines how a HTTPRoute forwards a HTTP request. -/// -/// Note that when a namespace different than the local namespace is specified, a -/// ReferenceGrant object is required in the referent namespace to allow that -/// namespace's owner to accept the reference. See the ReferenceGrant -/// documentation for details. -/// -/// When the BackendRef points to a Kubernetes Service, implementations SHOULD -/// honor the appProtocol field if it is set for the target Service Port. -/// -/// Implementations supporting appProtocol SHOULD recognize the Kubernetes -/// Standard Application Protocols defined in KEP-3726. -/// -/// If a Service appProtocol isn't specified, an implementation MAY infer the -/// backend protocol through its own means. Implementations MAY infer the -/// protocol from the Route type referring to the backend Service. -/// -/// If a Route is not able to send traffic to the backend using the specified -/// protocol then the backend is considered invalid. Implementations MUST set the -/// "ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason. +/// HTTPBackendRef defines how a HTTPRoute should forward an HTTP request. #[derive( Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema, )] @@ -760,52 +605,29 @@ pub struct HttpRequestMirrorFilter { pub struct HttpBackendRef { /// BackendRef is a reference to a backend to forward matched requests to. /// - /// A BackendRef can be invalid for the following reasons. In all cases, the - /// implementation MUST ensure the `ResolvedRefs` Condition on the Route - /// is set to `status: False`, with a Reason and Message that indicate - /// what is the cause of the error. - /// - /// A BackendRef is invalid if: + /// If the referent cannot be found, this HTTPBackendRef is invalid and must + /// be dropped from the Gateway. The controller must ensure the + /// "ResolvedRefs" condition on the Route is set to `status: False` and not + /// configure this backend in the underlying implementation. /// - /// * It refers to an unknown or unsupported kind of resource. In this - /// case, the Reason must be set to `InvalidKind` and Message of the - /// Condition must explain which kind of resource is unknown or unsupported. - /// - /// * It refers to a resource that does not exist. In this case, the Reason must - /// be set to `BackendNotFound` and the Message of the Condition must explain - /// which resource does not exist. - /// - /// * It refers a resource in another namespace when the reference has not been - /// explicitly allowed by a ReferenceGrant (or equivalent concept). In this - /// case, the Reason must be set to `RefNotPermitted` and the Message of the - /// Condition must explain which cross-namespace reference is not allowed. - /// - /// * It refers to a Kubernetes Service that has an incompatible appProtocol - /// for the given Route type - /// - /// * The BackendTLSPolicy object is installed in the cluster, a BackendTLSPolicy - /// is present that refers to the Service, and the implementation is unable - /// to meet the requirement. At the time of writing, BackendTLSPolicy is - /// experimental, but once it becomes standard, this will become a MUST - /// requirement. - /// - /// Support: Core for Kubernetes Service - /// - /// Support: Implementation-specific for any other resource - /// - /// Support for weight: Core + /// If there is a cross-namespace reference to an *existing* object + /// that is not covered by a ReferencePolicy, the controller must ensure the + /// "ResolvedRefs" condition on the Route is set to `status: False`, + /// with the "RefNotPermitted" reason and not configure this backend in the + /// underlying implementation. /// - /// Support for Kubernetes Service appProtocol: Extended + /// In either error case, the Message of the `ResolvedRefs` Condition + /// should be used to provide more detail about the problem. /// - /// Support for BackendTLSPolicy: Experimental and ImplementationSpecific + /// Support: Custom #[serde(flatten)] pub backend_ref: Option, /// Filters defined at this level should be executed if and only if the /// request is being forwarded to the backend defined here. /// - /// Support: Implementation-specific (For broader support of filters, use the - /// Filters field in HTTPRouteRule.) + /// Support: Custom (For broader support of filters, use the Filters field + /// in HTTPRouteRule.) pub filters: Option>, } diff --git a/src/lib.rs b/src/lib.rs index 775baf4..80d3d8b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,6 @@ // TODO(ver): We should deny missing_docs, but this doesn't play with // CustomResource derivations. -pub mod duration; mod gateway; mod gatewayclass; mod httproute; diff --git a/src/shared.rs b/src/shared.rs index c94cec3..555daf3 100644 --- a/src/shared.rs +++ b/src/shared.rs @@ -3,14 +3,9 @@ use k8s_openapi::apimachinery::pkg::apis::meta::v1 as metav1; use crate::BackendObjectReference; /// ParentReference identifies an API object (usually a Gateway) that can be considered -/// a parent of this resource (usually a route). There are two kinds of parent resources -/// with "Core" support: -/// -/// * Gateway (Gateway conformance profile) -/// * Service (Mesh conformance profile, experimental, ClusterIP Services only) -/// -/// This API may be extended in the future to support additional kinds of parent -/// resources. +/// a parent of this resource (usually a route). The only kind of parent resource +/// with "Core" support is Gateway. This API may be extended in the future to +/// support additional kinds of parent resources, such as HTTPRoute. /// /// The API object must be valid in the cluster; the Group and Kind must /// be registered in the cluster for this reference to be valid. @@ -20,41 +15,18 @@ use crate::BackendObjectReference; #[serde(rename_all = "camelCase")] pub struct ParentReference { /// Group is the group of the referent. - /// When unspecified, "gateway.networking.k8s.io" is inferred. - /// To set the core API group (such as for a "Service" kind referent), - /// Group must be explicitly set to "" (empty string). /// /// Support: Core pub group: Option, /// Kind is kind of the referent. /// - /// There are two kinds of parent resources with "Core" support: - /// - /// * Gateway (Gateway conformance profile) - /// * Service (Mesh conformance profile, experimental, ClusterIP Services only) - /// - /// Support for other resources is Implementation-Specific. + /// Support: Core (Gateway) + /// Support: Custom (Other Resources) pub kind: Option, - /// Namespace is the namespace of the referent. When unspecified, this refers - /// to the local namespace of the Route. - /// - /// Note that there are specific rules for ParentRefs which cross namespace - /// boundaries. Cross-namespace references are only valid if they are explicitly - /// allowed by something in the namespace they are referring to. For example: - /// Gateway has the AllowedRoutes field, and ReferenceGrant provides a - /// generic way to enable any other kind of cross-namespace reference. - /// - /// ParentRefs from a Route to a Service in the same namespace are "producer" - /// routes, which apply default routing rules to inbound connections from - /// any namespace to the Service. - /// - /// ParentRefs from a Route to a Service in a different namespace are - /// "consumer" routes, and these routing rules are only applied to outbound - /// connections originating from the same namespace as the Route, for which - /// the intended destination of the connections are a Service targeted as a - /// ParentRef of the Route. + /// Namespace is the namespace of the referent. When unspecified (or empty + /// string), this refers to the local namespace of the Route. /// /// Support: Core pub namespace: Option, @@ -70,42 +42,33 @@ pub struct ParentReference { /// * Gateway: Listener Name. When both Port (experimental) and SectionName /// are specified, the name and port of the selected listener must match /// both specified values. - /// * Service: Port Name. When both Port (experimental) and SectionName - /// are specified, the name and port of the selected listener must match - /// both specified values. Note that attaching Routes to Services as Parents - /// is part of experimental Mesh support and is not supported for any other - /// purpose. /// - /// Implementations MAY choose to support attaching Routes to other resources. - /// If that is the case, they MUST clearly document how SectionName is - /// interpreted. + /// Implementations MAY choose to support attaching Routes to other + /// resources. If that is the case, they MUST clearly document how + /// SectionName is interpreted. /// - /// When unspecified (empty string), this will reference the entire resource. - /// For the purpose of status, an attachment is considered successful if at - /// least one section in the parent resource accepts it. For example, Gateway - /// listeners can restrict which Routes can attach to them by Route kind, - /// namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from - /// the referencing Route, the Route MUST be considered successfully - /// attached. If no Gateway listeners accept attachment from this Route, the - /// Route MUST be considered detached from the Gateway. + /// When unspecified (empty string), this will reference the entire + /// resource. For the purpose of status, an attachment is considered + /// successful if at least one section in the parent resource accepts it. + /// For example, Gateway listeners can restrict which Routes can attach to + /// them by Route kind, namespace, or hostname. If 1 of 2 Gateway listeners + /// accept attachment from the referencing Route, the Route MUST be + /// considered successfully attached. If no Gateway listeners accept + /// attachment from this Route, the Route MUST be considered detached from + /// the Gateway. /// /// Support: Core pub section_name: Option, /// Port is the network port this Route targets. It can be interpreted - /// differently based on the type of parent resource. + /// differently based on the type of parent resource: /// - /// When the parent resource is a Gateway, this targets all listeners - /// listening on the specified port that also support this kind of Route(and - /// select this Route). It's not recommended to set `Port` unless the - /// networking behaviors specified in a Route must apply to a specific port - /// as opposed to a listener(s) whose port(s) may be changed. When both Port - /// and SectionName are specified, the name and port of the selected listener - /// must match both specified values. - /// - /// When the parent resource is a Service, this targets a specific port in the - /// Service spec. When both Port (experimental) and SectionName are specified, - /// the name and port of the selected port must match both specified values. + /// * Gateway: All listeners listening on the specified port that also + /// support this kind of Route(and select this Route). It's not recommended + /// to set `Port` unless the networking behaviors specified in a Route must + /// apply to a specific port as opposed to a listener(s) whose port(s) may + /// be changed. When both Port and SectionName are specified, the name and + /// port of the selected listener must match both specified values. /// /// Implementations MAY choose to support other parent resources. /// Implementations supporting other types of parent resources MUST clearly @@ -116,8 +79,8 @@ pub struct ParentReference { /// listeners can restrict which Routes can attach to them by Route kind, /// namespace, or hostname. If 1 of 2 Gateway listeners accept attachment /// from the referencing Route, the Route MUST be considered successfully - /// attached. If no Gateway listeners accept attachment from this Route, - /// the Route MUST be considered detached from the Gateway. + /// attached. If no Gateway listeners accept attachment from this Route, the + /// Route MUST be considered detached from the Gateway. /// /// Support: Extended pub port: Option, @@ -130,65 +93,25 @@ pub struct ParentReference { )] #[serde(rename_all = "camelCase")] pub struct CommonRouteSpec { - /// ParentRefs references the resources (usually Gateways) that a Route wants - /// to be attached to. Note that the referenced parent resource needs to - /// allow this for the attachment to be complete. For Gateways, that means - /// the Gateway needs to allow attachment from Routes of this kind and - /// namespace. For Services, that means the Service must either be in the same - /// namespace for a "producer" route, or the mesh implementation must support - /// and allow "consumer" routes for the referenced Service. ReferenceGrant is - /// not applicable for governing ParentRefs to Services - it is not possible to - /// create a "producer" route for a Service in a different namespace from the - /// Route. - /// - /// There are two kinds of parent resources with "Core" support: - /// - /// * Gateway (Gateway conformance profile) - /// * Service (Mesh conformance profile, experimental, ClusterIP Services only) - /// This API may be extended in the future to support additional kinds of parent - /// resources. - /// - /// ParentRefs must be _distinct_. This means either that: - /// - /// * They select different objects. If this is the case, then parentRef - /// entries are distinct. In terms of fields, this means that the - /// multi-part key defined by `group`, `kind`, `namespace`, and `name` must - /// be unique across all parentRef entries in the Route. - /// * They do not select different objects, but for each optional field used, - /// each ParentRef that selects the same object must set the same set of - /// optional fields to different values. If one ParentRef sets a - /// combination of optional fields, all must set the same combination. - /// - /// Some examples: - /// - /// * If one ParentRef sets `sectionName`, all ParentRefs referencing the - /// same object must also set `sectionName`. - /// * If one ParentRef sets `port`, all ParentRefs referencing the same - /// object must also set `port`. - /// * If one ParentRef sets `sectionName` and `port`, all ParentRefs - /// referencing the same object must also set `sectionName` and `port`. - /// - /// It is possible to separately reference multiple distinct objects that may - /// be collapsed by an implementation. For example, some implementations may - /// choose to merge compatible Gateway Listeners together. If that is the - /// case, the list of routes attached to those resources should also be + /// ParentRefs references the resources (usually Gateways) that a Route + /// wants to be attached to. Note that the referenced parent resource needs + /// to allow this for the attachment to be complete. For Gateways, that + /// means the Gateway needs to allow attachment from Routes of this kind and + /// namespace. + /// + /// The only kind of parent resource with "Core" support is Gateway. This + /// API may be extended in the future to support additional kinds of parent + /// resources such as one of the route kinds. + /// + /// It is invalid to reference an identical parent more than once. It is + /// valid to reference multiple distinct sections within the same parent + /// resource, such as 2 Listeners within a Gateway. + /// + /// It is possible to separately reference multiple distinct objects that + /// may be collapsed by an implementation. For example, some implementations + /// may choose to merge compatible Gateway Listeners together. If that is + /// the case, the list of routes attached to those resources should also be /// merged. - /// - /// Note that for ParentRefs that cross namespace boundaries, there are specific - /// rules. Cross-namespace references are only valid if they are explicitly - /// allowed by something in the namespace they are referring to. For example, - /// Gateway has the AllowedRoutes field, and ReferenceGrant provides a - /// generic way to enable other kinds of cross-namespace reference. - /// - /// ParentRefs from a Route to a Service in the same namespace are "producer" - /// routes, which apply default routing rules to inbound connections from - /// any namespace to the Service. - /// - /// ParentRefs from a Route to a Service in a different namespace are - /// "consumer" routes, and these routing rules are only applied to outbound - /// connections originating from the same namespace as the Route, for which - /// the intended destination of the connections are a Service targeted as a - /// ParentRef of the Route. pub parent_refs: Option>, } @@ -198,28 +121,9 @@ pub type PortNumber = u16; /// BackendRef defines how a Route should forward a request to a Kubernetes /// resource. /// -/// Note that when a namespace different than the local namespace is specified, a -/// ReferenceGrant object is required in the referent namespace to allow that -/// namespace's owner to accept the reference. See the ReferenceGrant -/// documentation for details. -/// -/// When the BackendRef points to a Kubernetes Service, implementations SHOULD -/// honor the appProtocol field if it is set for the target Service Port. -/// -/// Implementations supporting appProtocol SHOULD recognize the Kubernetes -/// Standard Application Protocols defined in KEP-3726. -/// -/// If a Service appProtocol isn't specified, an implementation MAY infer the -/// backend protocol through its own means. Implementations MAY infer the -/// protocol from the Route type referring to the backend Service. -/// -/// If a Route is not able to send traffic to the backend using the specified -/// protocol then the backend is considered invalid. Implementations MUST set the -/// "ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason. -/// -/// Note that when the BackendTLSPolicy object is enabled by the implementation, -/// there are some extra rules about validity to consider here. See the fields -/// where this struct is used for more information about the exact behavior. +/// Note that when a namespace is specified, a ReferencePolicy object is +/// required in the referent namespace to allow that namespace's owner to accept +/// the reference. See the ReferencePolicy documentation for details. #[derive( Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, schemars::JsonSchema, )] @@ -231,9 +135,9 @@ pub struct BackendRef { /// implementation supports. Weight is not a percentage and the sum of /// weights does not need to equal 100. /// - /// If only one backend is specified and it has a weight greater than 0, 100% - /// of the traffic is forwarded to that backend. If weight is set to 0, no - /// traffic should be forwarded for this entry. If unspecified, weight + /// If only one backend is specified and it has a weight greater than 0, + /// 100% of the traffic is forwarded to that backend. If weight is set to 0, + /// no traffic should be forwarded for this entry. If unspecified, weight /// defaults to 1. /// /// Support for this field varies based on the context where used. @@ -275,25 +179,25 @@ pub struct RouteParentStatus { /// [names]: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names pub controller_name: GatewayController, - /// Conditions describes the status of the route with respect to the Gateway. - /// Note that the route's availability is also subject to the Gateway's own - /// status conditions and listener status. + /// Conditions describes the status of the route with respect to the + /// Gateway. Note that the route's availability is also subject to the + /// Gateway's own status conditions and listener status. /// /// If the Route's ParentRef specifies an existing Gateway that supports /// Routes of this kind AND that Gateway's controller has sufficient access, /// then that Gateway's controller MUST set the "Accepted" condition on the - /// Route, to indicate whether the route has been accepted or rejected by the - /// Gateway, and why. + /// Route, to indicate whether the route has been accepted or rejected by + /// the Gateway, and why. /// /// A Route MUST be considered "Accepted" if at least one of the Route's /// rules is implemented by the Gateway. /// - /// There are a number of cases where the "Accepted" condition may not be set - /// due to lack of controller visibility, that includes when: + /// There are a number of cases where the "Accepted" condition may not be + /// set due to lack of controller visibility, that includes when: /// /// * The Route refers to a non-existent parent. /// * The Route is of a type that the controller does not support. - /// * The Route is in a namespace the controller does not have access to. + /// * The Route is in a namespace the the controller does not have access to. pub conditions: Vec, } @@ -448,17 +352,4 @@ pub type AnnotationKey = String; pub type AnnotationValue = String; /// AddressType defines how a network address is represented as a text string. -/// This may take two possible forms: -/// -/// * A predefined CamelCase string identifier (currently limited to `IPAddress` or `Hostname`) -/// * A domain-prefixed string identifier (like `acme.io/CustomAddressType`) -/// -/// Values `IPAddress` and `Hostname` have Extended support. -/// -/// The `NamedAddress` value has been deprecated in favor of implementation -/// specific domain-prefixed strings. -/// -/// All other values, including domain-prefixed values have Implementation-specific support, -/// which are used in implementation-specific behaviors. Support for additional -/// predefined CamelCase identifiers may be added in future releases. pub type AddressType = String;