diff --git a/api/v1alpha1/serviceroute_types.go b/api/v1alpha1/serviceroute_types.go
new file mode 100644
index 0000000..f5b7156
--- /dev/null
+++ b/api/v1alpha1/serviceroute_types.go
@@ -0,0 +1,207 @@
+package v1alpha1
+
+import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+// ServiceEndpoint publishes a platform service that can be reached through a
+// VPC attachment. The object describes the service contract; the controller
+// that owns the service is responsible for its health and implementation.
+//
+// +kubebuilder:object:root=true
+// +kubebuilder:resource:scope=Namespaced,shortName=svcendpoint
+// +kubebuilder:printcolumn:name="ADDRESS",type="string",JSONPath=".spec.address"
+// +kubebuilder:printcolumn:name="PORT",type="integer",JSONPath=".spec.port"
+// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
+type ServiceEndpoint struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec ServiceEndpointSpec `json:"spec,omitempty"`
+}
+
+// ServiceEndpointSpec defines a platform service address and its scope.
+// +kubebuilder:validation:XValidation:rule="has(self.attachmentRef) != has(self.attachmentSelector)",message="exactly one of attachmentRef or attachmentSelector must be set"
+type ServiceEndpointSpec struct {
+ // ServiceClass identifies the platform capability implemented by this
+ // endpoint, for example "ipv6-egress-dns".
+ // +kubebuilder:validation:Required
+ // +kubebuilder:validation:MinLength=1
+ ServiceClass string `json:"serviceClass"`
+
+ // Address is the stable address that consumers use to reach the service.
+ // +kubebuilder:validation:Required
+ // +kubebuilder:validation:XValidation:rule="isIP(self)",message="address must be an IP address"
+ Address string `json:"address"`
+
+ // Port is the service port.
+ // +kubebuilder:validation:Required
+ // +kubebuilder:validation:Minimum=1
+ // +kubebuilder:validation:Maximum=65535
+ Port int32 `json:"port"`
+
+ // Protocol is the transport protocol accepted by the endpoint.
+ // +kubebuilder:validation:Required
+ Protocol NetworkRuleProtocol `json:"protocol"`
+
+ // 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.
+ // +kubebuilder:validation:Required
+ DeliveryMode ServiceEndpointDeliveryMode `json:"deliveryMode"`
+
+ // 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.
+ // +optional
+ AttachmentRef *ServiceEndpointAttachmentReference `json:"attachmentRef,omitempty"`
+
+ // 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.
+ // +optional
+ AttachmentSelector *metav1.LabelSelector `json:"attachmentSelector,omitempty"`
+
+ // Region limits endpoint selection to a region. An empty value means the
+ // endpoint is not region-scoped.
+ // +optional
+ Region string `json:"region,omitempty"`
+}
+
+// ServiceEndpointDeliveryMode defines the placement contract for a service.
+// +kubebuilder:validation:Enum=NodeLocal;PreferNodeLocal
+type ServiceEndpointDeliveryMode string
+
+const (
+ // ServiceEndpointDeliveryModeNodeLocal requires the endpoint's backing
+ // attachment to be present on each node where selected consumers run.
+ ServiceEndpointDeliveryModeNodeLocal ServiceEndpointDeliveryMode = "NodeLocal"
+
+ // ServiceEndpointDeliveryModePreferNodeLocal selects a backing attachment on
+ // the consumer's node when possible and otherwise tunnels to a ready remote
+ // attachment while preserving the consumer source address.
+ ServiceEndpointDeliveryModePreferNodeLocal ServiceEndpointDeliveryMode = "PreferNodeLocal"
+)
+
+// ServiceEndpointAttachmentReference identifies the private attachment that
+// backs a platform service endpoint.
+type ServiceEndpointAttachmentReference struct {
+ // Namespace is the namespace containing the Cloud API VPCAttachment.
+ // +kubebuilder:validation:MinLength=1
+ Namespace string `json:"namespace"`
+
+ // Name is the Cloud API VPCAttachment name.
+ // +kubebuilder:validation:MinLength=1
+ Name string `json:"name"`
+}
+
+// ServiceEndpointList is a list of ServiceEndpoint resources.
+// +kubebuilder:object:root=true
+type ServiceEndpointList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []ServiceEndpoint `json:"items"`
+}
+
+// ServiceRoutePolicy selects VPC attachments that should receive a route to a
+// platform ServiceEndpoint. The selector is evaluated by the network control
+// plane; Galactic compiles the selected attachments into dataplane state.
+//
+// +kubebuilder:object:root=true
+// +kubebuilder:subresource:status
+// +kubebuilder:resource:scope=Namespaced,shortName=svcroute
+// +kubebuilder:printcolumn:name="SERVICE",type="string",JSONPath=".spec.serviceRef.name"
+// +kubebuilder:printcolumn:name="REGION",type="string",JSONPath=".spec.region"
+// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
+type ServiceRoutePolicy struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec ServiceRoutePolicySpec `json:"spec,omitempty"`
+ Status ServiceRoutePolicyStatus `json:"status,omitempty"`
+}
+
+// ServiceRoutePolicySpec defines service selection and attachment eligibility.
+type ServiceRoutePolicySpec struct {
+ // ServiceRef identifies the ServiceEndpoint in this namespace.
+ // +kubebuilder:validation:Required
+ ServiceRef ServiceEndpointReference `json:"serviceRef"`
+
+ // AttachmentSelector selects eligible VPC attachments by authoritative
+ // labels. Labels that grant access to platform services must be assigned by
+ // the network control plane, not by tenants.
+ // +kubebuilder:validation:Required
+ AttachmentSelector metav1.LabelSelector `json:"attachmentSelector"`
+
+ // ProtocolPorts limits the traffic that the route is intended to carry.
+ // An empty list means the endpoint's declared port and protocol are used.
+ // +optional
+ // +listType=atomic
+ ProtocolPorts []ServiceRouteProtocolPort `json:"protocolPorts,omitempty"`
+
+ // Region limits selected attachments to a region. An empty value means the
+ // policy applies in every region where the endpoint is available.
+ // +optional
+ Region string `json:"region,omitempty"`
+}
+
+// ServiceRouteProtocolPort identifies an allowed transport protocol and port.
+type ServiceRouteProtocolPort struct {
+ // Protocol is the transport protocol.
+ // +kubebuilder:validation:Required
+ Protocol NetworkRuleProtocol `json:"protocol"`
+
+ // Port is the transport port.
+ // +kubebuilder:validation:Required
+ // +kubebuilder:validation:Minimum=1
+ // +kubebuilder:validation:Maximum=65535
+ Port int32 `json:"port"`
+}
+
+// ServiceEndpointReference identifies a ServiceEndpoint in the policy's
+// namespace.
+type ServiceEndpointReference struct {
+ // Name is the ServiceEndpoint name.
+ // +kubebuilder:validation:MinLength=1
+ Name string `json:"name"`
+}
+
+// ServiceRoutePolicyStatus contains durable policy conditions only. Per-
+// attachment selection and programming state belongs in metrics and logs.
+type ServiceRoutePolicyStatus struct {
+ // ObservedGeneration is the .metadata.generation this status was computed from.
+ // +optional
+ ObservedGeneration int64 `json:"observedGeneration,omitempty"`
+
+ // Conditions contains durable acceptance and service-availability state.
+ //
+ // +listType=map
+ // +listMapKey=type
+ // +optional
+ Conditions []metav1.Condition `json:"conditions,omitempty"`
+}
+
+const (
+ // ConditionTypeServiceRouteAccepted reports whether the policy is valid and
+ // can be compiled by the dataplane controllers.
+ ConditionTypeServiceRouteAccepted = "Accepted"
+)
+
+// ServiceRoutePolicyList is a list of ServiceRoutePolicy resources.
+// +kubebuilder:object:root=true
+type ServiceRoutePolicyList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []ServiceRoutePolicy `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(
+ &ServiceEndpoint{}, &ServiceEndpointList{},
+ &ServiceRoutePolicy{}, &ServiceRoutePolicyList{},
+ )
+}
diff --git a/api/v1alpha1/serviceroute_types_test.go b/api/v1alpha1/serviceroute_types_test.go
new file mode 100644
index 0000000..7876bab
--- /dev/null
+++ b/api/v1alpha1/serviceroute_types_test.go
@@ -0,0 +1,65 @@
+package v1alpha1
+
+import (
+ "testing"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func TestServiceRoutePolicyDeepCopy(t *testing.T) {
+ original := &ServiceRoutePolicy{
+ ObjectMeta: metav1.ObjectMeta{Name: "dns", Namespace: "platform"},
+ Spec: ServiceRoutePolicySpec{
+ ServiceRef: ServiceEndpointReference{Name: "ipv6-egress-dns"},
+ AttachmentSelector: metav1.LabelSelector{MatchLabels: map[string]string{"egress": "enabled"}},
+ ProtocolPorts: []ServiceRouteProtocolPort{{Protocol: NetworkRuleProtocolUDP, Port: 53}},
+ Region: "us-central-1",
+ },
+ Status: ServiceRoutePolicyStatus{Conditions: []metav1.Condition{{Type: "Accepted"}}},
+ }
+
+ copy := original.DeepCopy()
+ copy.Spec.AttachmentSelector.MatchLabels["egress"] = "disabled"
+ copy.Spec.ProtocolPorts[0].Port = 853
+ copy.Status.Conditions[0].Type = "Rejected"
+
+ if original.Spec.AttachmentSelector.MatchLabels["egress"] != "enabled" {
+ t.Fatal("DeepCopy shared selector labels")
+ }
+ if original.Status.Conditions[0].Type != "Accepted" {
+ t.Fatal("DeepCopy shared status conditions")
+ }
+ if original.Spec.ProtocolPorts[0].Port != 53 {
+ t.Fatal("DeepCopy shared protocol ports")
+ }
+}
+
+func TestServiceRoutePolicyListDeepCopy(t *testing.T) {
+ original := &ServiceRoutePolicyList{Items: []ServiceRoutePolicy{{
+ Spec: ServiceRoutePolicySpec{
+ AttachmentSelector: metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{{
+ Key: "region", Operator: metav1.LabelSelectorOpIn, Values: []string{"us-central-1"},
+ }}},
+ }}}}
+
+ copy := original.DeepCopy()
+ copy.Items[0].Spec.AttachmentSelector.MatchExpressions[0].Values[0] = "eu-west-1"
+ if got := original.Items[0].Spec.AttachmentSelector.MatchExpressions[0].Values[0]; got != "us-central-1" {
+ t.Fatalf("DeepCopy shared selector values: got %q", got)
+ }
+}
+
+func TestServiceEndpointDeepCopy(t *testing.T) {
+ original := &ServiceEndpoint{Spec: ServiceEndpointSpec{
+ DeliveryMode: ServiceEndpointDeliveryModePreferNodeLocal,
+ AttachmentSelector: &metav1.LabelSelector{MatchLabels: map[string]string{
+ "service.datumapis.com/name": "dns64",
+ }},
+ }}
+
+ copy := original.DeepCopy()
+ copy.Spec.AttachmentSelector.MatchLabels["service.datumapis.com/name"] = "other"
+ if got := original.Spec.AttachmentSelector.MatchLabels["service.datumapis.com/name"]; got != "dns64" {
+ t.Fatalf("DeepCopy shared endpoint selector labels: got %q", got)
+ }
+}
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index 17eafb4..8833b84 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -1913,6 +1913,237 @@ func (in *RouterTarget) DeepCopy() *RouterTarget {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ServiceEndpoint) DeepCopyInto(out *ServiceEndpoint) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceEndpoint.
+func (in *ServiceEndpoint) DeepCopy() *ServiceEndpoint {
+ if in == nil {
+ return nil
+ }
+ out := new(ServiceEndpoint)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ServiceEndpoint) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ServiceEndpointAttachmentReference) DeepCopyInto(out *ServiceEndpointAttachmentReference) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceEndpointAttachmentReference.
+func (in *ServiceEndpointAttachmentReference) DeepCopy() *ServiceEndpointAttachmentReference {
+ if in == nil {
+ return nil
+ }
+ out := new(ServiceEndpointAttachmentReference)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ServiceEndpointList) DeepCopyInto(out *ServiceEndpointList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]ServiceEndpoint, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceEndpointList.
+func (in *ServiceEndpointList) DeepCopy() *ServiceEndpointList {
+ if in == nil {
+ return nil
+ }
+ out := new(ServiceEndpointList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ServiceEndpointList) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ServiceEndpointReference) DeepCopyInto(out *ServiceEndpointReference) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceEndpointReference.
+func (in *ServiceEndpointReference) DeepCopy() *ServiceEndpointReference {
+ if in == nil {
+ return nil
+ }
+ out := new(ServiceEndpointReference)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ServiceEndpointSpec) DeepCopyInto(out *ServiceEndpointSpec) {
+ *out = *in
+ if in.AttachmentRef != nil {
+ in, out := &in.AttachmentRef, &out.AttachmentRef
+ *out = new(ServiceEndpointAttachmentReference)
+ **out = **in
+ }
+ if in.AttachmentSelector != nil {
+ in, out := &in.AttachmentSelector, &out.AttachmentSelector
+ *out = new(v1.LabelSelector)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceEndpointSpec.
+func (in *ServiceEndpointSpec) DeepCopy() *ServiceEndpointSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ServiceEndpointSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ServiceRoutePolicy) DeepCopyInto(out *ServiceRoutePolicy) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+ in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceRoutePolicy.
+func (in *ServiceRoutePolicy) DeepCopy() *ServiceRoutePolicy {
+ if in == nil {
+ return nil
+ }
+ out := new(ServiceRoutePolicy)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ServiceRoutePolicy) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ServiceRoutePolicyList) DeepCopyInto(out *ServiceRoutePolicyList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]ServiceRoutePolicy, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceRoutePolicyList.
+func (in *ServiceRoutePolicyList) DeepCopy() *ServiceRoutePolicyList {
+ if in == nil {
+ return nil
+ }
+ out := new(ServiceRoutePolicyList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ServiceRoutePolicyList) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ServiceRoutePolicySpec) DeepCopyInto(out *ServiceRoutePolicySpec) {
+ *out = *in
+ out.ServiceRef = in.ServiceRef
+ in.AttachmentSelector.DeepCopyInto(&out.AttachmentSelector)
+ if in.ProtocolPorts != nil {
+ in, out := &in.ProtocolPorts, &out.ProtocolPorts
+ *out = make([]ServiceRouteProtocolPort, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceRoutePolicySpec.
+func (in *ServiceRoutePolicySpec) DeepCopy() *ServiceRoutePolicySpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ServiceRoutePolicySpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ServiceRoutePolicyStatus) DeepCopyInto(out *ServiceRoutePolicyStatus) {
+ *out = *in
+ if in.Conditions != nil {
+ in, out := &in.Conditions, &out.Conditions
+ *out = make([]v1.Condition, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceRoutePolicyStatus.
+func (in *ServiceRoutePolicyStatus) DeepCopy() *ServiceRoutePolicyStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(ServiceRoutePolicyStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ServiceRouteProtocolPort) DeepCopyInto(out *ServiceRouteProtocolPort) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceRouteProtocolPort.
+func (in *ServiceRouteProtocolPort) DeepCopy() *ServiceRouteProtocolPort {
+ if in == nil {
+ return nil
+ }
+ out := new(ServiceRouteProtocolPort)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceVIPBinding) DeepCopyInto(out *ServiceVIPBinding) {
*out = *in
diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml
index ea068d4..c8fc66f 100644
--- a/config/crd/kustomization.yaml
+++ b/config/crd/kustomization.yaml
@@ -12,3 +12,5 @@ resources:
- network.datumapis.com_networkgateways.yaml
- network.datumapis.com_networkrules.yaml
- network.datumapis.com_servicevipbindings.yaml
+ - network.datumapis.com_serviceendpoints.yaml
+ - network.datumapis.com_serviceroutepolicies.yaml
diff --git a/config/crd/network.datumapis.com_serviceendpoints.yaml b/config/crd/network.datumapis.com_serviceendpoints.yaml
new file mode 100644
index 0000000..65e02ae
--- /dev/null
+++ b/config/crd/network.datumapis.com_serviceendpoints.yaml
@@ -0,0 +1,185 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.18.0
+ name: serviceendpoints.network.datumapis.com
+spec:
+ group: network.datumapis.com
+ names:
+ kind: ServiceEndpoint
+ listKind: ServiceEndpointList
+ plural: serviceendpoints
+ shortNames:
+ - svcendpoint
+ singular: serviceendpoint
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - jsonPath: .spec.address
+ name: ADDRESS
+ type: string
+ - jsonPath: .spec.port
+ name: PORT
+ type: integer
+ - jsonPath: .metadata.creationTimestamp
+ name: AGE
+ type: date
+ name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: |-
+ ServiceEndpoint publishes a platform service that can be reached through a
+ VPC attachment. The object describes the service contract; the controller
+ that owns the service is responsible for its health and implementation.
+ properties:
+ apiVersion:
+ description: |-
+ 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
+ type: string
+ kind:
+ description: |-
+ 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
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: ServiceEndpointSpec defines a platform service address and
+ its scope.
+ properties:
+ address:
+ description: Address is the stable address that consumers use to reach
+ the service.
+ type: string
+ x-kubernetes-validations:
+ - message: address must be an IP address
+ rule: isIP(self)
+ attachmentRef:
+ description: |-
+ 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.
+ properties:
+ name:
+ description: Name is the Cloud API VPCAttachment name.
+ minLength: 1
+ type: string
+ namespace:
+ description: Namespace is the namespace containing the Cloud API
+ VPCAttachment.
+ minLength: 1
+ type: string
+ required:
+ - name
+ - namespace
+ type: object
+ attachmentSelector:
+ description: |-
+ 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.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ deliveryMode:
+ description: |-
+ 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
+ type: string
+ port:
+ description: Port is the service port.
+ format: int32
+ maximum: 65535
+ minimum: 1
+ type: integer
+ protocol:
+ description: Protocol is the transport protocol accepted by the endpoint.
+ enum:
+ - tcp
+ - udp
+ type: string
+ region:
+ description: |-
+ Region limits endpoint selection to a region. An empty value means the
+ endpoint is not region-scoped.
+ type: string
+ serviceClass:
+ description: |-
+ ServiceClass identifies the platform capability implemented by this
+ endpoint, for example "ipv6-egress-dns".
+ minLength: 1
+ type: string
+ required:
+ - address
+ - deliveryMode
+ - port
+ - protocol
+ - serviceClass
+ type: object
+ x-kubernetes-validations:
+ - message: exactly one of attachmentRef or attachmentSelector must be
+ set
+ rule: has(self.attachmentRef) != has(self.attachmentSelector)
+ type: object
+ served: true
+ storage: true
+ subresources: {}
diff --git a/config/crd/network.datumapis.com_serviceroutepolicies.yaml b/config/crd/network.datumapis.com_serviceroutepolicies.yaml
new file mode 100644
index 0000000..67d33c3
--- /dev/null
+++ b/config/crd/network.datumapis.com_serviceroutepolicies.yaml
@@ -0,0 +1,228 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.18.0
+ name: serviceroutepolicies.network.datumapis.com
+spec:
+ group: network.datumapis.com
+ names:
+ kind: ServiceRoutePolicy
+ listKind: ServiceRoutePolicyList
+ plural: serviceroutepolicies
+ shortNames:
+ - svcroute
+ singular: serviceroutepolicy
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - jsonPath: .spec.serviceRef.name
+ name: SERVICE
+ type: string
+ - jsonPath: .spec.region
+ name: REGION
+ type: string
+ - jsonPath: .metadata.creationTimestamp
+ name: AGE
+ type: date
+ name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: |-
+ ServiceRoutePolicy selects VPC attachments that should receive a route to a
+ platform ServiceEndpoint. The selector is evaluated by the network control
+ plane; Galactic compiles the selected attachments into dataplane state.
+ properties:
+ apiVersion:
+ description: |-
+ 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
+ type: string
+ kind:
+ description: |-
+ 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
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: ServiceRoutePolicySpec defines service selection and attachment
+ eligibility.
+ properties:
+ attachmentSelector:
+ description: |-
+ AttachmentSelector selects eligible VPC attachments by authoritative
+ labels. Labels that grant access to platform services must be assigned by
+ the network control plane, not by tenants.
+ properties:
+ matchExpressions:
+ description: matchExpressions is a list of label selector requirements.
+ The requirements are ANDed.
+ items:
+ description: |-
+ A label selector requirement is a selector that contains values, a key, and an operator that
+ relates the key and values.
+ properties:
+ key:
+ description: key is the label key that the selector applies
+ to.
+ type: string
+ operator:
+ description: |-
+ operator represents a key's relationship to a set of values.
+ Valid operators are In, NotIn, Exists and DoesNotExist.
+ type: string
+ values:
+ description: |-
+ values is an array of string values. If the operator is In or NotIn,
+ the values array must be non-empty. If the operator is Exists or DoesNotExist,
+ the values array must be empty. This array is replaced during a strategic
+ merge patch.
+ items:
+ type: string
+ type: array
+ x-kubernetes-list-type: atomic
+ required:
+ - key
+ - operator
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ matchLabels:
+ additionalProperties:
+ type: string
+ description: |-
+ matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
+ map is equivalent to an element of matchExpressions, whose key field is "key", the
+ operator is "In", and the values array contains only "value". The requirements are ANDed.
+ type: object
+ type: object
+ x-kubernetes-map-type: atomic
+ protocolPorts:
+ description: |-
+ ProtocolPorts limits the traffic that the route is intended to carry.
+ An empty list means the endpoint's declared port and protocol are used.
+ items:
+ description: ServiceRouteProtocolPort identifies an allowed transport
+ protocol and port.
+ properties:
+ port:
+ description: Port is the transport port.
+ format: int32
+ maximum: 65535
+ minimum: 1
+ type: integer
+ protocol:
+ description: Protocol is the transport protocol.
+ enum:
+ - tcp
+ - udp
+ type: string
+ required:
+ - port
+ - protocol
+ type: object
+ type: array
+ x-kubernetes-list-type: atomic
+ region:
+ description: |-
+ Region limits selected attachments to a region. An empty value means the
+ policy applies in every region where the endpoint is available.
+ type: string
+ serviceRef:
+ description: ServiceRef identifies the ServiceEndpoint in this namespace.
+ properties:
+ name:
+ description: Name is the ServiceEndpoint name.
+ minLength: 1
+ type: string
+ required:
+ - name
+ type: object
+ required:
+ - attachmentSelector
+ - serviceRef
+ type: object
+ status:
+ description: |-
+ ServiceRoutePolicyStatus contains durable policy conditions only. Per-
+ attachment selection and programming state belongs in metrics and logs.
+ properties:
+ conditions:
+ description: Conditions contains durable acceptance and service-availability
+ state.
+ items:
+ description: Condition contains details for one aspect of the current
+ state of this API Resource.
+ properties:
+ lastTransitionTime:
+ description: |-
+ lastTransitionTime is the last time the condition transitioned from one status to another.
+ This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
+ format: date-time
+ type: string
+ message:
+ description: |-
+ message is a human readable message indicating details about the transition.
+ This may be an empty string.
+ maxLength: 32768
+ type: string
+ observedGeneration:
+ description: |-
+ observedGeneration represents the .metadata.generation that the condition was set based upon.
+ For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
+ with respect to the current state of the instance.
+ format: int64
+ minimum: 0
+ type: integer
+ reason:
+ description: |-
+ reason contains a programmatic identifier indicating the reason for the condition's last transition.
+ Producers of specific condition types may define expected values and meanings for this field,
+ and whether the values are considered a guaranteed API.
+ The value should be a CamelCase string.
+ This field may not be empty.
+ maxLength: 1024
+ minLength: 1
+ pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
+ type: string
+ status:
+ description: status of the condition, one of True, False, Unknown.
+ enum:
+ - "True"
+ - "False"
+ - Unknown
+ type: string
+ type:
+ description: type of condition in CamelCase or in foo.example.com/CamelCase.
+ maxLength: 316
+ pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
+ type: string
+ required:
+ - lastTransitionTime
+ - message
+ - reason
+ - status
+ - type
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - type
+ x-kubernetes-list-type: map
+ observedGeneration:
+ description: ObservedGeneration is the .metadata.generation this status
+ was computed from.
+ format: int64
+ type: integer
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/docs/api/bgp.md b/docs/api/bgp.md
index d8345bb..cc6c93f 100644
--- a/docs/api/bgp.md
+++ b/docs/api/bgp.md
@@ -16,6 +16,8 @@ Package v1alpha1 contains API Schema definitions for the network.datumapis.com/v
- [BGPRouter](#bgprouter)
- [BGPVRFInstance](#bgpvrfinstance)
- [EgressShard](#egressshard)
+- [ServiceEndpoint](#serviceendpoint)
+- [ServiceRoutePolicy](#serviceroutepolicy)
- [ServiceVIPBinding](#servicevipbinding)
@@ -1407,6 +1409,179 @@ _Appears in:_
| `both` | SendCommunityTypeBoth sends both standard and extended communities.
|
+#### ServiceEndpoint
+
+
+
+ServiceEndpoint publishes a platform service that can be reached through a
+VPC attachment. The object describes the service contract; the controller
+that owns the service is responsible for its health and implementation.
+
+
+
+
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `apiVersion` _string_ | `network.datumapis.com/v1alpha1` | | |
+| `kind` _string_ | `ServiceEndpoint` | | |
+| `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` _[ServiceEndpointSpec](#serviceendpointspec)_ | | | |
+
+
+#### ServiceEndpointAttachmentReference
+
+
+
+ServiceEndpointAttachmentReference identifies the private attachment that
+backs a platform service endpoint.
+
+
+
+_Appears in:_
+- [ServiceEndpointSpec](#serviceendpointspec)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `namespace` _string_ | Namespace is the namespace containing the Cloud API VPCAttachment. | | MinLength: 1
|
+| `name` _string_ | Name is the Cloud API VPCAttachment name. | | MinLength: 1
|
+
+
+#### ServiceEndpointDeliveryMode
+
+_Underlying type:_ _string_
+
+ServiceEndpointDeliveryMode defines the placement contract for a service.
+
+_Validation:_
+- Enum: [NodeLocal PreferNodeLocal]
+
+_Appears in:_
+- [ServiceEndpointSpec](#serviceendpointspec)
+
+| Field | Description |
+| --- | --- |
+| `NodeLocal` | ServiceEndpointDeliveryModeNodeLocal requires the endpoint's backing
attachment to be present on each node where selected consumers run.
|
+| `PreferNodeLocal` | ServiceEndpointDeliveryModePreferNodeLocal selects a backing attachment on
the consumer's node when possible and otherwise tunnels to a ready remote
attachment while preserving the consumer source address.
|
+
+
+#### ServiceEndpointReference
+
+
+
+ServiceEndpointReference identifies a ServiceEndpoint in the policy's
+namespace.
+
+
+
+_Appears in:_
+- [ServiceRoutePolicySpec](#serviceroutepolicyspec)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `name` _string_ | Name is the ServiceEndpoint name. | | MinLength: 1
|
+
+
+#### ServiceEndpointSpec
+
+
+
+ServiceEndpointSpec defines a platform service address and its scope.
+
+
+
+_Appears in:_
+- [ServiceEndpoint](#serviceendpoint)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `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: \{\}
|
+| `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. | | |
+| `region` _string_ | Region limits endpoint selection to a region. An empty value means the
endpoint is not region-scoped. | | |
+
+
+#### ServiceRoutePolicy
+
+
+
+ServiceRoutePolicy selects VPC attachments that should receive a route to a
+platform ServiceEndpoint. The selector is evaluated by the network control
+plane; Galactic compiles the selected attachments into dataplane state.
+
+
+
+
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `apiVersion` _string_ | `network.datumapis.com/v1alpha1` | | |
+| `kind` _string_ | `ServiceRoutePolicy` | | |
+| `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` _[ServiceRoutePolicySpec](#serviceroutepolicyspec)_ | | | |
+| `status` _[ServiceRoutePolicyStatus](#serviceroutepolicystatus)_ | | | |
+
+
+#### ServiceRoutePolicySpec
+
+
+
+ServiceRoutePolicySpec defines service selection and attachment eligibility.
+
+
+
+_Appears in:_
+- [ServiceRoutePolicy](#serviceroutepolicy)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `serviceRef` _[ServiceEndpointReference](#serviceendpointreference)_ | ServiceRef identifies the ServiceEndpoint in this namespace. | | Required: \{\}
|
+| `attachmentSelector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v/#labelselector-v1-meta)_ | AttachmentSelector selects eligible VPC attachments by authoritative
labels. Labels that grant access to platform services must be assigned by
the network control plane, not by tenants. | | Required: \{\}
|
+| `protocolPorts` _[ServiceRouteProtocolPort](#servicerouteprotocolport) array_ | ProtocolPorts limits the traffic that the route is intended to carry.
An empty list means the endpoint's declared port and protocol are used. | | |
+| `region` _string_ | Region limits selected attachments to a region. An empty value means the
policy applies in every region where the endpoint is available. | | |
+
+
+#### ServiceRoutePolicyStatus
+
+
+
+ServiceRoutePolicyStatus contains durable policy conditions only. Per-
+attachment selection and programming state belongs in metrics and logs.
+
+
+
+_Appears in:_
+- [ServiceRoutePolicy](#serviceroutepolicy)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `observedGeneration` _integer_ | ObservedGeneration is the .metadata.generation this status was computed from. | | |
+| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v/#condition-v1-meta) array_ | Conditions contains durable acceptance and service-availability state. | | |
+
+
+#### ServiceRouteProtocolPort
+
+
+
+ServiceRouteProtocolPort identifies an allowed transport protocol and port.
+
+
+
+_Appears in:_
+- [ServiceRoutePolicySpec](#serviceroutepolicyspec)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `port` _integer_ | Port is the transport port. | | Maximum: 65535
Minimum: 1
Required: \{\}
|
+
+
#### ServiceVIPBinding
diff --git a/docs/api/gateway.md b/docs/api/gateway.md
index 7cda32a..179641d 100644
--- a/docs/api/gateway.md
+++ b/docs/api/gateway.md
@@ -13,6 +13,8 @@ Package v1alpha1 contains API Schema definitions for the network.datumapis.com/v
- [NetworkEgressPolicy](#networkegresspolicy)
- [NetworkGateway](#networkgateway)
- [NetworkRule](#networkrule)
+- [ServiceEndpoint](#serviceendpoint)
+- [ServiceRoutePolicy](#serviceroutepolicy)
- [ServiceVIPBinding](#servicevipbinding)
@@ -417,6 +419,8 @@ _Validation:_
_Appears in:_
- [NetworkRuleSpec](#networkrulespec)
+- [ServiceEndpointSpec](#serviceendpointspec)
+- [ServiceRouteProtocolPort](#servicerouteprotocolport)
- [ServiceVIPBindingSpec](#servicevipbindingspec)
| Field | Description |
@@ -464,6 +468,181 @@ _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. | | |
+#### ServiceEndpoint
+
+
+
+ServiceEndpoint publishes a platform service that can be reached through a
+VPC attachment. The object describes the service contract; the controller
+that owns the service is responsible for its health and implementation.
+
+
+
+
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `apiVersion` _string_ | `network.datumapis.com/v1alpha1` | | |
+| `kind` _string_ | `ServiceEndpoint` | | |
+| `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` _[ServiceEndpointSpec](#serviceendpointspec)_ | | | |
+
+
+#### ServiceEndpointAttachmentReference
+
+
+
+ServiceEndpointAttachmentReference identifies the private attachment that
+backs a platform service endpoint.
+
+
+
+_Appears in:_
+- [ServiceEndpointSpec](#serviceendpointspec)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `namespace` _string_ | Namespace is the namespace containing the Cloud API VPCAttachment. | | MinLength: 1
|
+| `name` _string_ | Name is the Cloud API VPCAttachment name. | | MinLength: 1
|
+
+
+#### ServiceEndpointDeliveryMode
+
+_Underlying type:_ _string_
+
+ServiceEndpointDeliveryMode defines the placement contract for a service.
+
+_Validation:_
+- Enum: [NodeLocal PreferNodeLocal]
+
+_Appears in:_
+- [ServiceEndpointSpec](#serviceendpointspec)
+
+| Field | Description |
+| --- | --- |
+| `NodeLocal` | ServiceEndpointDeliveryModeNodeLocal requires the endpoint's backing
attachment to be present on each node where selected consumers run.
|
+| `PreferNodeLocal` | ServiceEndpointDeliveryModePreferNodeLocal selects a backing attachment on
the consumer's node when possible and otherwise tunnels to a ready remote
attachment while preserving the consumer source address.
|
+
+
+#### ServiceEndpointReference
+
+
+
+ServiceEndpointReference identifies a ServiceEndpoint in the policy's
+namespace.
+
+
+
+_Appears in:_
+- [ServiceRoutePolicySpec](#serviceroutepolicyspec)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `name` _string_ | Name is the ServiceEndpoint name. | | MinLength: 1
|
+
+
+#### ServiceEndpointSpec
+
+
+
+ServiceEndpointSpec defines a platform service address and its scope.
+
+
+
+_Appears in:_
+- [ServiceEndpoint](#serviceendpoint)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `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: \{\}
|
+| `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. | | |
+| `region` _string_ | Region limits endpoint selection to a region. An empty value means the
endpoint is not region-scoped. | | |
+
+
+#### ServiceRoutePolicy
+
+
+
+ServiceRoutePolicy selects VPC attachments that should receive a route to a
+platform ServiceEndpoint. The selector is evaluated by the network control
+plane; Galactic compiles the selected attachments into dataplane state.
+
+
+
+
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `apiVersion` _string_ | `network.datumapis.com/v1alpha1` | | |
+| `kind` _string_ | `ServiceRoutePolicy` | | |
+| `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` _[ServiceRoutePolicySpec](#serviceroutepolicyspec)_ | | | |
+| `status` _[ServiceRoutePolicyStatus](#serviceroutepolicystatus)_ | | | |
+
+
+#### ServiceRoutePolicySpec
+
+
+
+ServiceRoutePolicySpec defines service selection and attachment eligibility.
+
+
+
+_Appears in:_
+- [ServiceRoutePolicy](#serviceroutepolicy)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `serviceRef` _[ServiceEndpointReference](#serviceendpointreference)_ | ServiceRef identifies the ServiceEndpoint in this namespace. | | Required: \{\}
|
+| `attachmentSelector` _[LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v/#labelselector-v1-meta)_ | AttachmentSelector selects eligible VPC attachments by authoritative
labels. Labels that grant access to platform services must be assigned by
the network control plane, not by tenants. | | Required: \{\}
|
+| `protocolPorts` _[ServiceRouteProtocolPort](#servicerouteprotocolport) array_ | ProtocolPorts limits the traffic that the route is intended to carry.
An empty list means the endpoint's declared port and protocol are used. | | |
+| `region` _string_ | Region limits selected attachments to a region. An empty value means the
policy applies in every region where the endpoint is available. | | |
+
+
+#### ServiceRoutePolicyStatus
+
+
+
+ServiceRoutePolicyStatus contains durable policy conditions only. Per-
+attachment selection and programming state belongs in metrics and logs.
+
+
+
+_Appears in:_
+- [ServiceRoutePolicy](#serviceroutepolicy)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `observedGeneration` _integer_ | ObservedGeneration is the .metadata.generation this status was computed from. | | |
+| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v/#condition-v1-meta) array_ | Conditions contains durable acceptance and service-availability state. | | |
+
+
+#### ServiceRouteProtocolPort
+
+
+
+ServiceRouteProtocolPort identifies an allowed transport protocol and port.
+
+
+
+_Appears in:_
+- [ServiceRoutePolicySpec](#serviceroutepolicyspec)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `protocol` _[NetworkRuleProtocol](#networkruleprotocol)_ | Protocol is the transport protocol. | | Enum: [tcp udp]
Required: \{\}
|
+| `port` _integer_ | Port is the transport port. | | Maximum: 65535
Minimum: 1
Required: \{\}
|
+
+
#### ServiceVIPBinding