From 0ff731831f50dd39fa1e01e61ff8162cfb7a7faf Mon Sep 17 00:00:00 2001 From: Peter Sprygada Date: Tue, 13 Oct 2026 15:12:41 -0400 Subject: [PATCH] refactor(api)!: Rename NetworkRule to NetworkService The object describes a load-balanced ingress service on a VIP and port with selected backends, not a rule, so the kind now says that. Fields, JSON keys, validation and behaviour are unchanged; only names change. There is no alias, conversion or deprecated copy, since v1alpha1 makes no compatibility promise. The Go types follow the kind: NetworkServiceSpec, NetworkServiceStatus, NetworkServiceList, and NetworkServiceProtocol with its TCP and UDP constants, which ServiceRoute and ServiceVIPBinding also use. Doc comments that called the object a rule now call it a service; CEL validation rules keep the word. The sample, the backend-selector e2e test, the crd-ref-docs allow-list and the generated CRD and API docs are renamed with it, and the networkrules CRD file is removed. network-services-operator defines a NetworkService kind too, in networking.datumapis.com. Its CRD reaches only the Milo control plane, and this repo's CRDs reach only edge cells, so no cluster serves both plurals. BREAKING CHANGE: the NetworkRule kind (networkrules.network.datumapis.com, short name netrule) is replaced by NetworkService (networkservices.network.datumapis.com, short name netsvc). Existing NetworkRule objects are not migrated. Co-Authored-By: Claude Opus 5.5 --- .crd-ref-docs.yaml | 8 +- AGENTS.md | 2 +- api/v1alpha1/egresspolicy_types.go | 4 +- api/v1alpha1/gateway_types.go | 4 +- ...{rule_types.go => networkservice_types.go} | 60 +++++++-------- ...s_test.go => networkservice_types_test.go} | 70 +++++++++--------- api/v1alpha1/serviceroute_types.go | 4 +- api/v1alpha1/serviceroute_types_test.go | 2 +- api/v1alpha1/vipbinding_types.go | 10 +-- api/v1alpha1/zz_generated.deepcopy.go | 38 +++++----- config/crd/kustomization.yaml | 2 +- ...k.datumapis.com_networkegresspolicies.yaml | 4 +- ...network.datumapis.com_networkgateways.yaml | 4 +- ...etwork.datumapis.com_networkservices.yaml} | 36 ++++----- ...work.datumapis.com_servicevipbindings.yaml | 8 +- ...apis.com_v1alpha1_networkservice_tcp.yaml} | 2 +- docs/api/bgp.md | 8 +- docs/api/gateway.md | 74 +++++++++---------- docs/api/index.md | 2 +- templates/api-index.md | 2 +- .../chainsaw-test.yaml | 38 +++++----- 21 files changed, 191 insertions(+), 191 deletions(-) rename api/v1alpha1/{rule_types.go => networkservice_types.go} (72%) rename api/v1alpha1/{rule_types_test.go => networkservice_types_test.go} (66%) rename config/crd/{network.datumapis.com_networkrules.yaml => network.datumapis.com_networkservices.yaml} (92%) rename config/samples/{network.datumapis.com_v1alpha1_networkrule_tcp.yaml => network.datumapis.com_v1alpha1_networkservice_tcp.yaml} (92%) rename test/e2e/tests/{networkrule-backend-selector => networkservice-backend-selector}/chainsaw-test.yaml (83%) diff --git a/.crd-ref-docs.yaml b/.crd-ref-docs.yaml index 67665b2..fa52002 100644 --- a/.crd-ref-docs.yaml +++ b/.crd-ref-docs.yaml @@ -5,10 +5,10 @@ processor: - "NetworkGateway" - "NetworkGatewaySpec" - "NetworkGatewayStatus" - - "NetworkRule" - - "NetworkRuleProtocol" - - "NetworkRuleSpec" - - "NetworkRuleStatus" + - "NetworkService" + - "NetworkServiceProtocol" + - "NetworkServiceSpec" + - "NetworkServiceStatus" - "NetworkEgressPolicy" - "NetworkEgressPolicySpec" - "NetworkEgressPolicyStatus" diff --git a/AGENTS.md b/AGENTS.md index b743183..dfc8b6e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -40,7 +40,7 @@ All dev tools (golangci-lint, controller-gen, chainsaw, yamlfmt) are installed l | Group | Version | Resources | |--------------------|------------|---------------------------------------------------------------------------| -| `network.datumapis.com` | `v1alpha1` | BGPRouter, BGPPeer, BGPAdvertisement, BGPPolicy, BGPVRFInstance, NetworkGateway, NetworkRule | +| `network.datumapis.com` | `v1alpha1` | BGPRouter, BGPPeer, BGPAdvertisement, BGPPolicy, BGPVRFInstance, NetworkGateway, NetworkService | Source lives in `api/v1alpha1/`. Each resource has its own `*_types.go` file; shared types (RouterTarget, AddressFamily, etc.) live in `shared_types.go`. diff --git a/api/v1alpha1/egresspolicy_types.go b/api/v1alpha1/egresspolicy_types.go index 8629c5c..0885acd 100644 --- a/api/v1alpha1/egresspolicy_types.go +++ b/api/v1alpha1/egresspolicy_types.go @@ -6,14 +6,14 @@ import ( // NetworkEgressPolicy enables internet egress for a single tenant // VPC/VPCAttachment, served by the sharded, stateful galactic-nat tier -// (see EgressShard). Unlike NetworkRule, it carries no VIP/backend/port: +// (see EgressShard). Unlike NetworkService, it carries no VIP/backend/port: // egress is on or off for a (vpcRef, vpcAttachmentRef) pair, // existence-implies-enabled, not a per-flow rule — because the destination // of an egress flow is an arbitrary internet address, not a pre-configured // backend list. // // It is namespaced (deployed to galactic-system) and tenant-writable; like -// NetworkRule's vpcRef, vpcRef/vpcAttachmentRef are opaque string identifiers +// NetworkService's vpcRef, vpcRef/vpcAttachmentRef are opaque string identifiers // because the VPC API is owned by a separate companion operator, not this // repo. An admission webhook (implemented by the consuming controller) must // verify the requester is authorized for vpcRef/vpcAttachmentRef before a diff --git a/api/v1alpha1/gateway_types.go b/api/v1alpha1/gateway_types.go index fcb53b0..3729095 100644 --- a/api/v1alpha1/gateway_types.go +++ b/api/v1alpha1/gateway_types.go @@ -8,8 +8,8 @@ import ( // Maglev/DSR consistent-hash L4 load-balancer engine. Exactly one // NetworkGateway exists per gateway node (spec.targetRef.name is the // Kubernetes node name), mirroring the BGPRouter node-scoped root object -// pattern. NetworkRule resources are served by every NetworkGateway in the -// namespace equally (anycast — see NetworkRuleStatus's doc comment); this +// pattern. NetworkService resources are served by every NetworkGateway in the +// namespace equally (anycast — see NetworkServiceStatus's doc comment); this // object's only job is to identify which nodes participate at all and // surface each node's engine health via Conditions. // diff --git a/api/v1alpha1/rule_types.go b/api/v1alpha1/networkservice_types.go similarity index 72% rename from api/v1alpha1/rule_types.go rename to api/v1alpha1/networkservice_types.go index 7b62eb2..20e9cc4 100644 --- a/api/v1alpha1/rule_types.go +++ b/api/v1alpha1/networkservice_types.go @@ -4,21 +4,21 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// NetworkRuleProtocol is the transport protocol matched by a NetworkRule's +// NetworkServiceProtocol is the transport protocol matched by a NetworkService's // ingress VIP. // // +kubebuilder:validation:Enum=tcp;udp -type NetworkRuleProtocol string +type NetworkServiceProtocol string const ( - // NetworkRuleProtocolTCP matches TCP traffic. - NetworkRuleProtocolTCP NetworkRuleProtocol = "tcp" + // NetworkServiceProtocolTCP matches TCP traffic. + NetworkServiceProtocolTCP NetworkServiceProtocol = "tcp" - // NetworkRuleProtocolUDP matches UDP traffic. - NetworkRuleProtocolUDP NetworkRuleProtocol = "udp" + // NetworkServiceProtocolUDP matches UDP traffic. + NetworkServiceProtocolUDP NetworkServiceProtocol = "udp" ) -// Accepted reasons — used as Accepted.Reason on NetworkRule (and reused by +// Accepted reasons — used as Accepted.Reason on NetworkService (and reused by // NetworkEgressPolicy), set by the admission webhook that verifies the // requester is authorized for the VPC resources the object references. const ( @@ -32,58 +32,58 @@ const ( AcceptedReasonOwnershipDenied string = "OwnershipDenied" ) -// NetworkRule defines ingress load-balancing for a single tenant VPC, served +// NetworkService defines ingress load-balancing for a single tenant VPC, served // by every NetworkGateway node identically (anycast Direct Server Return — // see NetworkGateway's doc comment). It is namespaced (deployed to // galactic-system) and tenant-writable; vpcRef is an opaque string identifier // because the VPC API is owned by a separate companion operator, not this // repo. An admission webhook (implemented by the consuming controller) must -// verify the requester is authorized for vpcRef before a rule is accepted — +// verify the requester is authorized for vpcRef before a service is accepted — // see the Accepted condition. // // Unlike the earlier Full-NAT design this type originally described, there -// is no primary/secondary gateway node for a rule: every NetworkGateway -// advertises every accepted rule's vipAddresses at equal BGP preference, +// is no primary/secondary gateway node for a service: every NetworkGateway +// advertises every accepted service's vipAddresses at equal BGP preference, // consistent-hashes the same backend list to the same backend for the same // flow (internal/maglev), and forwards without rewriting anything — // backend selection never needs a single "owning" node the way Full-NAT's // SNAT-source model did. // // Backends are not listed. BackendSelector picks the VPCAttachments that -// serve the rule, so the backend set follows attachments as they are +// serve the service, so the backend set follows attachments as they are // created, deleted or moved to another node, and galactic-router on each // node generates the ServiceVIPBinding its backends need from the same // selection. // // +kubebuilder:object:root=true // +kubebuilder:subresource:status -// +kubebuilder:resource:scope=Namespaced,shortName=netrule +// +kubebuilder:resource:scope=Namespaced,shortName=netsvc // +kubebuilder:printcolumn:name="VPC",type="string",JSONPath=".spec.vpcRef" // +kubebuilder:printcolumn:name="PROTOCOL",type="string",JSONPath=".spec.protocol" // +kubebuilder:printcolumn:name="PORT",type="integer",JSONPath=".spec.port" // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" -type NetworkRule struct { +type NetworkService struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec NetworkRuleSpec `json:"spec,omitempty"` - Status NetworkRuleStatus `json:"status,omitempty"` + Spec NetworkServiceSpec `json:"spec,omitempty"` + Status NetworkServiceStatus `json:"status,omitempty"` } -// NetworkRuleSpec defines the desired ingress load-balancing state for a +// NetworkServiceSpec defines the desired ingress load-balancing state for a // tenant VPC. -type NetworkRuleSpec struct { - // VPCRef is the opaque identifier of the target VPC this rule applies +type NetworkServiceSpec struct { + // VPCRef is the opaque identifier of the target VPC this service applies // to. This repo does not own the VPC API and does not validate the // identifier beyond non-emptiness; the admission webhook of the // consuming controller is responsible for verifying the requester is - // authorized for this VPC before the rule is accepted. + // authorized for this VPC before the service is accepted. // +kubebuilder:validation:Required // +kubebuilder:validation:MinLength=1 VPCRef string `json:"vpcRef"` // VIPAddresses is the list of ingress VIP addresses (IPv4 and/or IPv6) - // this rule provisions on the assigned gateway node(s). + // this service provisions on the assigned gateway node(s). // +kubebuilder:validation:Required // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=8 @@ -94,16 +94,16 @@ type NetworkRuleSpec struct { // Protocol is the transport protocol matched by VIPAddresses/Port. // +kubebuilder:validation:Required - Protocol NetworkRuleProtocol `json:"protocol"` + Protocol NetworkServiceProtocol `json:"protocol"` - // Port is the ingress port on VIPAddresses that this rule load-balances. + // Port is the ingress port on VIPAddresses that this service load-balances. // +kubebuilder:validation:Required // +kubebuilder:validation:Minimum=1 // +kubebuilder:validation:Maximum=65535 Port int32 `json:"port"` // BackendSelector selects the VPCAttachments (cloud.datumapis.com/v1alpha1, - // in any namespace) that serve this rule, matched against each + // in any namespace) that serve this service, matched against each // VPCAttachment object's own labels. Only attachments whose status.vpc // equals VPCRef are candidates, whatever their labels, so a selector cannot // reach into another tenant's VPC. Each selected attachment contributes the @@ -123,8 +123,8 @@ type NetworkRuleSpec struct { BackendPort int32 `json:"backendPort"` } -// NetworkRuleStatus defines the observed state of a NetworkRule. -type NetworkRuleStatus struct { +// NetworkServiceStatus defines the observed state of a NetworkService. +type NetworkServiceStatus struct { // ObservedGeneration is the .metadata.generation this status was computed from. // +optional ObservedGeneration int64 `json:"observedGeneration,omitempty"` @@ -137,14 +137,14 @@ type NetworkRuleStatus struct { Conditions []metav1.Condition `json:"conditions,omitempty"` } -// NetworkRuleList is a list of NetworkRule resources. +// NetworkServiceList is a list of NetworkService resources. // +kubebuilder:object:root=true -type NetworkRuleList struct { +type NetworkServiceList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []NetworkRule `json:"items"` + Items []NetworkService `json:"items"` } func init() { - SchemeBuilder.Register(&NetworkRule{}, &NetworkRuleList{}) + SchemeBuilder.Register(&NetworkService{}, &NetworkServiceList{}) } diff --git a/api/v1alpha1/rule_types_test.go b/api/v1alpha1/networkservice_types_test.go similarity index 66% rename from api/v1alpha1/rule_types_test.go rename to api/v1alpha1/networkservice_types_test.go index f0fca19..8e438b6 100644 --- a/api/v1alpha1/rule_types_test.go +++ b/api/v1alpha1/networkservice_types_test.go @@ -7,17 +7,17 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func newTestRule() *NetworkRule { - return &NetworkRule{ +func newTestService() *NetworkService { + return &NetworkService{ TypeMeta: metav1.TypeMeta{ APIVersion: "network.datumapis.com/v1alpha1", - Kind: "NetworkRule", + Kind: "NetworkService", }, - ObjectMeta: metav1.ObjectMeta{Name: "test-rule", Namespace: "galactic-system"}, - Spec: NetworkRuleSpec{ + ObjectMeta: metav1.ObjectMeta{Name: "test-service", Namespace: "galactic-system"}, + Spec: NetworkServiceSpec{ VPCRef: "vpc-a", VIPAddresses: []string{"2001:db8:1::10"}, - Protocol: NetworkRuleProtocolTCP, + Protocol: NetworkServiceProtocolTCP, Port: 443, BackendSelector: metav1.LabelSelector{ MatchLabels: map[string]string{"app": "web"}, @@ -27,10 +27,10 @@ func newTestRule() *NetworkRule { } } -// TestNetworkRuleDeepCopy verifies that DeepCopy produces an independent +// TestNetworkServiceDeepCopy verifies that DeepCopy produces an independent // copy: mutations to slices in the copy must not affect the original. -func TestNetworkRuleDeepCopy(t *testing.T) { - orig := newTestRule() +func TestNetworkServiceDeepCopy(t *testing.T) { + orig := newTestService() dup := orig.DeepCopy() dup.Spec.VIPAddresses[0] = "2001:db8:1::20" @@ -44,18 +44,18 @@ func TestNetworkRuleDeepCopy(t *testing.T) { } } -// TestNetworkRuleDeepCopyNil verifies DeepCopy on a nil pointer returns nil. -func TestNetworkRuleDeepCopyNil(t *testing.T) { - var r *NetworkRule +// TestNetworkServiceDeepCopyNil verifies DeepCopy on a nil pointer returns nil. +func TestNetworkServiceDeepCopyNil(t *testing.T) { + var r *NetworkService if r.DeepCopy() != nil { t.Error("DeepCopy on nil pointer should return nil") } } -// TestNetworkRuleJSONRoundTrip verifies that the struct serialises and +// TestNetworkServiceJSONRoundTrip verifies that the struct serialises and // deserialises through JSON without data loss. -func TestNetworkRuleJSONRoundTrip(t *testing.T) { - orig := newTestRule() +func TestNetworkServiceJSONRoundTrip(t *testing.T) { + orig := newTestService() orig.Spec.BackendSelector.MatchExpressions = []metav1.LabelSelectorRequirement{ {Key: "tier", Operator: metav1.LabelSelectorOpIn, Values: []string{"frontend"}}, } @@ -68,7 +68,7 @@ func TestNetworkRuleJSONRoundTrip(t *testing.T) { t.Fatalf("Marshal: %v", err) } - var got NetworkRule + var got NetworkService if err := json.Unmarshal(data, &got); err != nil { t.Fatalf("Unmarshal: %v", err) } @@ -87,11 +87,11 @@ func TestNetworkRuleJSONRoundTrip(t *testing.T) { } } -// TestNetworkRuleListDeepCopy verifies that NetworkRuleList.DeepCopy +// TestNetworkServiceListDeepCopy verifies that NetworkServiceList.DeepCopy // produces independent copies of each item. -func TestNetworkRuleListDeepCopy(t *testing.T) { - list := &NetworkRuleList{ - Items: []NetworkRule{*newTestRule()}, +func TestNetworkServiceListDeepCopy(t *testing.T) { + list := &NetworkServiceList{ + Items: []NetworkService{*newTestService()}, } copied := list.DeepCopy() copied.Items[0].Spec.VPCRef = "vpc-b" @@ -101,12 +101,12 @@ func TestNetworkRuleListDeepCopy(t *testing.T) { } } -// TestNetworkRuleStatusHasNoPrimaryNode is a regression test: the earlier -// active-passive Full-NAT design assigned a single primaryNode per rule. -// This design's anycast/DSR model has every NetworkGateway serve every rule +// TestNetworkServiceStatusHasNoPrimaryNode is a regression test: the earlier +// active-passive Full-NAT design assigned a single primaryNode per service. +// This design's anycast/DSR model has every NetworkGateway serve every service // identically, so no such field should exist any more. -func TestNetworkRuleStatusHasNoPrimaryNode(t *testing.T) { - orig := newTestRule() +func TestNetworkServiceStatusHasNoPrimaryNode(t *testing.T) { + orig := newTestService() orig.Status.Conditions = []metav1.Condition{{Type: ConditionTypeAccepted}} data, err := json.Marshal(orig.Status) @@ -124,11 +124,11 @@ func TestNetworkRuleStatusHasNoPrimaryNode(t *testing.T) { } } -// TestNetworkRuleBackendFieldNames verifies the JSON keys for the backend +// TestNetworkServiceBackendFieldNames verifies the JSON keys for the backend // selection fields match the CRD schema, and that the static backend list // they replaced is gone. -func TestNetworkRuleBackendFieldNames(t *testing.T) { - data, err := json.Marshal(newTestRule().Spec) +func TestNetworkServiceBackendFieldNames(t *testing.T) { + data, err := json.Marshal(newTestService().Spec) if err != nil { t.Fatalf("Marshal: %v", err) } @@ -147,13 +147,13 @@ func TestNetworkRuleBackendFieldNames(t *testing.T) { } } -// TestNetworkRuleProtocolValues is a regression test pinning the accepted -// NetworkRuleProtocol enum values. -func TestNetworkRuleProtocolValues(t *testing.T) { - if NetworkRuleProtocolTCP != "tcp" { - t.Errorf("NetworkRuleProtocolTCP: got %q, want %q", NetworkRuleProtocolTCP, "tcp") +// TestNetworkServiceProtocolValues is a regression test pinning the accepted +// NetworkServiceProtocol enum values. +func TestNetworkServiceProtocolValues(t *testing.T) { + if NetworkServiceProtocolTCP != "tcp" { + t.Errorf("NetworkServiceProtocolTCP: got %q, want %q", NetworkServiceProtocolTCP, "tcp") } - if NetworkRuleProtocolUDP != "udp" { - t.Errorf("NetworkRuleProtocolUDP: got %q, want %q", NetworkRuleProtocolUDP, "udp") + if NetworkServiceProtocolUDP != "udp" { + t.Errorf("NetworkServiceProtocolUDP: got %q, want %q", NetworkServiceProtocolUDP, "udp") } } diff --git a/api/v1alpha1/serviceroute_types.go b/api/v1alpha1/serviceroute_types.go index 85451b5..2ae877c 100644 --- a/api/v1alpha1/serviceroute_types.go +++ b/api/v1alpha1/serviceroute_types.go @@ -40,7 +40,7 @@ type ServiceEndpointSpec struct { // Protocol is the transport protocol accepted by the endpoint. // +kubebuilder:validation:Required - Protocol NetworkRuleProtocol `json:"protocol"` + Protocol NetworkServiceProtocol `json:"protocol"` // DeliveryMode defines how a backing attachment is selected relative to a // consumer. PreferNodeLocal uses a ready attachment on the consumer's node @@ -198,7 +198,7 @@ type ServiceRouteFrontend struct { type ServiceRouteProtocolPort struct { // Protocol is the transport protocol. // +kubebuilder:validation:Required - Protocol NetworkRuleProtocol `json:"protocol"` + Protocol NetworkServiceProtocol `json:"protocol"` // Port is the transport port. // +kubebuilder:validation:Required diff --git a/api/v1alpha1/serviceroute_types_test.go b/api/v1alpha1/serviceroute_types_test.go index 7876bab..b1cc5f0 100644 --- a/api/v1alpha1/serviceroute_types_test.go +++ b/api/v1alpha1/serviceroute_types_test.go @@ -12,7 +12,7 @@ func TestServiceRoutePolicyDeepCopy(t *testing.T) { Spec: ServiceRoutePolicySpec{ ServiceRef: ServiceEndpointReference{Name: "ipv6-egress-dns"}, AttachmentSelector: metav1.LabelSelector{MatchLabels: map[string]string{"egress": "enabled"}}, - ProtocolPorts: []ServiceRouteProtocolPort{{Protocol: NetworkRuleProtocolUDP, Port: 53}}, + ProtocolPorts: []ServiceRouteProtocolPort{{Protocol: NetworkServiceProtocolUDP, Port: 53}}, Region: "us-central-1", }, Status: ServiceRoutePolicyStatus{Conditions: []metav1.Condition{{Type: "Accepted"}}}, diff --git a/api/v1alpha1/vipbinding_types.go b/api/v1alpha1/vipbinding_types.go index 08f8541..ad2654d 100644 --- a/api/v1alpha1/vipbinding_types.go +++ b/api/v1alpha1/vipbinding_types.go @@ -9,9 +9,9 @@ import ( // specific local backend must be reachable on, so the backend can reply to // clients directly (the "Direct Server Return" this design depends on — // see NetworkGateway's doc comment). Generated, never written by users: -// galactic-router on each worker node writes one object per (rule, VIP, -// backend) for every backend a NetworkRule's BackendSelector places on that -// node, owned by the rule, and the same process's per-node reconciler +// galactic-router on each worker node writes one object per (service, VIP, +// backend) for every backend a NetworkService's BackendSelector places on that +// node, owned by the service, and the same process's per-node reconciler // consumes it. // // EgressKind decides which of two backend mechanisms this object drives, @@ -78,7 +78,7 @@ type ServiceVIPBindingSpec struct { TargetRef TargetRef `json:"targetRef"` // VPCRef is the opaque identifier of the VPC the backend belongs to, - // copied from the owning NetworkRule. It names the tenant VRF the + // copied from the owning NetworkService. It names the tenant VRF the // binding's translation rows are written for, so two tenants using the // same backend address on one node never share a row. // +kubebuilder:validation:Required @@ -98,7 +98,7 @@ type ServiceVIPBindingSpec struct { // Protocol is the transport protocol this binding applies to. // +kubebuilder:validation:Required - Protocol NetworkRuleProtocol `json:"protocol"` + Protocol NetworkServiceProtocol `json:"protocol"` // BackendAddress is the backend's own real address (its pod-netns // address for a veth backend, or its actual guest-facing address for a diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 1ca08dc..74d2d5a 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1632,7 +1632,7 @@ func (in *NetworkGatewayStatus) DeepCopy() *NetworkGatewayStatus { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkRule) DeepCopyInto(out *NetworkRule) { +func (in *NetworkService) DeepCopyInto(out *NetworkService) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -1640,18 +1640,18 @@ func (in *NetworkRule) DeepCopyInto(out *NetworkRule) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkRule. -func (in *NetworkRule) DeepCopy() *NetworkRule { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkService. +func (in *NetworkService) DeepCopy() *NetworkService { if in == nil { return nil } - out := new(NetworkRule) + out := new(NetworkService) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NetworkRule) DeepCopyObject() runtime.Object { +func (in *NetworkService) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1659,31 +1659,31 @@ func (in *NetworkRule) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkRuleList) DeepCopyInto(out *NetworkRuleList) { +func (in *NetworkServiceList) DeepCopyInto(out *NetworkServiceList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]NetworkRule, len(*in)) + *out = make([]NetworkService, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkRuleList. -func (in *NetworkRuleList) DeepCopy() *NetworkRuleList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkServiceList. +func (in *NetworkServiceList) DeepCopy() *NetworkServiceList { if in == nil { return nil } - out := new(NetworkRuleList) + out := new(NetworkServiceList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NetworkRuleList) DeepCopyObject() runtime.Object { +func (in *NetworkServiceList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1691,7 +1691,7 @@ func (in *NetworkRuleList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkRuleSpec) DeepCopyInto(out *NetworkRuleSpec) { +func (in *NetworkServiceSpec) DeepCopyInto(out *NetworkServiceSpec) { *out = *in if in.VIPAddresses != nil { in, out := &in.VIPAddresses, &out.VIPAddresses @@ -1701,18 +1701,18 @@ func (in *NetworkRuleSpec) DeepCopyInto(out *NetworkRuleSpec) { in.BackendSelector.DeepCopyInto(&out.BackendSelector) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkRuleSpec. -func (in *NetworkRuleSpec) DeepCopy() *NetworkRuleSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkServiceSpec. +func (in *NetworkServiceSpec) DeepCopy() *NetworkServiceSpec { if in == nil { return nil } - out := new(NetworkRuleSpec) + out := new(NetworkServiceSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NetworkRuleStatus) DeepCopyInto(out *NetworkRuleStatus) { +func (in *NetworkServiceStatus) DeepCopyInto(out *NetworkServiceStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions @@ -1723,12 +1723,12 @@ func (in *NetworkRuleStatus) DeepCopyInto(out *NetworkRuleStatus) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkRuleStatus. -func (in *NetworkRuleStatus) DeepCopy() *NetworkRuleStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkServiceStatus. +func (in *NetworkServiceStatus) DeepCopy() *NetworkServiceStatus { if in == nil { return nil } - out := new(NetworkRuleStatus) + out := new(NetworkServiceStatus) in.DeepCopyInto(out) return out } diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index c8fc66f..d2456a8 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -10,7 +10,7 @@ resources: - network.datumapis.com_egressshards.yaml - network.datumapis.com_networkegresspolicies.yaml - network.datumapis.com_networkgateways.yaml - - network.datumapis.com_networkrules.yaml + - network.datumapis.com_networkservices.yaml - network.datumapis.com_servicevipbindings.yaml - network.datumapis.com_serviceendpoints.yaml - network.datumapis.com_serviceroutepolicies.yaml diff --git a/config/crd/network.datumapis.com_networkegresspolicies.yaml b/config/crd/network.datumapis.com_networkegresspolicies.yaml index 4b6044b..f5bb35e 100644 --- a/config/crd/network.datumapis.com_networkegresspolicies.yaml +++ b/config/crd/network.datumapis.com_networkegresspolicies.yaml @@ -32,14 +32,14 @@ spec: description: |- NetworkEgressPolicy enables internet egress for a single tenant VPC/VPCAttachment, served by the sharded, stateful galactic-nat tier - (see EgressShard). Unlike NetworkRule, it carries no VIP/backend/port: + (see EgressShard). Unlike NetworkService, it carries no VIP/backend/port: egress is on or off for a (vpcRef, vpcAttachmentRef) pair, existence-implies-enabled, not a per-flow rule — because the destination of an egress flow is an arbitrary internet address, not a pre-configured backend list. It is namespaced (deployed to galactic-system) and tenant-writable; like - NetworkRule's vpcRef, vpcRef/vpcAttachmentRef are opaque string identifiers + NetworkService's vpcRef, vpcRef/vpcAttachmentRef are opaque string identifiers because the VPC API is owned by a separate companion operator, not this repo. An admission webhook (implemented by the consuming controller) must verify the requester is authorized for vpcRef/vpcAttachmentRef before a diff --git a/config/crd/network.datumapis.com_networkgateways.yaml b/config/crd/network.datumapis.com_networkgateways.yaml index 4d5515f..9158875 100644 --- a/config/crd/network.datumapis.com_networkgateways.yaml +++ b/config/crd/network.datumapis.com_networkgateways.yaml @@ -31,8 +31,8 @@ spec: Maglev/DSR consistent-hash L4 load-balancer engine. Exactly one NetworkGateway exists per gateway node (spec.targetRef.name is the Kubernetes node name), mirroring the BGPRouter node-scoped root object - pattern. NetworkRule resources are served by every NetworkGateway in the - namespace equally (anycast — see NetworkRuleStatus's doc comment); this + pattern. NetworkService resources are served by every NetworkGateway in the + namespace equally (anycast — see NetworkServiceStatus's doc comment); this object's only job is to identify which nodes participate at all and surface each node's engine health via Conditions. diff --git a/config/crd/network.datumapis.com_networkrules.yaml b/config/crd/network.datumapis.com_networkservices.yaml similarity index 92% rename from config/crd/network.datumapis.com_networkrules.yaml rename to config/crd/network.datumapis.com_networkservices.yaml index 2b5cf86..ef17865 100644 --- a/config/crd/network.datumapis.com_networkrules.yaml +++ b/config/crd/network.datumapis.com_networkservices.yaml @@ -4,16 +4,16 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.18.0 - name: networkrules.network.datumapis.com + name: networkservices.network.datumapis.com spec: group: network.datumapis.com names: - kind: NetworkRule - listKind: NetworkRuleList - plural: networkrules + kind: NetworkService + listKind: NetworkServiceList + plural: networkservices shortNames: - - netrule - singular: networkrule + - netsvc + singular: networkservice scope: Namespaced versions: - additionalPrinterColumns: @@ -33,25 +33,25 @@ spec: schema: openAPIV3Schema: description: |- - NetworkRule defines ingress load-balancing for a single tenant VPC, served + NetworkService defines ingress load-balancing for a single tenant VPC, served by every NetworkGateway node identically (anycast Direct Server Return — see NetworkGateway's doc comment). It is namespaced (deployed to galactic-system) and tenant-writable; vpcRef is an opaque string identifier because the VPC API is owned by a separate companion operator, not this repo. An admission webhook (implemented by the consuming controller) must - verify the requester is authorized for vpcRef before a rule is accepted — + verify the requester is authorized for vpcRef before a service is accepted — see the Accepted condition. Unlike the earlier Full-NAT design this type originally described, there - is no primary/secondary gateway node for a rule: every NetworkGateway - advertises every accepted rule's vipAddresses at equal BGP preference, + is no primary/secondary gateway node for a service: every NetworkGateway + advertises every accepted service's vipAddresses at equal BGP preference, consistent-hashes the same backend list to the same backend for the same flow (internal/maglev), and forwards without rewriting anything — backend selection never needs a single "owning" node the way Full-NAT's SNAT-source model did. Backends are not listed. BackendSelector picks the VPCAttachments that - serve the rule, so the backend set follows attachments as they are + serve the service, so the backend set follows attachments as they are created, deleted or moved to another node, and galactic-router on each node generates the ServiceVIPBinding its backends need from the same selection. @@ -75,7 +75,7 @@ spec: type: object spec: description: |- - NetworkRuleSpec defines the desired ingress load-balancing state for a + NetworkServiceSpec defines the desired ingress load-balancing state for a tenant VPC. properties: backendPort: @@ -88,7 +88,7 @@ spec: backendSelector: description: |- BackendSelector selects the VPCAttachments (cloud.datumapis.com/v1alpha1, - in any namespace) that serve this rule, matched against each + in any namespace) that serve this service, matched against each VPCAttachment object's own labels. Only attachments whose status.vpc equals VPCRef are candidates, whatever their labels, so a selector cannot reach into another tenant's VPC. Each selected attachment contributes the @@ -146,7 +146,7 @@ spec: rule: (has(self.matchLabels) && size(self.matchLabels) > 0) || (has(self.matchExpressions) && size(self.matchExpressions) > 0) port: - description: Port is the ingress port on VIPAddresses that this rule + description: Port is the ingress port on VIPAddresses that this service load-balances. format: int32 maximum: 65535 @@ -161,7 +161,7 @@ spec: vipAddresses: description: |- VIPAddresses is the list of ingress VIP addresses (IPv4 and/or IPv6) - this rule provisions on the assigned gateway node(s). + this service provisions on the assigned gateway node(s). items: maxLength: 45 type: string @@ -174,11 +174,11 @@ spec: rule: self.all(v, isIP(v)) vpcRef: description: |- - VPCRef is the opaque identifier of the target VPC this rule applies + VPCRef is the opaque identifier of the target VPC this service applies to. This repo does not own the VPC API and does not validate the identifier beyond non-emptiness; the admission webhook of the consuming controller is responsible for verifying the requester is - authorized for this VPC before the rule is accepted. + authorized for this VPC before the service is accepted. minLength: 1 type: string required: @@ -190,7 +190,7 @@ spec: - vpcRef type: object status: - description: NetworkRuleStatus defines the observed state of a NetworkRule. + description: NetworkServiceStatus defines the observed state of a NetworkService. properties: conditions: description: Conditions contains the standard conditions for this diff --git a/config/crd/network.datumapis.com_servicevipbindings.yaml b/config/crd/network.datumapis.com_servicevipbindings.yaml index 79a16a6..56300c7 100644 --- a/config/crd/network.datumapis.com_servicevipbindings.yaml +++ b/config/crd/network.datumapis.com_servicevipbindings.yaml @@ -41,9 +41,9 @@ spec: specific local backend must be reachable on, so the backend can reply to clients directly (the "Direct Server Return" this design depends on — see NetworkGateway's doc comment). Generated, never written by users: - galactic-router on each worker node writes one object per (rule, VIP, - backend) for every backend a NetworkRule's BackendSelector places on that - node, owned by the rule, and the same process's per-node reconciler + galactic-router on each worker node writes one object per (service, VIP, + backend) for every backend a NetworkService's BackendSelector places on that + node, owned by the service, and the same process's per-node reconciler consumes it. EgressKind decides which of two backend mechanisms this object drives, @@ -156,7 +156,7 @@ spec: vpcRef: description: |- VPCRef is the opaque identifier of the VPC the backend belongs to, - copied from the owning NetworkRule. It names the tenant VRF the + copied from the owning NetworkService. It names the tenant VRF the binding's translation rows are written for, so two tenants using the same backend address on one node never share a row. minLength: 1 diff --git a/config/samples/network.datumapis.com_v1alpha1_networkrule_tcp.yaml b/config/samples/network.datumapis.com_v1alpha1_networkservice_tcp.yaml similarity index 92% rename from config/samples/network.datumapis.com_v1alpha1_networkrule_tcp.yaml rename to config/samples/network.datumapis.com_v1alpha1_networkservice_tcp.yaml index 14955d9..0c29475 100644 --- a/config/samples/network.datumapis.com_v1alpha1_networkrule_tcp.yaml +++ b/config/samples/network.datumapis.com_v1alpha1_networkservice_tcp.yaml @@ -1,5 +1,5 @@ apiVersion: network.datumapis.com/v1alpha1 -kind: NetworkRule +kind: NetworkService metadata: name: vpc-a-https namespace: galactic-system diff --git a/docs/api/bgp.md b/docs/api/bgp.md index 39b681e..c230c0a 100644 --- a/docs/api/bgp.md +++ b/docs/api/bgp.md @@ -1665,9 +1665,9 @@ DSR/Maglev load-balancer datapath: it tells the node which service VIP a specific local backend must be reachable on, so the backend can reply to clients directly (the "Direct Server Return" this design depends on — see NetworkGateway's doc comment). Generated, never written by users: -galactic-router on each worker node writes one object per (rule, VIP, -backend) for every backend a NetworkRule's BackendSelector places on that -node, owned by the rule, and the same process's per-node reconciler +galactic-router on each worker node writes one object per (service, VIP, +backend) for every backend a NetworkService's BackendSelector places on that +node, owned by the service, and the same process's per-node reconciler consumes it. EgressKind decides which of two backend mechanisms this object drives, @@ -1740,7 +1740,7 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | | `targetRef` _[TargetRef](#targetref)_ | TargetRef identifies the Node this binding applies to. | | Required: \{\}
| -| `vpcRef` _string_ | VPCRef is the opaque identifier of the VPC the backend belongs to,
copied from the owning NetworkRule. It names the tenant VRF the
binding's translation rows are written for, so two tenants using the
same backend address on one node never share a row. | | MinLength: 1
Required: \{\}
| +| `vpcRef` _string_ | VPCRef is the opaque identifier of the VPC the backend belongs to,
copied from the owning NetworkService. It names the tenant VRF the
binding's translation rows are written for, so two tenants using the
same backend address on one node never share a row. | | MinLength: 1
Required: \{\}
| | `vipAddress` _string_ | VIPAddress is the service VIP the backend must be reachable on. | | Required: \{\}
| | `port` _integer_ | Port is the VIP-facing port traffic arrives on. | | Maximum: 65535
Minimum: 1
Required: \{\}
| | `backendAddress` _string_ | BackendAddress is the backend's own real address (its pod-netns
address for a veth backend, or its actual guest-facing address for a
tap backend) — the VIP-boundary substitution target for both kinds
now (see EgressKind's own doc comment for why veth needs this too,
not just tap). +optional at the API level for the same reason
EgressKind itself carries no matching CEL requirement; the
reconciler validates it's set for either kind before doing anything. | | | diff --git a/docs/api/gateway.md b/docs/api/gateway.md index 7e2818b..6d088aa 100644 --- a/docs/api/gateway.md +++ b/docs/api/gateway.md @@ -12,7 +12,7 @@ Package v1alpha1 contains API Schema definitions for the network.datumapis.com/v - [EgressShard](#egressshard) - [NetworkEgressPolicy](#networkegresspolicy) - [NetworkGateway](#networkgateway) -- [NetworkRule](#networkrule) +- [NetworkService](#networkservice) - [ServiceEndpoint](#serviceendpoint) - [ServiceRoutePolicy](#serviceroutepolicy) - [ServiceVIPBinding](#servicevipbinding) @@ -206,14 +206,14 @@ _Appears in:_ NetworkEgressPolicy enables internet egress for a single tenant VPC/VPCAttachment, served by the sharded, stateful galactic-nat tier -(see EgressShard). Unlike NetworkRule, it carries no VIP/backend/port: +(see EgressShard). Unlike NetworkService, it carries no VIP/backend/port: egress is on or off for a (vpcRef, vpcAttachmentRef) pair, existence-implies-enabled, not a per-flow rule — because the destination of an egress flow is an arbitrary internet address, not a pre-configured backend list. It is namespaced (deployed to galactic-system) and tenant-writable; like -NetworkRule's vpcRef, vpcRef/vpcAttachmentRef are opaque string identifiers +NetworkService's vpcRef, vpcRef/vpcAttachmentRef are opaque string identifiers because the VPC API is owned by a separate companion operator, not this repo. An admission webhook (implemented by the consuming controller) must verify the requester is authorized for vpcRef/vpcAttachmentRef before a @@ -290,8 +290,8 @@ NetworkGateway marks a single dedicated gateway-role node as running the Maglev/DSR consistent-hash L4 load-balancer engine. Exactly one NetworkGateway exists per gateway node (spec.targetRef.name is the Kubernetes node name), mirroring the BGPRouter node-scoped root object -pattern. NetworkRule resources are served by every NetworkGateway in the -namespace equally (anycast — see NetworkRuleStatus's doc comment); this +pattern. NetworkService resources are served by every NetworkGateway in the +namespace equally (anycast — see NetworkServiceStatus's doc comment); this object's only job is to identify which nodes participate at all and surface each node's engine health via Conditions. @@ -353,29 +353,29 @@ _Appears in:_ | `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v/#condition-v1-meta) array_ | Conditions contains the standard conditions for this resource. | | | -#### NetworkRule +#### NetworkService -NetworkRule defines ingress load-balancing for a single tenant VPC, served +NetworkService defines ingress load-balancing for a single tenant VPC, served by every NetworkGateway node identically (anycast Direct Server Return — see NetworkGateway's doc comment). It is namespaced (deployed to galactic-system) and tenant-writable; vpcRef is an opaque string identifier because the VPC API is owned by a separate companion operator, not this repo. An admission webhook (implemented by the consuming controller) must -verify the requester is authorized for vpcRef before a rule is accepted — +verify the requester is authorized for vpcRef before a service is accepted — see the Accepted condition. Unlike the earlier Full-NAT design this type originally described, there -is no primary/secondary gateway node for a rule: every NetworkGateway -advertises every accepted rule's vipAddresses at equal BGP preference, +is no primary/secondary gateway node for a service: every NetworkGateway +advertises every accepted service's vipAddresses at equal BGP preference, consistent-hashes the same backend list to the same backend for the same flow (internal/maglev), and forwards without rewriting anything — backend selection never needs a single "owning" node the way Full-NAT's SNAT-source model did. Backends are not listed. BackendSelector picks the VPCAttachments that -serve the rule, so the backend set follows attachments as they are +serve the service, so the backend set follows attachments as they are created, deleted or moved to another node, and galactic-router on each node generates the ServiceVIPBinding its backends need from the same selection. @@ -387,68 +387,68 @@ selection. | Field | Description | Default | Validation | | --- | --- | --- | --- | | `apiVersion` _string_ | `network.datumapis.com/v1alpha1` | | | -| `kind` _string_ | `NetworkRule` | | | +| `kind` _string_ | `NetworkService` | | | | `kind` _string_ | Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | | | | `apiVersion` _string_ | APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | | | | `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | | -| `spec` _[NetworkRuleSpec](#networkrulespec)_ | | | | -| `status` _[NetworkRuleStatus](#networkrulestatus)_ | | | | +| `spec` _[NetworkServiceSpec](#networkservicespec)_ | | | | +| `status` _[NetworkServiceStatus](#networkservicestatus)_ | | | | -#### NetworkRuleProtocol +#### NetworkServiceProtocol _Underlying type:_ _string_ -NetworkRuleProtocol is the transport protocol matched by a NetworkRule's +NetworkServiceProtocol is the transport protocol matched by a NetworkService's ingress VIP. _Validation:_ - Enum: [tcp udp] _Appears in:_ -- [NetworkRuleSpec](#networkrulespec) +- [NetworkServiceSpec](#networkservicespec) - [ServiceEndpointSpec](#serviceendpointspec) - [ServiceRouteProtocolPort](#servicerouteprotocolport) - [ServiceVIPBindingSpec](#servicevipbindingspec) | Field | Description | | --- | --- | -| `tcp` | NetworkRuleProtocolTCP matches TCP traffic.
| -| `udp` | NetworkRuleProtocolUDP matches UDP traffic.
| +| `tcp` | NetworkServiceProtocolTCP matches TCP traffic.
| +| `udp` | NetworkServiceProtocolUDP matches UDP traffic.
| -#### NetworkRuleSpec +#### NetworkServiceSpec -NetworkRuleSpec defines the desired ingress load-balancing state for a +NetworkServiceSpec defines the desired ingress load-balancing state for a tenant VPC. _Appears in:_ -- [NetworkRule](#networkrule) +- [NetworkService](#networkservice) | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `vpcRef` _string_ | VPCRef is the opaque identifier of the target VPC this rule applies
to. This repo does not own the VPC API and does not validate the
identifier beyond non-emptiness; the admission webhook of the
consuming controller is responsible for verifying the requester is
authorized for this VPC before the rule is accepted. | | MinLength: 1
Required: \{\}
| -| `vipAddresses` _string array_ | VIPAddresses is the list of ingress VIP addresses (IPv4 and/or IPv6)
this rule provisions on the assigned gateway node(s). | | MaxItems: 8
MinItems: 1
Required: \{\}
items:MaxLength: 45
| -| `protocol` _[NetworkRuleProtocol](#networkruleprotocol)_ | Protocol is the transport protocol matched by VIPAddresses/Port. | | Enum: [tcp udp]
Required: \{\}
| -| `port` _integer_ | Port is the ingress port on VIPAddresses that this rule load-balances. | | Maximum: 65535
Minimum: 1
Required: \{\}
| -| `backendSelector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v/#labelselector-v1-meta)_ | BackendSelector selects the VPCAttachments (cloud.datumapis.com/v1alpha1,
in any namespace) that serve this rule, matched against each
VPCAttachment object's own labels. Only attachments whose status.vpc
equals VPCRef are candidates, whatever their labels, so a selector cannot
reach into another tenant's VPC. Each selected attachment contributes the
IPv6 addresses in its spec.interface.addresses as backends, on
BackendPort; the DSR datapath carries IPv6 backends only. An attachment
with no status.node or no IPv6 address is not a backend until it has
both. An empty selector is rejected rather than read as "every attachment
in the VPC". | | Required: \{\}
| +| `vpcRef` _string_ | VPCRef is the opaque identifier of the target VPC this service applies
to. This repo does not own the VPC API and does not validate the
identifier beyond non-emptiness; the admission webhook of the
consuming controller is responsible for verifying the requester is
authorized for this VPC before the service is accepted. | | MinLength: 1
Required: \{\}
| +| `vipAddresses` _string array_ | VIPAddresses is the list of ingress VIP addresses (IPv4 and/or IPv6)
this service provisions on the assigned gateway node(s). | | MaxItems: 8
MinItems: 1
Required: \{\}
items:MaxLength: 45
| +| `protocol` _[NetworkServiceProtocol](#networkserviceprotocol)_ | Protocol is the transport protocol matched by VIPAddresses/Port. | | Enum: [tcp udp]
Required: \{\}
| +| `port` _integer_ | Port is the ingress port on VIPAddresses that this service load-balances. | | Maximum: 65535
Minimum: 1
Required: \{\}
| +| `backendSelector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v/#labelselector-v1-meta)_ | BackendSelector selects the VPCAttachments (cloud.datumapis.com/v1alpha1,
in any namespace) that serve this service, matched against each
VPCAttachment object's own labels. Only attachments whose status.vpc
equals VPCRef are candidates, whatever their labels, so a selector cannot
reach into another tenant's VPC. Each selected attachment contributes the
IPv6 addresses in its spec.interface.addresses as backends, on
BackendPort; the DSR datapath carries IPv6 backends only. An attachment
with no status.node or no IPv6 address is not a backend until it has
both. An empty selector is rejected rather than read as "every attachment
in the VPC". | | Required: \{\}
| | `backendPort` _integer_ | BackendPort is the destination port on every selected backend. | | Maximum: 65535
Minimum: 1
Required: \{\}
| -#### NetworkRuleStatus +#### NetworkServiceStatus -NetworkRuleStatus defines the observed state of a NetworkRule. +NetworkServiceStatus defines the observed state of a NetworkService. _Appears in:_ -- [NetworkRule](#networkrule) +- [NetworkService](#networkservice) | Field | Description | Default | Validation | | --- | --- | --- | --- | @@ -547,7 +547,7 @@ _Appears in:_ | `serviceClass` _string_ | ServiceClass identifies the platform capability implemented by this
endpoint, for example "ipv6-egress-dns". | | MinLength: 1
Required: \{\}
| | `address` _string_ | Address is the stable address that consumers use to reach the service. | | Required: \{\}
| | `port` _integer_ | Port is the service port. | | Maximum: 65535
Minimum: 1
Required: \{\}
| -| `protocol` _[NetworkRuleProtocol](#networkruleprotocol)_ | Protocol is the transport protocol accepted by the endpoint. | | Enum: [tcp udp]
Required: \{\}
| +| `protocol` _[NetworkServiceProtocol](#networkserviceprotocol)_ | Protocol is the transport protocol accepted by the endpoint. | | Enum: [tcp udp]
Required: \{\}
| | `deliveryMode` _[ServiceEndpointDeliveryMode](#serviceendpointdeliverymode)_ | DeliveryMode defines how a backing attachment is selected relative to a
consumer. PreferNodeLocal uses a ready attachment on the consumer's node
when one exists and otherwise falls back to a ready remote attachment.
The dataplane preserves the consumer source address. If consumers with
overlapping address space present an identical TCP or UDP five-tuple to the
same replica, it rejects the later ambiguous flow fail-closed rather than
translate the source or risk returning traffic to the wrong VPC. | | Enum: [NodeLocal PreferNodeLocal]
Required: \{\}
| | `attachmentRef` _[ServiceEndpointAttachmentReference](#serviceendpointattachmentreference)_ | AttachmentRef identifies the Cloud API VPCAttachment that hosts this
endpoint when the service is delivered through a private VPC path.
The network API keeps this reference opaque; the consuming controller
resolves it against the Cloud API. | | | | `attachmentSelector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v/#labelselector-v1-meta)_ | AttachmentSelector selects the Cloud API VPCAttachments that host replicas
of this endpoint. Labels used here must be assigned by the platform service
controller, not by tenants. The dataplane selects one ready replica for
each consumer according to DeliveryMode. | | | @@ -683,7 +683,7 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `protocol` _[NetworkRuleProtocol](#networkruleprotocol)_ | Protocol is the transport protocol. | | Enum: [tcp udp]
Required: \{\}
| +| `protocol` _[NetworkServiceProtocol](#networkserviceprotocol)_ | Protocol is the transport protocol. | | Enum: [tcp udp]
Required: \{\}
| | `port` _integer_ | Port is the transport port. | | Maximum: 65535
Minimum: 1
Required: \{\}
| @@ -713,9 +713,9 @@ DSR/Maglev load-balancer datapath: it tells the node which service VIP a specific local backend must be reachable on, so the backend can reply to clients directly (the "Direct Server Return" this design depends on — see NetworkGateway's doc comment). Generated, never written by users: -galactic-router on each worker node writes one object per (rule, VIP, -backend) for every backend a NetworkRule's BackendSelector places on that -node, owned by the rule, and the same process's per-node reconciler +galactic-router on each worker node writes one object per (service, VIP, +backend) for every backend a NetworkService's BackendSelector places on that +node, owned by the service, and the same process's per-node reconciler consumes it. EgressKind decides which of two backend mechanisms this object drives, @@ -788,10 +788,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | | `targetRef` _[TargetRef](#targetref)_ | TargetRef identifies the Node this binding applies to. | | Required: \{\}
| -| `vpcRef` _string_ | VPCRef is the opaque identifier of the VPC the backend belongs to,
copied from the owning NetworkRule. It names the tenant VRF the
binding's translation rows are written for, so two tenants using the
same backend address on one node never share a row. | | MinLength: 1
Required: \{\}
| +| `vpcRef` _string_ | VPCRef is the opaque identifier of the VPC the backend belongs to,
copied from the owning NetworkService. It names the tenant VRF the
binding's translation rows are written for, so two tenants using the
same backend address on one node never share a row. | | MinLength: 1
Required: \{\}
| | `vipAddress` _string_ | VIPAddress is the service VIP the backend must be reachable on. | | Required: \{\}
| | `port` _integer_ | Port is the VIP-facing port traffic arrives on. | | Maximum: 65535
Minimum: 1
Required: \{\}
| -| `protocol` _[NetworkRuleProtocol](#networkruleprotocol)_ | Protocol is the transport protocol this binding applies to. | | Enum: [tcp udp]
Required: \{\}
| +| `protocol` _[NetworkServiceProtocol](#networkserviceprotocol)_ | Protocol is the transport protocol this binding applies to. | | Enum: [tcp udp]
Required: \{\}
| | `backendAddress` _string_ | BackendAddress is the backend's own real address (its pod-netns
address for a veth backend, or its actual guest-facing address for a
tap backend) — the VIP-boundary substitution target for both kinds
now (see EgressKind's own doc comment for why veth needs this too,
not just tap). +optional at the API level for the same reason
EgressKind itself carries no matching CEL requirement; the
reconciler validates it's set for either kind before doing anything. | | | | `backendPort` _integer_ | BackendPort is the backend's own real port, paired with
BackendAddress — required for both kinds, see that field's doc
comment. | | Maximum: 65535
Minimum: 1
| | `egressKind` _[ServiceVIPBindingEgressKind](#servicevipbindingegresskind)_ | EgressKind selects which backend mechanism this binding drives. | | Enum: [veth tap]
Required: \{\}
| diff --git a/docs/api/index.md b/docs/api/index.md index d423052..10d665c 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -14,5 +14,5 @@ and VRF instances. Hyperconverged gateway and ingress load-balancing resources. -- [Gateway API Reference](gateway.md) — NetworkGateway, NetworkRule, and +- [Gateway API Reference](gateway.md) — NetworkGateway, NetworkService, and associated types diff --git a/templates/api-index.md b/templates/api-index.md index d423052..10d665c 100644 --- a/templates/api-index.md +++ b/templates/api-index.md @@ -14,5 +14,5 @@ and VRF instances. Hyperconverged gateway and ingress load-balancing resources. -- [Gateway API Reference](gateway.md) — NetworkGateway, NetworkRule, and +- [Gateway API Reference](gateway.md) — NetworkGateway, NetworkService, and associated types diff --git a/test/e2e/tests/networkrule-backend-selector/chainsaw-test.yaml b/test/e2e/tests/networkservice-backend-selector/chainsaw-test.yaml similarity index 83% rename from test/e2e/tests/networkrule-backend-selector/chainsaw-test.yaml rename to test/e2e/tests/networkservice-backend-selector/chainsaw-test.yaml index 7f04566..3562fdf 100644 --- a/test/e2e/tests/networkrule-backend-selector/chainsaw-test.yaml +++ b/test/e2e/tests/networkservice-backend-selector/chainsaw-test.yaml @@ -1,25 +1,25 @@ apiVersion: chainsaw.kyverno.io/v1alpha1 kind: Test metadata: - name: networkrule-backend-selector + name: networkservice-backend-selector spec: description: > - Verify the schema rules for a NetworkRule's backend selection: a rule with - a non-empty backendSelector and a backendPort is accepted, a rule with an - empty backendSelector is rejected, and a rule that still lists static + Verify the schema rules for a NetworkService's backend selection: a service with + a non-empty backendSelector and a backendPort is accepted, a service with an + empty backendSelector is rejected, and a service that still lists static backends or a vpcAttachmentRef is rejected, since neither field exists any more. Also verifies that a ServiceVIPBinding requires vpcRef. Does not require any operator to be running; every rule under test is enforced by the API server alone. steps: - - name: accept-rule-with-selector + - name: accept-service-with-selector try: - apply: resource: apiVersion: network.datumapis.com/v1alpha1 - kind: NetworkRule + kind: NetworkService metadata: - name: e2e-rule-selector + name: e2e-service-selector spec: vpcRef: vpc-a vipAddresses: @@ -33,9 +33,9 @@ spec: - assert: resource: apiVersion: network.datumapis.com/v1alpha1 - kind: NetworkRule + kind: NetworkService metadata: - name: e2e-rule-selector + name: e2e-service-selector spec: backendPort: 8443 backendSelector: @@ -49,9 +49,9 @@ spec: set +e OUTPUT=$(kubectl apply -n "$NAMESPACE" -f - 2>&1 <<'YAML' apiVersion: network.datumapis.com/v1alpha1 - kind: NetworkRule + kind: NetworkService metadata: - name: e2e-rule-empty-selector + name: e2e-service-empty-selector spec: vpcRef: vpc-a vipAddresses: @@ -81,9 +81,9 @@ spec: set +e OUTPUT=$(kubectl apply -n "$NAMESPACE" -f - 2>&1 <<'YAML' apiVersion: network.datumapis.com/v1alpha1 - kind: NetworkRule + kind: NetworkService metadata: - name: e2e-rule-static-backends + name: e2e-service-static-backends spec: vpcRef: vpc-a vipAddresses: @@ -98,14 +98,14 @@ spec: EXIT=$? set -e if [ "$EXIT" -eq 0 ]; then - echo "ERROR: expected rejection of a rule with static backends but the resource was accepted" + echo "ERROR: expected rejection of a service with static backends but the resource was accepted" exit 1 fi case "$OUTPUT" in *'unknown field "spec.backends"'*) ;; *) echo "ERROR: rejected for the wrong reason: $OUTPUT"; exit 1 ;; esac - echo "OK: rule with static backends correctly rejected" + echo "OK: service with static backends correctly rejected" - name: reject-vpc-attachment-ref try: @@ -114,9 +114,9 @@ spec: set +e OUTPUT=$(kubectl apply -n "$NAMESPACE" -f - 2>&1 <<'YAML' apiVersion: network.datumapis.com/v1alpha1 - kind: NetworkRule + kind: NetworkService metadata: - name: e2e-rule-vpc-attachment-ref + name: e2e-service-vpc-attachment-ref spec: vpcRef: vpc-a vpcAttachmentRef: vpc-a-attachment @@ -133,14 +133,14 @@ spec: EXIT=$? set -e if [ "$EXIT" -eq 0 ]; then - echo "ERROR: expected rejection of a rule with vpcAttachmentRef but the resource was accepted" + echo "ERROR: expected rejection of a service with vpcAttachmentRef but the resource was accepted" exit 1 fi case "$OUTPUT" in *'unknown field "spec.vpcAttachmentRef"'*) ;; *) echo "ERROR: rejected for the wrong reason: $OUTPUT"; exit 1 ;; esac - echo "OK: rule with vpcAttachmentRef correctly rejected" + echo "OK: service with vpcAttachmentRef correctly rejected" - name: reject-binding-without-vpcref try: