diff --git a/components/api-server/go.mod b/components/api-server/go.mod
index 2d5ec7824..6f7c8b0c1 100644
--- a/components/api-server/go.mod
+++ b/components/api-server/go.mod
@@ -64,6 +64,7 @@ require (
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v0.2.1 // indirect
github.com/cpuguy83/dockercfg v0.3.2 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/docker v28.5.2+incompatible // indirect
@@ -112,6 +113,7 @@ require (
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
+ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
diff --git a/components/api-server/go.sum b/components/api-server/go.sum
index 89159e86d..c8c408066 100644
--- a/components/api-server/go.sum
+++ b/components/api-server/go.sum
@@ -88,8 +88,9 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20190423183735-731ef375ac02/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
@@ -302,8 +303,9 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -514,8 +516,8 @@ golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
+golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/components/api-server/openapi/openapi.gateways.yaml b/components/api-server/openapi/openapi.gateways.yaml
index 759aa7d25..9f559cf2a 100644
--- a/components/api-server/openapi/openapi.gateways.yaml
+++ b/components/api-server/openapi/openapi.gateways.yaml
@@ -59,9 +59,9 @@ paths:
$ref: '#/components/schemas/Gateway'
'400':
description: |
- Validation errors occurred, including a cluster_id that is empty or does not
- reference a ManagedCluster with a registered control plane (non-empty
- oidc_subject). On update, cluster_id is validated only when it changes.
+ Validation errors occurred, including an invalid or unavailable placement
+ intent. The backend resolves a valid intent to a registered ManagedCluster
+ before creating the gateway.
content:
application/json:
schema:
@@ -90,6 +90,31 @@ paths:
application/json:
schema:
$ref: 'openapi.yaml#/components/schemas/Error'
+ /api/hypershell/v1/gateways/placement-availability:
+ get:
+ operationId: getGatewayPlacementAvailability
+ summary: Returns current provider placement eligibility
+ security:
+ - Bearer: []
+ responses:
+ '200':
+ description: Current backend placement eligibility
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GatewayPlacementAvailability'
+ '401':
+ description: Auth token is invalid
+ content:
+ application/json:
+ schema:
+ $ref: 'openapi.yaml#/components/schemas/Error'
+ '500':
+ description: Unexpected error evaluating placement availability
+ content:
+ application/json:
+ schema:
+ $ref: 'openapi.yaml#/components/schemas/Error'
# NEW ENDPOINT START
/api/hypershell/v1/gateways/{id}:
# NEW ENDPOINT END
@@ -329,12 +354,12 @@ components:
type: object
required:
- name
- - cluster_id
+ - placement
properties:
name:
type: string
- cluster_id:
- type: string
+ placement:
+ $ref: '#/components/schemas/GatewayPlacementIntent'
external_dns:
type: string
tls_mode:
@@ -365,6 +390,51 @@ components:
credential_driver:
type: string
description: JSON-encoded credential storage driver configuration
+ GatewayPlacementIntent:
+ type: object
+ description: Exactly one of network/provider or mode must be supplied.
+ oneOf:
+ - title: Managed placement
+ required: [network, provider]
+ not:
+ required: [mode]
+ - title: Local Kind placement
+ required: [mode]
+ not:
+ anyOf:
+ - required: [network]
+ - required: [provider]
+ properties:
+ network:
+ type: string
+ enum: [public, vpn]
+ provider:
+ type: string
+ enum: [aws, ibm]
+ description: IBM Cloud supports public placement only; VPN requires AWS.
+ mode:
+ type: string
+ enum: [local-kind]
+ GatewayPlacementAvailability:
+ type: object
+ required: [aws_public, aws_vpn, ibm_public, ibm_vpn, local_kind]
+ properties:
+ aws_public:
+ type: boolean
+ aws_vpn:
+ type: boolean
+ ibm_public:
+ type: boolean
+ ibm_vpn:
+ type: boolean
+ local_kind:
+ type: boolean
+ aws_reason:
+ type: string
+ enum: [no-eligible-cluster]
+ ibm_reason:
+ type: string
+ enum: [no-eligible-cluster]
# NEW SCHEMA START
GatewayList:
# NEW SCHEMA END
diff --git a/components/api-server/openapi/openapi.managedClusters.yaml b/components/api-server/openapi/openapi.managedClusters.yaml
index fbcc84b91..5efa023d5 100644
--- a/components/api-server/openapi/openapi.managedClusters.yaml
+++ b/components/api-server/openapi/openapi.managedClusters.yaml
@@ -301,6 +301,12 @@ components:
type: string
provider:
type: string
+ description: Cloud provider capability used for gateway placement.
+ visibility:
+ type: string
+ enum: [public, vpn]
+ readOnly: true
+ description: Network visibility supported by this control plane for gateway placement.
region:
type: string
kubeconfig_secret:
@@ -329,6 +335,14 @@ components:
description:
type: string
description: Optional description of the spoke.
+ provider:
+ type: string
+ enum: [aws, ibm, kind]
+ description: Cloud provider hosting this control plane.
+ visibility:
+ type: string
+ enum: [public, vpn]
+ description: Network visibility supported for gateways on this control plane.
ManagedClusterRegistrationResponse:
type: object
required:
diff --git a/components/api-server/openapi/openapi.yaml b/components/api-server/openapi/openapi.yaml
index e37155f45..4d99919ad 100644
--- a/components/api-server/openapi/openapi.yaml
+++ b/components/api-server/openapi/openapi.yaml
@@ -34,6 +34,8 @@ paths:
$ref: 'openapi.managedClusters.yaml#/paths/~1api~1hypershell~1v1~1managed_clusters~1{id}'
/api/hypershell/v1/gateways:
$ref: 'openapi.gateways.yaml#/paths/~1api~1hypershell~1v1~1gateways'
+ /api/hypershell/v1/gateways/placement-availability:
+ $ref: 'openapi.gateways.yaml#/paths/~1api~1hypershell~1v1~1gateways~1placement-availability'
/api/hypershell/v1/gateways/{id}:
$ref: 'openapi.gateways.yaml#/paths/~1api~1hypershell~1v1~1gateways~1{id}'
/api/hypershell/v1/gateways/{gateway_id}/service_accounts:
@@ -136,6 +138,10 @@ components:
$ref: 'openapi.gateways.yaml#/components/schemas/GatewayList'
GatewayPatchRequest:
$ref: 'openapi.gateways.yaml#/components/schemas/GatewayPatchRequest'
+ GatewayPlacementIntent:
+ $ref: 'openapi.gateways.yaml#/components/schemas/GatewayPlacementIntent'
+ GatewayPlacementAvailability:
+ $ref: 'openapi.gateways.yaml#/components/schemas/GatewayPlacementAvailability'
OpenShellGatewayServiceAccountRole:
$ref: 'openapi.serviceAccounts.yaml#/components/schemas/OpenShellGatewayServiceAccountRole'
OpenShellGatewayServiceAccountStatus:
diff --git a/components/api-server/pkg/api/grpc/hypershell/v1/gateways.pb.go b/components/api-server/pkg/api/grpc/hypershell/v1/gateways.pb.go
index b5ed58aea..e09b35045 100644
--- a/components/api-server/pkg/api/grpc/hypershell/v1/gateways.pb.go
+++ b/components/api-server/pkg/api/grpc/hypershell/v1/gateways.pb.go
@@ -136,6 +136,176 @@ func (x *ProvisioningCondition) GetMessage() string {
return ""
}
+type GatewayPlacementIntent struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ // Types that are valid to be assigned to Placement:
+ //
+ // *GatewayPlacementIntent_NetworkProvider
+ // *GatewayPlacementIntent_LocalKind
+ Placement isGatewayPlacementIntent_Placement `protobuf_oneof:"placement"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GatewayPlacementIntent) Reset() {
+ *x = GatewayPlacementIntent{}
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GatewayPlacementIntent) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GatewayPlacementIntent) ProtoMessage() {}
+
+func (x *GatewayPlacementIntent) ProtoReflect() protoreflect.Message {
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GatewayPlacementIntent.ProtoReflect.Descriptor instead.
+func (*GatewayPlacementIntent) Descriptor() ([]byte, []int) {
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *GatewayPlacementIntent) GetPlacement() isGatewayPlacementIntent_Placement {
+ if x != nil {
+ return x.Placement
+ }
+ return nil
+}
+
+func (x *GatewayPlacementIntent) GetNetworkProvider() *NetworkProviderPlacement {
+ if x != nil {
+ if x, ok := x.Placement.(*GatewayPlacementIntent_NetworkProvider); ok {
+ return x.NetworkProvider
+ }
+ }
+ return nil
+}
+
+func (x *GatewayPlacementIntent) GetLocalKind() *LocalKindPlacement {
+ if x != nil {
+ if x, ok := x.Placement.(*GatewayPlacementIntent_LocalKind); ok {
+ return x.LocalKind
+ }
+ }
+ return nil
+}
+
+type isGatewayPlacementIntent_Placement interface {
+ isGatewayPlacementIntent_Placement()
+}
+
+type GatewayPlacementIntent_NetworkProvider struct {
+ NetworkProvider *NetworkProviderPlacement `protobuf:"bytes,1,opt,name=network_provider,json=networkProvider,proto3,oneof"`
+}
+
+type GatewayPlacementIntent_LocalKind struct {
+ LocalKind *LocalKindPlacement `protobuf:"bytes,2,opt,name=local_kind,json=localKind,proto3,oneof"`
+}
+
+func (*GatewayPlacementIntent_NetworkProvider) isGatewayPlacementIntent_Placement() {}
+
+func (*GatewayPlacementIntent_LocalKind) isGatewayPlacementIntent_Placement() {}
+
+type NetworkProviderPlacement struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"`
+ Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *NetworkProviderPlacement) Reset() {
+ *x = NetworkProviderPlacement{}
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *NetworkProviderPlacement) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*NetworkProviderPlacement) ProtoMessage() {}
+
+func (x *NetworkProviderPlacement) ProtoReflect() protoreflect.Message {
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[2]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use NetworkProviderPlacement.ProtoReflect.Descriptor instead.
+func (*NetworkProviderPlacement) Descriptor() ([]byte, []int) {
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *NetworkProviderPlacement) GetNetwork() string {
+ if x != nil {
+ return x.Network
+ }
+ return ""
+}
+
+func (x *NetworkProviderPlacement) GetProvider() string {
+ if x != nil {
+ return x.Provider
+ }
+ return ""
+}
+
+type LocalKindPlacement struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *LocalKindPlacement) Reset() {
+ *x = LocalKindPlacement{}
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *LocalKindPlacement) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LocalKindPlacement) ProtoMessage() {}
+
+func (x *LocalKindPlacement) ProtoReflect() protoreflect.Message {
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[3]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use LocalKindPlacement.ProtoReflect.Descriptor instead.
+func (*LocalKindPlacement) Descriptor() ([]byte, []int) {
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{3}
+}
+
type Gateway struct {
state protoimpl.MessageState `protogen:"open.v1"`
Metadata *ObjectReference `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
@@ -172,7 +342,7 @@ type Gateway struct {
func (x *Gateway) Reset() {
*x = Gateway{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[1]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -184,7 +354,7 @@ func (x *Gateway) String() string {
func (*Gateway) ProtoMessage() {}
func (x *Gateway) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[1]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -197,7 +367,7 @@ func (x *Gateway) ProtoReflect() protoreflect.Message {
// Deprecated: Use Gateway.ProtoReflect.Descriptor instead.
func (*Gateway) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{1}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{4}
}
func (x *Gateway) GetMetadata() *ObjectReference {
@@ -369,28 +539,29 @@ func (x *Gateway) GetObservedGeneration() int64 {
}
type CreateGatewayRequest struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
- ClusterId string `protobuf:"bytes,3,opt,name=cluster_id,json=clusterId,proto3" json:"cluster_id,omitempty"`
- ReleaseId string `protobuf:"bytes,4,opt,name=release_id,json=releaseId,proto3" json:"release_id,omitempty"`
- ExternalDns *string `protobuf:"bytes,6,opt,name=external_dns,json=externalDns,proto3,oneof" json:"external_dns,omitempty"`
- TlsMode *string `protobuf:"bytes,7,opt,name=tls_mode,json=tlsMode,proto3,oneof" json:"tls_mode,omitempty"`
- ServiceType *string `protobuf:"bytes,8,opt,name=service_type,json=serviceType,proto3,oneof" json:"service_type,omitempty"`
- Status *string `protobuf:"bytes,9,opt,name=status,proto3,oneof" json:"status,omitempty"`
- Phase *string `protobuf:"bytes,10,opt,name=phase,proto3,oneof" json:"phase,omitempty"`
- Image *string `protobuf:"bytes,11,opt,name=image,proto3,oneof" json:"image,omitempty"`
- SupervisorImage *string `protobuf:"bytes,12,opt,name=supervisor_image,json=supervisorImage,proto3,oneof" json:"supervisor_image,omitempty"`
- ServerDnsNames []string `protobuf:"bytes,13,rep,name=server_dns_names,json=serverDnsNames,proto3" json:"server_dns_names,omitempty"`
- Oidc *string `protobuf:"bytes,14,opt,name=oidc,proto3,oneof" json:"oidc,omitempty"`
- Route *string `protobuf:"bytes,15,opt,name=route,proto3,oneof" json:"route,omitempty"`
- CredentialDriver *string `protobuf:"bytes,17,opt,name=credential_driver,json=credentialDriver,proto3,oneof" json:"credential_driver,omitempty"`
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ ClusterId string `protobuf:"bytes,3,opt,name=cluster_id,json=clusterId,proto3" json:"cluster_id,omitempty"`
+ ReleaseId string `protobuf:"bytes,4,opt,name=release_id,json=releaseId,proto3" json:"release_id,omitempty"`
+ ExternalDns *string `protobuf:"bytes,6,opt,name=external_dns,json=externalDns,proto3,oneof" json:"external_dns,omitempty"`
+ TlsMode *string `protobuf:"bytes,7,opt,name=tls_mode,json=tlsMode,proto3,oneof" json:"tls_mode,omitempty"`
+ ServiceType *string `protobuf:"bytes,8,opt,name=service_type,json=serviceType,proto3,oneof" json:"service_type,omitempty"`
+ Status *string `protobuf:"bytes,9,opt,name=status,proto3,oneof" json:"status,omitempty"`
+ Phase *string `protobuf:"bytes,10,opt,name=phase,proto3,oneof" json:"phase,omitempty"`
+ Image *string `protobuf:"bytes,11,opt,name=image,proto3,oneof" json:"image,omitempty"`
+ SupervisorImage *string `protobuf:"bytes,12,opt,name=supervisor_image,json=supervisorImage,proto3,oneof" json:"supervisor_image,omitempty"`
+ ServerDnsNames []string `protobuf:"bytes,13,rep,name=server_dns_names,json=serverDnsNames,proto3" json:"server_dns_names,omitempty"`
+ Oidc *string `protobuf:"bytes,14,opt,name=oidc,proto3,oneof" json:"oidc,omitempty"`
+ Route *string `protobuf:"bytes,15,opt,name=route,proto3,oneof" json:"route,omitempty"`
+ CredentialDriver *string `protobuf:"bytes,17,opt,name=credential_driver,json=credentialDriver,proto3,oneof" json:"credential_driver,omitempty"`
+ Placement *GatewayPlacementIntent `protobuf:"bytes,18,opt,name=placement,proto3" json:"placement,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CreateGatewayRequest) Reset() {
*x = CreateGatewayRequest{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[2]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -402,7 +573,7 @@ func (x *CreateGatewayRequest) String() string {
func (*CreateGatewayRequest) ProtoMessage() {}
func (x *CreateGatewayRequest) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[2]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -415,7 +586,7 @@ func (x *CreateGatewayRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use CreateGatewayRequest.ProtoReflect.Descriptor instead.
func (*CreateGatewayRequest) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{2}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{5}
}
func (x *CreateGatewayRequest) GetName() string {
@@ -516,6 +687,13 @@ func (x *CreateGatewayRequest) GetCredentialDriver() string {
return ""
}
+func (x *CreateGatewayRequest) GetPlacement() *GatewayPlacementIntent {
+ if x != nil {
+ return x.Placement
+ }
+ return nil
+}
+
type CreateGatewayResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Gateway *Gateway `protobuf:"bytes,1,opt,name=gateway,proto3" json:"gateway,omitempty"`
@@ -525,7 +703,7 @@ type CreateGatewayResponse struct {
func (x *CreateGatewayResponse) Reset() {
*x = CreateGatewayResponse{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[3]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -537,7 +715,7 @@ func (x *CreateGatewayResponse) String() string {
func (*CreateGatewayResponse) ProtoMessage() {}
func (x *CreateGatewayResponse) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[3]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -550,7 +728,7 @@ func (x *CreateGatewayResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use CreateGatewayResponse.ProtoReflect.Descriptor instead.
func (*CreateGatewayResponse) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{3}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{6}
}
func (x *CreateGatewayResponse) GetGateway() *Gateway {
@@ -569,7 +747,7 @@ type GetGatewayRequest struct {
func (x *GetGatewayRequest) Reset() {
*x = GetGatewayRequest{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[4]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -581,7 +759,7 @@ func (x *GetGatewayRequest) String() string {
func (*GetGatewayRequest) ProtoMessage() {}
func (x *GetGatewayRequest) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[4]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -594,7 +772,7 @@ func (x *GetGatewayRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use GetGatewayRequest.ProtoReflect.Descriptor instead.
func (*GetGatewayRequest) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{4}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{7}
}
func (x *GetGatewayRequest) GetId() string {
@@ -613,7 +791,7 @@ type GetGatewayResponse struct {
func (x *GetGatewayResponse) Reset() {
*x = GetGatewayResponse{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[5]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -625,7 +803,7 @@ func (x *GetGatewayResponse) String() string {
func (*GetGatewayResponse) ProtoMessage() {}
func (x *GetGatewayResponse) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[5]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -638,7 +816,7 @@ func (x *GetGatewayResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use GetGatewayResponse.ProtoReflect.Descriptor instead.
func (*GetGatewayResponse) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{5}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{8}
}
func (x *GetGatewayResponse) GetGateway() *Gateway {
@@ -684,7 +862,7 @@ type UpdateGatewayRequest struct {
func (x *UpdateGatewayRequest) Reset() {
*x = UpdateGatewayRequest{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[6]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -696,7 +874,7 @@ func (x *UpdateGatewayRequest) String() string {
func (*UpdateGatewayRequest) ProtoMessage() {}
func (x *UpdateGatewayRequest) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[6]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -709,7 +887,7 @@ func (x *UpdateGatewayRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use UpdateGatewayRequest.ProtoReflect.Descriptor instead.
func (*UpdateGatewayRequest) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{6}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{9}
}
func (x *UpdateGatewayRequest) GetId() string {
@@ -861,7 +1039,7 @@ type UpdateGatewayResponse struct {
func (x *UpdateGatewayResponse) Reset() {
*x = UpdateGatewayResponse{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[7]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -873,7 +1051,7 @@ func (x *UpdateGatewayResponse) String() string {
func (*UpdateGatewayResponse) ProtoMessage() {}
func (x *UpdateGatewayResponse) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[7]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -886,7 +1064,7 @@ func (x *UpdateGatewayResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use UpdateGatewayResponse.ProtoReflect.Descriptor instead.
func (*UpdateGatewayResponse) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{7}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{10}
}
func (x *UpdateGatewayResponse) GetGateway() *Gateway {
@@ -909,7 +1087,7 @@ type AdjustActiveSandboxCountRequest struct {
func (x *AdjustActiveSandboxCountRequest) Reset() {
*x = AdjustActiveSandboxCountRequest{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[8]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -921,7 +1099,7 @@ func (x *AdjustActiveSandboxCountRequest) String() string {
func (*AdjustActiveSandboxCountRequest) ProtoMessage() {}
func (x *AdjustActiveSandboxCountRequest) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[8]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[11]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -934,7 +1112,7 @@ func (x *AdjustActiveSandboxCountRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use AdjustActiveSandboxCountRequest.ProtoReflect.Descriptor instead.
func (*AdjustActiveSandboxCountRequest) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{8}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{11}
}
func (x *AdjustActiveSandboxCountRequest) GetNamespace() string {
@@ -962,7 +1140,7 @@ type AdjustActiveSandboxCountResponse struct {
func (x *AdjustActiveSandboxCountResponse) Reset() {
*x = AdjustActiveSandboxCountResponse{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[9]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -974,7 +1152,7 @@ func (x *AdjustActiveSandboxCountResponse) String() string {
func (*AdjustActiveSandboxCountResponse) ProtoMessage() {}
func (x *AdjustActiveSandboxCountResponse) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[9]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[12]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -987,7 +1165,7 @@ func (x *AdjustActiveSandboxCountResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use AdjustActiveSandboxCountResponse.ProtoReflect.Descriptor instead.
func (*AdjustActiveSandboxCountResponse) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{9}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{12}
}
func (x *AdjustActiveSandboxCountResponse) GetActiveSandboxCount() int32 {
@@ -1010,7 +1188,7 @@ type SetActiveSandboxCountRequest struct {
func (x *SetActiveSandboxCountRequest) Reset() {
*x = SetActiveSandboxCountRequest{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[10]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1022,7 +1200,7 @@ func (x *SetActiveSandboxCountRequest) String() string {
func (*SetActiveSandboxCountRequest) ProtoMessage() {}
func (x *SetActiveSandboxCountRequest) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[10]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[13]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1035,7 +1213,7 @@ func (x *SetActiveSandboxCountRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use SetActiveSandboxCountRequest.ProtoReflect.Descriptor instead.
func (*SetActiveSandboxCountRequest) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{10}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{13}
}
func (x *SetActiveSandboxCountRequest) GetNamespace() string {
@@ -1061,7 +1239,7 @@ type SetActiveSandboxCountResponse struct {
func (x *SetActiveSandboxCountResponse) Reset() {
*x = SetActiveSandboxCountResponse{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[11]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1073,7 +1251,7 @@ func (x *SetActiveSandboxCountResponse) String() string {
func (*SetActiveSandboxCountResponse) ProtoMessage() {}
func (x *SetActiveSandboxCountResponse) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[11]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[14]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1086,7 +1264,7 @@ func (x *SetActiveSandboxCountResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use SetActiveSandboxCountResponse.ProtoReflect.Descriptor instead.
func (*SetActiveSandboxCountResponse) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{11}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{14}
}
func (x *SetActiveSandboxCountResponse) GetActiveSandboxCount() int32 {
@@ -1108,7 +1286,7 @@ type SetGatewayVersionRequest struct {
func (x *SetGatewayVersionRequest) Reset() {
*x = SetGatewayVersionRequest{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[12]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1120,7 +1298,7 @@ func (x *SetGatewayVersionRequest) String() string {
func (*SetGatewayVersionRequest) ProtoMessage() {}
func (x *SetGatewayVersionRequest) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[12]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[15]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1133,7 +1311,7 @@ func (x *SetGatewayVersionRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use SetGatewayVersionRequest.ProtoReflect.Descriptor instead.
func (*SetGatewayVersionRequest) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{12}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{15}
}
func (x *SetGatewayVersionRequest) GetId() string {
@@ -1159,7 +1337,7 @@ type SetGatewayVersionResponse struct {
func (x *SetGatewayVersionResponse) Reset() {
*x = SetGatewayVersionResponse{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[13]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1171,7 +1349,7 @@ func (x *SetGatewayVersionResponse) String() string {
func (*SetGatewayVersionResponse) ProtoMessage() {}
func (x *SetGatewayVersionResponse) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[13]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[16]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1184,7 +1362,7 @@ func (x *SetGatewayVersionResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use SetGatewayVersionResponse.ProtoReflect.Descriptor instead.
func (*SetGatewayVersionResponse) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{13}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{16}
}
func (x *SetGatewayVersionResponse) GetGatewayVersion() string {
@@ -1203,7 +1381,7 @@ type DeleteGatewayRequest struct {
func (x *DeleteGatewayRequest) Reset() {
*x = DeleteGatewayRequest{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[14]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1215,7 +1393,7 @@ func (x *DeleteGatewayRequest) String() string {
func (*DeleteGatewayRequest) ProtoMessage() {}
func (x *DeleteGatewayRequest) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[14]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1228,7 +1406,7 @@ func (x *DeleteGatewayRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use DeleteGatewayRequest.ProtoReflect.Descriptor instead.
func (*DeleteGatewayRequest) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{14}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{17}
}
func (x *DeleteGatewayRequest) GetId() string {
@@ -1253,7 +1431,7 @@ type ListGatewaysRequest struct {
func (x *ListGatewaysRequest) Reset() {
*x = ListGatewaysRequest{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[15]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1265,7 +1443,7 @@ func (x *ListGatewaysRequest) String() string {
func (*ListGatewaysRequest) ProtoMessage() {}
func (x *ListGatewaysRequest) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[15]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[18]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1278,7 +1456,7 @@ func (x *ListGatewaysRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use ListGatewaysRequest.ProtoReflect.Descriptor instead.
func (*ListGatewaysRequest) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{15}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{18}
}
func (x *ListGatewaysRequest) GetPage() int32 {
@@ -1312,7 +1490,7 @@ type ListGatewaysResponse struct {
func (x *ListGatewaysResponse) Reset() {
*x = ListGatewaysResponse{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[16]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1324,7 +1502,7 @@ func (x *ListGatewaysResponse) String() string {
func (*ListGatewaysResponse) ProtoMessage() {}
func (x *ListGatewaysResponse) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[16]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[19]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1337,7 +1515,7 @@ func (x *ListGatewaysResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use ListGatewaysResponse.ProtoReflect.Descriptor instead.
func (*ListGatewaysResponse) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{16}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{19}
}
func (x *ListGatewaysResponse) GetItems() []*Gateway {
@@ -1362,7 +1540,7 @@ type DeleteGatewayResponse struct {
func (x *DeleteGatewayResponse) Reset() {
*x = DeleteGatewayResponse{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[17]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1374,7 +1552,7 @@ func (x *DeleteGatewayResponse) String() string {
func (*DeleteGatewayResponse) ProtoMessage() {}
func (x *DeleteGatewayResponse) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[17]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[20]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1387,7 +1565,7 @@ func (x *DeleteGatewayResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use DeleteGatewayResponse.ProtoReflect.Descriptor instead.
func (*DeleteGatewayResponse) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{17}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{20}
}
type WatchGatewaysRequest struct {
@@ -1403,7 +1581,7 @@ type WatchGatewaysRequest struct {
func (x *WatchGatewaysRequest) Reset() {
*x = WatchGatewaysRequest{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[18]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1415,7 +1593,7 @@ func (x *WatchGatewaysRequest) String() string {
func (*WatchGatewaysRequest) ProtoMessage() {}
func (x *WatchGatewaysRequest) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[18]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[21]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1428,7 +1606,7 @@ func (x *WatchGatewaysRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use WatchGatewaysRequest.ProtoReflect.Descriptor instead.
func (*WatchGatewaysRequest) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{18}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{21}
}
func (x *WatchGatewaysRequest) GetClusterId() string {
@@ -1449,7 +1627,7 @@ type WatchGatewaysResponse struct {
func (x *WatchGatewaysResponse) Reset() {
*x = WatchGatewaysResponse{}
- mi := &file_hypershell_v1_gateways_proto_msgTypes[19]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1461,7 +1639,7 @@ func (x *WatchGatewaysResponse) String() string {
func (*WatchGatewaysResponse) ProtoMessage() {}
func (x *WatchGatewaysResponse) ProtoReflect() protoreflect.Message {
- mi := &file_hypershell_v1_gateways_proto_msgTypes[19]
+ mi := &file_hypershell_v1_gateways_proto_msgTypes[22]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1474,7 +1652,7 @@ func (x *WatchGatewaysResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use WatchGatewaysResponse.ProtoReflect.Descriptor instead.
func (*WatchGatewaysResponse) Descriptor() ([]byte, []int) {
- return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{19}
+ return file_hypershell_v1_gateways_proto_rawDescGZIP(), []int{22}
}
func (x *WatchGatewaysResponse) GetType() EventType {
@@ -1506,7 +1684,16 @@ const file_hypershell_v1_gateways_proto_rawDesc = "" +
"\x15ProvisioningCondition\x12\x12\n" +
"\x04type\x18\x01 \x01(\tR\x04type\x12U\n" +
"\x10condition_status\x18\x02 \x01(\x0e2*.hypershell.v1.ProvisioningConditionStatusR\x0fconditionStatus\x12\x18\n" +
- "\amessage\x18\x03 \x01(\tR\amessage\"\x91\n" +
+ "\amessage\x18\x03 \x01(\tR\amessage\"\xbf\x01\n" +
+ "\x16GatewayPlacementIntent\x12T\n" +
+ "\x10network_provider\x18\x01 \x01(\v2'.hypershell.v1.NetworkProviderPlacementH\x00R\x0fnetworkProvider\x12B\n" +
+ "\n" +
+ "local_kind\x18\x02 \x01(\v2!.hypershell.v1.LocalKindPlacementH\x00R\tlocalKindB\v\n" +
+ "\tplacement\"P\n" +
+ "\x18NetworkProviderPlacement\x12\x18\n" +
+ "\anetwork\x18\x01 \x01(\tR\anetwork\x12\x1a\n" +
+ "\bprovider\x18\x02 \x01(\tR\bprovider\"\x14\n" +
+ "\x12LocalKindPlacement\"\x91\n" +
"\n" +
"\aGateway\x12:\n" +
"\bmetadata\x18\x01 \x01(\v2\x1e.hypershell.v1.ObjectReferenceR\bmetadata\x12\x12\n" +
@@ -1554,7 +1741,7 @@ const file_hypershell_v1_gateways_proto_rawDesc = "" +
"\x10_console_addressB\x12\n" +
"\x10_gateway_versionB\x16\n" +
"\x14_observed_release_idB\x16\n" +
- "\x14_observed_generationJ\x04\b\x03\x10\x04J\x04\b\x06\x10\aR\bfleet_idR\vdatabase_id\"\x9a\x05\n" +
+ "\x14_observed_generationJ\x04\b\x03\x10\x04J\x04\b\x06\x10\aR\bfleet_idR\vdatabase_id\"\xdf\x05\n" +
"\x14CreateGatewayRequest\x12\x12\n" +
"\x04name\x18\x01 \x01(\tR\x04name\x12\x1d\n" +
"\n" +
@@ -1572,7 +1759,8 @@ const file_hypershell_v1_gateways_proto_rawDesc = "" +
"\x10server_dns_names\x18\r \x03(\tR\x0eserverDnsNames\x12\x17\n" +
"\x04oidc\x18\x0e \x01(\tH\aR\x04oidc\x88\x01\x01\x12\x19\n" +
"\x05route\x18\x0f \x01(\tH\bR\x05route\x88\x01\x01\x120\n" +
- "\x11credential_driver\x18\x11 \x01(\tH\tR\x10credentialDriver\x88\x01\x01B\x0f\n" +
+ "\x11credential_driver\x18\x11 \x01(\tH\tR\x10credentialDriver\x88\x01\x01\x12C\n" +
+ "\tplacement\x18\x12 \x01(\v2%.hypershell.v1.GatewayPlacementIntentR\tplacementB\x0f\n" +
"\r_external_dnsB\v\n" +
"\t_tls_modeB\x0f\n" +
"\r_service_typeB\t\n" +
@@ -1700,68 +1888,74 @@ func file_hypershell_v1_gateways_proto_rawDescGZIP() []byte {
}
var file_hypershell_v1_gateways_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
-var file_hypershell_v1_gateways_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
+var file_hypershell_v1_gateways_proto_msgTypes = make([]protoimpl.MessageInfo, 23)
var file_hypershell_v1_gateways_proto_goTypes = []any{
(ProvisioningConditionStatus)(0), // 0: hypershell.v1.ProvisioningConditionStatus
(*ProvisioningCondition)(nil), // 1: hypershell.v1.ProvisioningCondition
- (*Gateway)(nil), // 2: hypershell.v1.Gateway
- (*CreateGatewayRequest)(nil), // 3: hypershell.v1.CreateGatewayRequest
- (*CreateGatewayResponse)(nil), // 4: hypershell.v1.CreateGatewayResponse
- (*GetGatewayRequest)(nil), // 5: hypershell.v1.GetGatewayRequest
- (*GetGatewayResponse)(nil), // 6: hypershell.v1.GetGatewayResponse
- (*UpdateGatewayRequest)(nil), // 7: hypershell.v1.UpdateGatewayRequest
- (*UpdateGatewayResponse)(nil), // 8: hypershell.v1.UpdateGatewayResponse
- (*AdjustActiveSandboxCountRequest)(nil), // 9: hypershell.v1.AdjustActiveSandboxCountRequest
- (*AdjustActiveSandboxCountResponse)(nil), // 10: hypershell.v1.AdjustActiveSandboxCountResponse
- (*SetActiveSandboxCountRequest)(nil), // 11: hypershell.v1.SetActiveSandboxCountRequest
- (*SetActiveSandboxCountResponse)(nil), // 12: hypershell.v1.SetActiveSandboxCountResponse
- (*SetGatewayVersionRequest)(nil), // 13: hypershell.v1.SetGatewayVersionRequest
- (*SetGatewayVersionResponse)(nil), // 14: hypershell.v1.SetGatewayVersionResponse
- (*DeleteGatewayRequest)(nil), // 15: hypershell.v1.DeleteGatewayRequest
- (*ListGatewaysRequest)(nil), // 16: hypershell.v1.ListGatewaysRequest
- (*ListGatewaysResponse)(nil), // 17: hypershell.v1.ListGatewaysResponse
- (*DeleteGatewayResponse)(nil), // 18: hypershell.v1.DeleteGatewayResponse
- (*WatchGatewaysRequest)(nil), // 19: hypershell.v1.WatchGatewaysRequest
- (*WatchGatewaysResponse)(nil), // 20: hypershell.v1.WatchGatewaysResponse
- (*ObjectReference)(nil), // 21: hypershell.v1.ObjectReference
- (*ListMeta)(nil), // 22: hypershell.v1.ListMeta
- (EventType)(0), // 23: hypershell.v1.EventType
+ (*GatewayPlacementIntent)(nil), // 2: hypershell.v1.GatewayPlacementIntent
+ (*NetworkProviderPlacement)(nil), // 3: hypershell.v1.NetworkProviderPlacement
+ (*LocalKindPlacement)(nil), // 4: hypershell.v1.LocalKindPlacement
+ (*Gateway)(nil), // 5: hypershell.v1.Gateway
+ (*CreateGatewayRequest)(nil), // 6: hypershell.v1.CreateGatewayRequest
+ (*CreateGatewayResponse)(nil), // 7: hypershell.v1.CreateGatewayResponse
+ (*GetGatewayRequest)(nil), // 8: hypershell.v1.GetGatewayRequest
+ (*GetGatewayResponse)(nil), // 9: hypershell.v1.GetGatewayResponse
+ (*UpdateGatewayRequest)(nil), // 10: hypershell.v1.UpdateGatewayRequest
+ (*UpdateGatewayResponse)(nil), // 11: hypershell.v1.UpdateGatewayResponse
+ (*AdjustActiveSandboxCountRequest)(nil), // 12: hypershell.v1.AdjustActiveSandboxCountRequest
+ (*AdjustActiveSandboxCountResponse)(nil), // 13: hypershell.v1.AdjustActiveSandboxCountResponse
+ (*SetActiveSandboxCountRequest)(nil), // 14: hypershell.v1.SetActiveSandboxCountRequest
+ (*SetActiveSandboxCountResponse)(nil), // 15: hypershell.v1.SetActiveSandboxCountResponse
+ (*SetGatewayVersionRequest)(nil), // 16: hypershell.v1.SetGatewayVersionRequest
+ (*SetGatewayVersionResponse)(nil), // 17: hypershell.v1.SetGatewayVersionResponse
+ (*DeleteGatewayRequest)(nil), // 18: hypershell.v1.DeleteGatewayRequest
+ (*ListGatewaysRequest)(nil), // 19: hypershell.v1.ListGatewaysRequest
+ (*ListGatewaysResponse)(nil), // 20: hypershell.v1.ListGatewaysResponse
+ (*DeleteGatewayResponse)(nil), // 21: hypershell.v1.DeleteGatewayResponse
+ (*WatchGatewaysRequest)(nil), // 22: hypershell.v1.WatchGatewaysRequest
+ (*WatchGatewaysResponse)(nil), // 23: hypershell.v1.WatchGatewaysResponse
+ (*ObjectReference)(nil), // 24: hypershell.v1.ObjectReference
+ (*ListMeta)(nil), // 25: hypershell.v1.ListMeta
+ (EventType)(0), // 26: hypershell.v1.EventType
}
var file_hypershell_v1_gateways_proto_depIdxs = []int32{
0, // 0: hypershell.v1.ProvisioningCondition.condition_status:type_name -> hypershell.v1.ProvisioningConditionStatus
- 21, // 1: hypershell.v1.Gateway.metadata:type_name -> hypershell.v1.ObjectReference
- 1, // 2: hypershell.v1.Gateway.provisioning_conditions:type_name -> hypershell.v1.ProvisioningCondition
- 2, // 3: hypershell.v1.CreateGatewayResponse.gateway:type_name -> hypershell.v1.Gateway
- 2, // 4: hypershell.v1.GetGatewayResponse.gateway:type_name -> hypershell.v1.Gateway
- 1, // 5: hypershell.v1.UpdateGatewayRequest.provisioning_conditions:type_name -> hypershell.v1.ProvisioningCondition
- 2, // 6: hypershell.v1.UpdateGatewayResponse.gateway:type_name -> hypershell.v1.Gateway
- 2, // 7: hypershell.v1.ListGatewaysResponse.items:type_name -> hypershell.v1.Gateway
- 22, // 8: hypershell.v1.ListGatewaysResponse.metadata:type_name -> hypershell.v1.ListMeta
- 23, // 9: hypershell.v1.WatchGatewaysResponse.type:type_name -> hypershell.v1.EventType
- 2, // 10: hypershell.v1.WatchGatewaysResponse.gateway:type_name -> hypershell.v1.Gateway
- 5, // 11: hypershell.v1.GatewayService.GetGateway:input_type -> hypershell.v1.GetGatewayRequest
- 3, // 12: hypershell.v1.GatewayService.CreateGateway:input_type -> hypershell.v1.CreateGatewayRequest
- 7, // 13: hypershell.v1.GatewayService.UpdateGateway:input_type -> hypershell.v1.UpdateGatewayRequest
- 15, // 14: hypershell.v1.GatewayService.DeleteGateway:input_type -> hypershell.v1.DeleteGatewayRequest
- 16, // 15: hypershell.v1.GatewayService.ListGateways:input_type -> hypershell.v1.ListGatewaysRequest
- 19, // 16: hypershell.v1.GatewayService.WatchGateways:input_type -> hypershell.v1.WatchGatewaysRequest
- 9, // 17: hypershell.v1.GatewayService.AdjustActiveSandboxCount:input_type -> hypershell.v1.AdjustActiveSandboxCountRequest
- 11, // 18: hypershell.v1.GatewayService.SetActiveSandboxCount:input_type -> hypershell.v1.SetActiveSandboxCountRequest
- 13, // 19: hypershell.v1.GatewayService.SetGatewayVersion:input_type -> hypershell.v1.SetGatewayVersionRequest
- 6, // 20: hypershell.v1.GatewayService.GetGateway:output_type -> hypershell.v1.GetGatewayResponse
- 4, // 21: hypershell.v1.GatewayService.CreateGateway:output_type -> hypershell.v1.CreateGatewayResponse
- 8, // 22: hypershell.v1.GatewayService.UpdateGateway:output_type -> hypershell.v1.UpdateGatewayResponse
- 18, // 23: hypershell.v1.GatewayService.DeleteGateway:output_type -> hypershell.v1.DeleteGatewayResponse
- 17, // 24: hypershell.v1.GatewayService.ListGateways:output_type -> hypershell.v1.ListGatewaysResponse
- 20, // 25: hypershell.v1.GatewayService.WatchGateways:output_type -> hypershell.v1.WatchGatewaysResponse
- 10, // 26: hypershell.v1.GatewayService.AdjustActiveSandboxCount:output_type -> hypershell.v1.AdjustActiveSandboxCountResponse
- 12, // 27: hypershell.v1.GatewayService.SetActiveSandboxCount:output_type -> hypershell.v1.SetActiveSandboxCountResponse
- 14, // 28: hypershell.v1.GatewayService.SetGatewayVersion:output_type -> hypershell.v1.SetGatewayVersionResponse
- 20, // [20:29] is the sub-list for method output_type
- 11, // [11:20] is the sub-list for method input_type
- 11, // [11:11] is the sub-list for extension type_name
- 11, // [11:11] is the sub-list for extension extendee
- 0, // [0:11] is the sub-list for field type_name
+ 3, // 1: hypershell.v1.GatewayPlacementIntent.network_provider:type_name -> hypershell.v1.NetworkProviderPlacement
+ 4, // 2: hypershell.v1.GatewayPlacementIntent.local_kind:type_name -> hypershell.v1.LocalKindPlacement
+ 24, // 3: hypershell.v1.Gateway.metadata:type_name -> hypershell.v1.ObjectReference
+ 1, // 4: hypershell.v1.Gateway.provisioning_conditions:type_name -> hypershell.v1.ProvisioningCondition
+ 2, // 5: hypershell.v1.CreateGatewayRequest.placement:type_name -> hypershell.v1.GatewayPlacementIntent
+ 5, // 6: hypershell.v1.CreateGatewayResponse.gateway:type_name -> hypershell.v1.Gateway
+ 5, // 7: hypershell.v1.GetGatewayResponse.gateway:type_name -> hypershell.v1.Gateway
+ 1, // 8: hypershell.v1.UpdateGatewayRequest.provisioning_conditions:type_name -> hypershell.v1.ProvisioningCondition
+ 5, // 9: hypershell.v1.UpdateGatewayResponse.gateway:type_name -> hypershell.v1.Gateway
+ 5, // 10: hypershell.v1.ListGatewaysResponse.items:type_name -> hypershell.v1.Gateway
+ 25, // 11: hypershell.v1.ListGatewaysResponse.metadata:type_name -> hypershell.v1.ListMeta
+ 26, // 12: hypershell.v1.WatchGatewaysResponse.type:type_name -> hypershell.v1.EventType
+ 5, // 13: hypershell.v1.WatchGatewaysResponse.gateway:type_name -> hypershell.v1.Gateway
+ 8, // 14: hypershell.v1.GatewayService.GetGateway:input_type -> hypershell.v1.GetGatewayRequest
+ 6, // 15: hypershell.v1.GatewayService.CreateGateway:input_type -> hypershell.v1.CreateGatewayRequest
+ 10, // 16: hypershell.v1.GatewayService.UpdateGateway:input_type -> hypershell.v1.UpdateGatewayRequest
+ 18, // 17: hypershell.v1.GatewayService.DeleteGateway:input_type -> hypershell.v1.DeleteGatewayRequest
+ 19, // 18: hypershell.v1.GatewayService.ListGateways:input_type -> hypershell.v1.ListGatewaysRequest
+ 22, // 19: hypershell.v1.GatewayService.WatchGateways:input_type -> hypershell.v1.WatchGatewaysRequest
+ 12, // 20: hypershell.v1.GatewayService.AdjustActiveSandboxCount:input_type -> hypershell.v1.AdjustActiveSandboxCountRequest
+ 14, // 21: hypershell.v1.GatewayService.SetActiveSandboxCount:input_type -> hypershell.v1.SetActiveSandboxCountRequest
+ 16, // 22: hypershell.v1.GatewayService.SetGatewayVersion:input_type -> hypershell.v1.SetGatewayVersionRequest
+ 9, // 23: hypershell.v1.GatewayService.GetGateway:output_type -> hypershell.v1.GetGatewayResponse
+ 7, // 24: hypershell.v1.GatewayService.CreateGateway:output_type -> hypershell.v1.CreateGatewayResponse
+ 11, // 25: hypershell.v1.GatewayService.UpdateGateway:output_type -> hypershell.v1.UpdateGatewayResponse
+ 21, // 26: hypershell.v1.GatewayService.DeleteGateway:output_type -> hypershell.v1.DeleteGatewayResponse
+ 20, // 27: hypershell.v1.GatewayService.ListGateways:output_type -> hypershell.v1.ListGatewaysResponse
+ 23, // 28: hypershell.v1.GatewayService.WatchGateways:output_type -> hypershell.v1.WatchGatewaysResponse
+ 13, // 29: hypershell.v1.GatewayService.AdjustActiveSandboxCount:output_type -> hypershell.v1.AdjustActiveSandboxCountResponse
+ 15, // 30: hypershell.v1.GatewayService.SetActiveSandboxCount:output_type -> hypershell.v1.SetActiveSandboxCountResponse
+ 17, // 31: hypershell.v1.GatewayService.SetGatewayVersion:output_type -> hypershell.v1.SetGatewayVersionResponse
+ 23, // [23:32] is the sub-list for method output_type
+ 14, // [14:23] is the sub-list for method input_type
+ 14, // [14:14] is the sub-list for extension type_name
+ 14, // [14:14] is the sub-list for extension extendee
+ 0, // [0:14] is the sub-list for field type_name
}
func init() { file_hypershell_v1_gateways_proto_init() }
@@ -1770,18 +1964,22 @@ func file_hypershell_v1_gateways_proto_init() {
return
}
file_hypershell_v1_common_proto_init()
- file_hypershell_v1_gateways_proto_msgTypes[1].OneofWrappers = []any{}
- file_hypershell_v1_gateways_proto_msgTypes[2].OneofWrappers = []any{}
- file_hypershell_v1_gateways_proto_msgTypes[6].OneofWrappers = []any{}
- file_hypershell_v1_gateways_proto_msgTypes[15].OneofWrappers = []any{}
+ file_hypershell_v1_gateways_proto_msgTypes[1].OneofWrappers = []any{
+ (*GatewayPlacementIntent_NetworkProvider)(nil),
+ (*GatewayPlacementIntent_LocalKind)(nil),
+ }
+ file_hypershell_v1_gateways_proto_msgTypes[4].OneofWrappers = []any{}
+ file_hypershell_v1_gateways_proto_msgTypes[5].OneofWrappers = []any{}
+ file_hypershell_v1_gateways_proto_msgTypes[9].OneofWrappers = []any{}
file_hypershell_v1_gateways_proto_msgTypes[18].OneofWrappers = []any{}
+ file_hypershell_v1_gateways_proto_msgTypes[21].OneofWrappers = []any{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_hypershell_v1_gateways_proto_rawDesc), len(file_hypershell_v1_gateways_proto_rawDesc)),
NumEnums: 1,
- NumMessages: 20,
+ NumMessages: 23,
NumExtensions: 0,
NumServices: 1,
},
diff --git a/components/api-server/pkg/api/openapi/.openapi-generator/FILES b/components/api-server/pkg/api/openapi/.openapi-generator/FILES
index b33907ac0..fa0ab9bc7 100644
--- a/components/api-server/pkg/api/openapi/.openapi-generator/FILES
+++ b/components/api-server/pkg/api/openapi/.openapi-generator/FILES
@@ -16,6 +16,8 @@ docs/GatewayAllOfProvisioningConditions.md
docs/GatewayCreateRequest.md
docs/GatewayList.md
docs/GatewayPatchRequest.md
+docs/GatewayPlacementAvailability.md
+docs/GatewayPlacementIntent.md
docs/InferenceRoute.md
docs/InferenceRouteList.md
docs/List.md
@@ -66,6 +68,8 @@ model_gateway_all_of_provisioning_conditions.go
model_gateway_create_request.go
model_gateway_list.go
model_gateway_patch_request.go
+model_gateway_placement_availability.go
+model_gateway_placement_intent.go
model_inference_route.go
model_inference_route_list.go
model_list.go
diff --git a/components/api-server/pkg/api/openapi/README.md b/components/api-server/pkg/api/openapi/README.md
index c98e9b5e9..f157380f6 100644
--- a/components/api-server/pkg/api/openapi/README.md
+++ b/components/api-server/pkg/api/openapi/README.md
@@ -100,6 +100,7 @@ Class | Method | HTTP request | Description
*DefaultAPI* | [**DeleteSecretSource**](docs/DefaultAPI.md#deletesecretsource) | **Delete** /api/hypershell/ext/secret_sources/{id} | Delete a secret source
*DefaultAPI* | [**GetAgentRuntime**](docs/DefaultAPI.md#getagentruntime) | **Get** /api/hypershell/ext/agent_runtimes/{id} | Get an agent runtime by ID
*DefaultAPI* | [**GetGateway**](docs/DefaultAPI.md#getgateway) | **Get** /api/hypershell/v1/gateways/{id} | Get an gateway by id
+*DefaultAPI* | [**GetGatewayPlacementAvailability**](docs/DefaultAPI.md#getgatewayplacementavailability) | **Get** /api/hypershell/v1/gateways/placement-availability | Returns current provider placement eligibility
*DefaultAPI* | [**GetGatewayServiceAccount**](docs/DefaultAPI.md#getgatewayserviceaccount) | **Get** /api/hypershell/v1/gateways/{gateway_id}/service_accounts/{service_account_id} | Get an OpenShell gateway service account
*DefaultAPI* | [**GetInferenceRoute**](docs/DefaultAPI.md#getinferenceroute) | **Get** /api/hypershell/ext/inference_routes/{id} | Get an inference route by ID
*DefaultAPI* | [**GetManagedCluster**](docs/DefaultAPI.md#getmanagedcluster) | **Get** /api/hypershell/v1/managed_clusters/{id} | Get an managedCluster by id
@@ -145,6 +146,8 @@ Class | Method | HTTP request | Description
- [GatewayCreateRequest](docs/GatewayCreateRequest.md)
- [GatewayList](docs/GatewayList.md)
- [GatewayPatchRequest](docs/GatewayPatchRequest.md)
+ - [GatewayPlacementAvailability](docs/GatewayPlacementAvailability.md)
+ - [GatewayPlacementIntent](docs/GatewayPlacementIntent.md)
- [InferenceRoute](docs/InferenceRoute.md)
- [InferenceRouteList](docs/InferenceRouteList.md)
- [List](docs/List.md)
diff --git a/components/api-server/pkg/api/openapi/api/openapi.yaml b/components/api-server/pkg/api/openapi/api/openapi.yaml
index c7a2ebdd4..e739bc88c 100644
--- a/components/api-server/pkg/api/openapi/api/openapi.yaml
+++ b/components/api-server/pkg/api/openapi/api/openapi.yaml
@@ -474,9 +474,9 @@ paths:
schema:
$ref: "#/components/schemas/Error"
description: |
- Validation errors occurred, including a cluster_id that is empty or does not
- reference a ManagedCluster with a registered control plane (non-empty
- oidc_subject). On update, cluster_id is validated only when it changes.
+ Validation errors occurred, including an invalid or unavailable placement
+ intent. The backend resolves a valid intent to a registered ManagedCluster
+ before creating the gateway.
"401":
content:
application/json:
@@ -504,6 +504,31 @@ paths:
security:
- Bearer: []
summary: Create a new gateway
+ /api/hypershell/v1/gateways/placement-availability:
+ get:
+ operationId: getGatewayPlacementAvailability
+ responses:
+ "200":
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/GatewayPlacementAvailability"
+ description: Current backend placement eligibility
+ "401":
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Error"
+ description: Auth token is invalid
+ "500":
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Error"
+ description: Unexpected error evaluating placement availability
+ security:
+ - Bearer: []
+ summary: Returns current provider placement eligibility
/api/hypershell/v1/gateways/{id}:
delete:
operationId: deleteGateway
@@ -2826,6 +2851,15 @@ components:
name:
type: string
provider:
+ description: Cloud provider capability used for gateway placement.
+ type: string
+ visibility:
+ description: Network visibility supported by this control plane for gateway
+ placement.
+ enum:
+ - public
+ - vpn
+ readOnly: true
type: string
region:
type: string
@@ -2852,6 +2886,7 @@ components:
- provider
type: object
example:
+ visibility: public
kind: kind
created_at: 2000-01-23T04:56:07.000+00:00
oidc_subject: oidc_subject
@@ -2884,7 +2919,8 @@ components:
id: id
href: href
items:
- - kind: kind
+ - visibility: public
+ kind: kind
created_at: 2000-01-23T04:56:07.000+00:00
oidc_subject: oidc_subject
updated_at: 2000-01-23T04:56:07.000+00:00
@@ -2897,7 +2933,8 @@ components:
last_seen_at: 2000-01-23T04:56:07.000+00:00
status: status
api_server_url: api_server_url
- - kind: kind
+ - visibility: public
+ kind: kind
created_at: 2000-01-23T04:56:07.000+00:00
oidc_subject: oidc_subject
updated_at: 2000-01-23T04:56:07.000+00:00
@@ -2934,6 +2971,8 @@ components:
type: object
ManagedClusterRegistrationRequest:
example:
+ visibility: public
+ provider: aws
name: name
description: description
properties:
@@ -2944,6 +2983,19 @@ components:
description:
description: Optional description of the spoke.
type: string
+ provider:
+ description: Cloud provider hosting this control plane.
+ enum:
+ - aws
+ - ibm
+ - kind
+ type: string
+ visibility:
+ description: Network visibility supported for gateways on this control plane.
+ enum:
+ - public
+ - vpn
+ type: string
required:
- name
type: object
@@ -3225,6 +3277,66 @@ components:
credential_driver:
type: string
type: object
+ GatewayPlacementIntent:
+ description: Exactly one of network/provider or mode must be supplied.
+ example:
+ mode: local-kind
+ provider: aws
+ network: public
+ nullable: true
+ oneOf: []
+ properties:
+ network:
+ enum:
+ - public
+ - vpn
+ type: string
+ provider:
+ description: IBM Cloud supports public placement only; VPN requires AWS.
+ enum:
+ - aws
+ - ibm
+ type: string
+ mode:
+ enum:
+ - local-kind
+ type: string
+ type: object
+ GatewayPlacementAvailability:
+ example:
+ aws_public: true
+ aws_reason: no-eligible-cluster
+ local_kind: true
+ ibm_reason: no-eligible-cluster
+ ibm_public: true
+ aws_vpn: true
+ ibm_vpn: true
+ properties:
+ aws_public:
+ type: boolean
+ aws_vpn:
+ type: boolean
+ ibm_public:
+ type: boolean
+ ibm_vpn:
+ type: boolean
+ local_kind:
+ type: boolean
+ aws_reason:
+ enum:
+ - no-eligible-cluster
+ type: string
+ ibm_reason:
+ enum:
+ - no-eligible-cluster
+ type: string
+ required:
+ - aws_public
+ - aws_vpn
+ - ibm_public
+ - ibm_vpn
+ - local_kind
+ type: object
OpenShellGatewayServiceAccountRole:
enum:
- openshell-user
@@ -4381,18 +4493,21 @@ components:
credential_driver: credential_driver
oidc: oidc
supervisor_image: supervisor_image
- cluster_id: cluster_id
service_type: service_type
tls_mode: tls_mode
route: route
name: name
+ placement:
+ mode: local-kind
+ provider: aws
+ network: public
external_dns: external_dns
status: status
properties:
name:
type: string
- cluster_id:
- type: string
+ placement:
+ $ref: "#/components/schemas/GatewayPlacementIntent"
external_dns:
type: string
tls_mode:
@@ -4424,8 +4539,8 @@ components:
description: JSON-encoded credential storage driver configuration
type: string
required:
- - cluster_id
- name
+ - placement
type: object
Gateway_allOf_provisioning_conditions:
example:
diff --git a/components/api-server/pkg/api/openapi/api_default.go b/components/api-server/pkg/api/openapi/api_default.go
index 29f832a78..aa7c563da 100644
--- a/components/api-server/pkg/api/openapi/api_default.go
+++ b/components/api-server/pkg/api/openapi/api_default.go
@@ -2894,6 +2894,125 @@ func (a *DefaultAPIService) GetGatewayExecute(r ApiGetGatewayRequest) (*Gateway,
return localVarReturnValue, localVarHTTPResponse, nil
}
+type ApiGetGatewayPlacementAvailabilityRequest struct {
+ ctx context.Context
+ ApiService *DefaultAPIService
+}
+
+func (r ApiGetGatewayPlacementAvailabilityRequest) Execute() (*GatewayPlacementAvailability, *http.Response, error) {
+ return r.ApiService.GetGatewayPlacementAvailabilityExecute(r)
+}
+
+/*
+GetGatewayPlacementAvailability Returns current provider placement eligibility
+
+ @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
+ @return ApiGetGatewayPlacementAvailabilityRequest
+*/
+func (a *DefaultAPIService) GetGatewayPlacementAvailability(ctx context.Context) ApiGetGatewayPlacementAvailabilityRequest {
+ return ApiGetGatewayPlacementAvailabilityRequest{
+ ApiService: a,
+ ctx: ctx,
+ }
+}
+
+// Execute executes the request
+//
+// @return GatewayPlacementAvailability
+func (a *DefaultAPIService) GetGatewayPlacementAvailabilityExecute(r ApiGetGatewayPlacementAvailabilityRequest) (*GatewayPlacementAvailability, *http.Response, error) {
+ var (
+ localVarHTTPMethod = http.MethodGet
+ localVarPostBody interface{}
+ formFiles []formFile
+ localVarReturnValue *GatewayPlacementAvailability
+ )
+
+ localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "DefaultAPIService.GetGatewayPlacementAvailability")
+ if err != nil {
+ return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()}
+ }
+
+ localVarPath := localBasePath + "/api/hypershell/v1/gateways/placement-availability"
+
+ localVarHeaderParams := make(map[string]string)
+ localVarQueryParams := url.Values{}
+ localVarFormParams := url.Values{}
+
+ // to determine the Content-Type header
+ localVarHTTPContentTypes := []string{}
+
+ // set Content-Type header
+ localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
+ if localVarHTTPContentType != "" {
+ localVarHeaderParams["Content-Type"] = localVarHTTPContentType
+ }
+
+ // to determine the Accept header
+ localVarHTTPHeaderAccepts := []string{"application/json"}
+
+ // set Accept header
+ localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
+ if localVarHTTPHeaderAccept != "" {
+ localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
+ }
+ req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles)
+ if err != nil {
+ return localVarReturnValue, nil, err
+ }
+
+ localVarHTTPResponse, err := a.client.callAPI(req)
+ if err != nil || localVarHTTPResponse == nil {
+ return localVarReturnValue, localVarHTTPResponse, err
+ }
+
+ localVarBody, err := io.ReadAll(localVarHTTPResponse.Body)
+ localVarHTTPResponse.Body.Close()
+ localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody))
+ if err != nil {
+ return localVarReturnValue, localVarHTTPResponse, err
+ }
+
+ if localVarHTTPResponse.StatusCode >= 300 {
+ newErr := &GenericOpenAPIError{
+ body: localVarBody,
+ error: localVarHTTPResponse.Status,
+ }
+ if localVarHTTPResponse.StatusCode == 401 {
+ var v Error
+ err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
+ if err != nil {
+ newErr.error = err.Error()
+ return localVarReturnValue, localVarHTTPResponse, newErr
+ }
+ newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
+ newErr.model = v
+ return localVarReturnValue, localVarHTTPResponse, newErr
+ }
+ if localVarHTTPResponse.StatusCode == 500 {
+ var v Error
+ err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
+ if err != nil {
+ newErr.error = err.Error()
+ return localVarReturnValue, localVarHTTPResponse, newErr
+ }
+ newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
+ newErr.model = v
+ }
+ return localVarReturnValue, localVarHTTPResponse, newErr
+ }
+
+ err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
+ if err != nil {
+ newErr := &GenericOpenAPIError{
+ body: localVarBody,
+ error: err.Error(),
+ }
+ return localVarReturnValue, localVarHTTPResponse, newErr
+ }
+
+ return localVarReturnValue, localVarHTTPResponse, nil
+}
+
type ApiGetGatewayServiceAccountRequest struct {
ctx context.Context
ApiService *DefaultAPIService
diff --git a/components/api-server/pkg/api/openapi/docs/DefaultAPI.md b/components/api-server/pkg/api/openapi/docs/DefaultAPI.md
index c10a0bccd..6c8a06334 100644
--- a/components/api-server/pkg/api/openapi/docs/DefaultAPI.md
+++ b/components/api-server/pkg/api/openapi/docs/DefaultAPI.md
@@ -26,6 +26,7 @@ Method | HTTP request | Description
[**DeleteSecretSource**](DefaultAPI.md#DeleteSecretSource) | **Delete** /api/hypershell/ext/secret_sources/{id} | Delete a secret source
[**GetAgentRuntime**](DefaultAPI.md#GetAgentRuntime) | **Get** /api/hypershell/ext/agent_runtimes/{id} | Get an agent runtime by ID
[**GetGateway**](DefaultAPI.md#GetGateway) | **Get** /api/hypershell/v1/gateways/{id} | Get an gateway by id
+[**GetGatewayPlacementAvailability**](DefaultAPI.md#GetGatewayPlacementAvailability) | **Get** /api/hypershell/v1/gateways/placement-availability | Returns current provider placement eligibility
[**GetGatewayServiceAccount**](DefaultAPI.md#GetGatewayServiceAccount) | **Get** /api/hypershell/v1/gateways/{gateway_id}/service_accounts/{service_account_id} | Get an OpenShell gateway service account
[**GetInferenceRoute**](DefaultAPI.md#GetInferenceRoute) | **Get** /api/hypershell/ext/inference_routes/{id} | Get an inference route by ID
[**GetManagedCluster**](DefaultAPI.md#GetManagedCluster) | **Get** /api/hypershell/v1/managed_clusters/{id} | Get an managedCluster by id
@@ -144,7 +145,7 @@ import (
)
func main() {
- gatewayCreateRequest := *openapiclient.NewGatewayCreateRequest("Name_example", "ClusterId_example") // GatewayCreateRequest | Gateway data
+ gatewayCreateRequest := *openapiclient.NewGatewayCreateRequest("Name_example", "TODO") // GatewayCreateRequest | Gateway data
configuration := openapiclient.NewConfiguration()
apiClient := openapiclient.NewAPIClient(configuration)
@@ -1508,6 +1509,65 @@ Name | Type | Description | Notes
[[Back to README]](../README.md)
+## GetGatewayPlacementAvailability
+
+> GatewayPlacementAvailability GetGatewayPlacementAvailability(ctx).Execute()
+
+Returns current provider placement eligibility
+
+### Example
+
+```go
+package main
+
+import (
+ "context"
+ "fmt"
+ "os"
+ openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID"
+)
+
+func main() {
+
+ configuration := openapiclient.NewConfiguration()
+ apiClient := openapiclient.NewAPIClient(configuration)
+ resp, r, err := apiClient.DefaultAPI.GetGatewayPlacementAvailability(context.Background()).Execute()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error when calling `DefaultAPI.GetGatewayPlacementAvailability``: %v\n", err)
+ fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)
+ }
+ // response from `GetGatewayPlacementAvailability`: GatewayPlacementAvailability
+ fmt.Fprintf(os.Stdout, "Response from `DefaultAPI.GetGatewayPlacementAvailability`: %v\n", resp)
+}
+```
+
+### Path Parameters
+
+This endpoint does not need any parameter.
+
+### Other Parameters
+
+Other parameters are passed through a pointer to a apiGetGatewayPlacementAvailabilityRequest struct via the builder pattern
+
+
+### Return type
+
+[**GatewayPlacementAvailability**](GatewayPlacementAvailability.md)
+
+### Authorization
+
+[Bearer](../README.md#Bearer)
+
+### HTTP request headers
+
+- **Content-Type**: Not defined
+- **Accept**: application/json
+
+[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints)
+[[Back to Model list]](../README.md#documentation-for-models)
+[[Back to README]](../README.md)
+
+
## GetGatewayServiceAccount
> OpenShellGatewayServiceAccountGetResponse GetGatewayServiceAccount(ctx, gatewayId, serviceAccountId).Execute()
diff --git a/components/api-server/pkg/api/openapi/docs/GatewayCreateRequest.md b/components/api-server/pkg/api/openapi/docs/GatewayCreateRequest.md
index 3a2a17300..33e981f18 100644
--- a/components/api-server/pkg/api/openapi/docs/GatewayCreateRequest.md
+++ b/components/api-server/pkg/api/openapi/docs/GatewayCreateRequest.md
@@ -5,7 +5,7 @@
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Name** | **string** | |
-**ClusterId** | **string** | |
+**Placement** | [**NullableGatewayPlacementIntent**](GatewayPlacementIntent.md) | |
**ExternalDns** | Pointer to **string** | | [optional]
**TlsMode** | Pointer to **string** | | [optional]
**ServiceType** | Pointer to **string** | | [optional]
@@ -22,7 +22,7 @@ Name | Type | Description | Notes
### NewGatewayCreateRequest
-`func NewGatewayCreateRequest(name string, clusterId string, ) *GatewayCreateRequest`
+`func NewGatewayCreateRequest(name string, placement NullableGatewayPlacementIntent, ) *GatewayCreateRequest`
NewGatewayCreateRequest instantiates a new GatewayCreateRequest object
This constructor will assign default values to properties that have it defined,
@@ -57,26 +57,36 @@ and a boolean to check if the value has been set.
SetName sets Name field to given value.
-### GetClusterId
+### GetPlacement
-`func (o *GatewayCreateRequest) GetClusterId() string`
+`func (o *GatewayCreateRequest) GetPlacement() GatewayPlacementIntent`
-GetClusterId returns the ClusterId field if non-nil, zero value otherwise.
+GetPlacement returns the Placement field if non-nil, zero value otherwise.
-### GetClusterIdOk
+### GetPlacementOk
-`func (o *GatewayCreateRequest) GetClusterIdOk() (*string, bool)`
+`func (o *GatewayCreateRequest) GetPlacementOk() (*GatewayPlacementIntent, bool)`
-GetClusterIdOk returns a tuple with the ClusterId field if it's non-nil, zero value otherwise
+GetPlacementOk returns a tuple with the Placement field if it's non-nil, zero value otherwise
and a boolean to check if the value has been set.
-### SetClusterId
+### SetPlacement
-`func (o *GatewayCreateRequest) SetClusterId(v string)`
+`func (o *GatewayCreateRequest) SetPlacement(v GatewayPlacementIntent)`
-SetClusterId sets ClusterId field to given value.
+SetPlacement sets Placement field to given value.
+### SetPlacementNil
+
+`func (o *GatewayCreateRequest) SetPlacementNil(b bool)`
+
+ SetPlacementNil sets the value for Placement to be an explicit nil
+
+### UnsetPlacement
+`func (o *GatewayCreateRequest) UnsetPlacement()`
+
+UnsetPlacement ensures that no value is present for Placement, not even an explicit nil
### GetExternalDns
`func (o *GatewayCreateRequest) GetExternalDns() string`
diff --git a/components/api-server/pkg/api/openapi/docs/GatewayPlacementAvailability.md b/components/api-server/pkg/api/openapi/docs/GatewayPlacementAvailability.md
new file mode 100644
index 000000000..386edab2e
--- /dev/null
+++ b/components/api-server/pkg/api/openapi/docs/GatewayPlacementAvailability.md
@@ -0,0 +1,187 @@
+# GatewayPlacementAvailability
+
+## Properties
+
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**AwsPublic** | **bool** | |
+**AwsVpn** | **bool** | |
+**IbmPublic** | **bool** | |
+**IbmVpn** | **bool** | |
+**LocalKind** | **bool** | |
+**AwsReason** | Pointer to **string** | | [optional]
+**IbmReason** | Pointer to **string** | | [optional]
+
+## Methods
+
+### NewGatewayPlacementAvailability
+
+`func NewGatewayPlacementAvailability(awsPublic bool, awsVpn bool, ibmPublic bool, ibmVpn bool, localKind bool, ) *GatewayPlacementAvailability`
+
+NewGatewayPlacementAvailability instantiates a new GatewayPlacementAvailability object
+This constructor will assign default values to properties that have it defined,
+and makes sure properties required by API are set, but the set of arguments
+will change when the set of required properties is changed
+
+### NewGatewayPlacementAvailabilityWithDefaults
+
+`func NewGatewayPlacementAvailabilityWithDefaults() *GatewayPlacementAvailability`
+
+NewGatewayPlacementAvailabilityWithDefaults instantiates a new GatewayPlacementAvailability object
+This constructor will only assign default values to properties that have it defined,
+but it doesn't guarantee that properties required by API are set
+
+### GetAwsPublic
+
+`func (o *GatewayPlacementAvailability) GetAwsPublic() bool`
+
+GetAwsPublic returns the AwsPublic field if non-nil, zero value otherwise.
+
+### GetAwsPublicOk
+
+`func (o *GatewayPlacementAvailability) GetAwsPublicOk() (*bool, bool)`
+
+GetAwsPublicOk returns a tuple with the AwsPublic field if it's non-nil, zero value otherwise
+and a boolean to check if the value has been set.
+
+### SetAwsPublic
+
+`func (o *GatewayPlacementAvailability) SetAwsPublic(v bool)`
+
+SetAwsPublic sets AwsPublic field to given value.
+
+
+### GetAwsVpn
+
+`func (o *GatewayPlacementAvailability) GetAwsVpn() bool`
+
+GetAwsVpn returns the AwsVpn field if non-nil, zero value otherwise.
+
+### GetAwsVpnOk
+
+`func (o *GatewayPlacementAvailability) GetAwsVpnOk() (*bool, bool)`
+
+GetAwsVpnOk returns a tuple with the AwsVpn field if it's non-nil, zero value otherwise
+and a boolean to check if the value has been set.
+
+### SetAwsVpn
+
+`func (o *GatewayPlacementAvailability) SetAwsVpn(v bool)`
+
+SetAwsVpn sets AwsVpn field to given value.
+
+
+### GetIbmPublic
+
+`func (o *GatewayPlacementAvailability) GetIbmPublic() bool`
+
+GetIbmPublic returns the IbmPublic field if non-nil, zero value otherwise.
+
+### GetIbmPublicOk
+
+`func (o *GatewayPlacementAvailability) GetIbmPublicOk() (*bool, bool)`
+
+GetIbmPublicOk returns a tuple with the IbmPublic field if it's non-nil, zero value otherwise
+and a boolean to check if the value has been set.
+
+### SetIbmPublic
+
+`func (o *GatewayPlacementAvailability) SetIbmPublic(v bool)`
+
+SetIbmPublic sets IbmPublic field to given value.
+
+
+### GetIbmVpn
+
+`func (o *GatewayPlacementAvailability) GetIbmVpn() bool`
+
+GetIbmVpn returns the IbmVpn field if non-nil, zero value otherwise.
+
+### GetIbmVpnOk
+
+`func (o *GatewayPlacementAvailability) GetIbmVpnOk() (*bool, bool)`
+
+GetIbmVpnOk returns a tuple with the IbmVpn field if it's non-nil, zero value otherwise
+and a boolean to check if the value has been set.
+
+### SetIbmVpn
+
+`func (o *GatewayPlacementAvailability) SetIbmVpn(v bool)`
+
+SetIbmVpn sets IbmVpn field to given value.
+
+
+### GetLocalKind
+
+`func (o *GatewayPlacementAvailability) GetLocalKind() bool`
+
+GetLocalKind returns the LocalKind field if non-nil, zero value otherwise.
+
+### GetLocalKindOk
+
+`func (o *GatewayPlacementAvailability) GetLocalKindOk() (*bool, bool)`
+
+GetLocalKindOk returns a tuple with the LocalKind field if it's non-nil, zero value otherwise
+and a boolean to check if the value has been set.
+
+### SetLocalKind
+
+`func (o *GatewayPlacementAvailability) SetLocalKind(v bool)`
+
+SetLocalKind sets LocalKind field to given value.
+
+
+### GetAwsReason
+
+`func (o *GatewayPlacementAvailability) GetAwsReason() string`
+
+GetAwsReason returns the AwsReason field if non-nil, zero value otherwise.
+
+### GetAwsReasonOk
+
+`func (o *GatewayPlacementAvailability) GetAwsReasonOk() (*string, bool)`
+
+GetAwsReasonOk returns a tuple with the AwsReason field if it's non-nil, zero value otherwise
+and a boolean to check if the value has been set.
+
+### SetAwsReason
+
+`func (o *GatewayPlacementAvailability) SetAwsReason(v string)`
+
+SetAwsReason sets AwsReason field to given value.
+
+### HasAwsReason
+
+`func (o *GatewayPlacementAvailability) HasAwsReason() bool`
+
+HasAwsReason returns a boolean if a field has been set.
+
+### GetIbmReason
+
+`func (o *GatewayPlacementAvailability) GetIbmReason() string`
+
+GetIbmReason returns the IbmReason field if non-nil, zero value otherwise.
+
+### GetIbmReasonOk
+
+`func (o *GatewayPlacementAvailability) GetIbmReasonOk() (*string, bool)`
+
+GetIbmReasonOk returns a tuple with the IbmReason field if it's non-nil, zero value otherwise
+and a boolean to check if the value has been set.
+
+### SetIbmReason
+
+`func (o *GatewayPlacementAvailability) SetIbmReason(v string)`
+
+SetIbmReason sets IbmReason field to given value.
+
+### HasIbmReason
+
+`func (o *GatewayPlacementAvailability) HasIbmReason() bool`
+
+HasIbmReason returns a boolean if a field has been set.
+
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
+
+
diff --git a/components/api-server/pkg/api/openapi/docs/GatewayPlacementIntent.md b/components/api-server/pkg/api/openapi/docs/GatewayPlacementIntent.md
new file mode 100644
index 000000000..7889310df
--- /dev/null
+++ b/components/api-server/pkg/api/openapi/docs/GatewayPlacementIntent.md
@@ -0,0 +1,108 @@
+# GatewayPlacementIntent
+
+## Properties
+
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**Network** | Pointer to **string** | | [optional]
+**Provider** | Pointer to **string** | IBM Cloud supports public placement only; VPN requires AWS. | [optional]
+**Mode** | Pointer to **string** | | [optional]
+
+## Methods
+
+### NewGatewayPlacementIntent
+
+`func NewGatewayPlacementIntent() *GatewayPlacementIntent`
+
+NewGatewayPlacementIntent instantiates a new GatewayPlacementIntent object
+This constructor will assign default values to properties that have it defined,
+and makes sure properties required by API are set, but the set of arguments
+will change when the set of required properties is changed
+
+### NewGatewayPlacementIntentWithDefaults
+
+`func NewGatewayPlacementIntentWithDefaults() *GatewayPlacementIntent`
+
+NewGatewayPlacementIntentWithDefaults instantiates a new GatewayPlacementIntent object
+This constructor will only assign default values to properties that have it defined,
+but it doesn't guarantee that properties required by API are set
+
+### GetNetwork
+
+`func (o *GatewayPlacementIntent) GetNetwork() string`
+
+GetNetwork returns the Network field if non-nil, zero value otherwise.
+
+### GetNetworkOk
+
+`func (o *GatewayPlacementIntent) GetNetworkOk() (*string, bool)`
+
+GetNetworkOk returns a tuple with the Network field if it's non-nil, zero value otherwise
+and a boolean to check if the value has been set.
+
+### SetNetwork
+
+`func (o *GatewayPlacementIntent) SetNetwork(v string)`
+
+SetNetwork sets Network field to given value.
+
+### HasNetwork
+
+`func (o *GatewayPlacementIntent) HasNetwork() bool`
+
+HasNetwork returns a boolean if a field has been set.
+
+### GetProvider
+
+`func (o *GatewayPlacementIntent) GetProvider() string`
+
+GetProvider returns the Provider field if non-nil, zero value otherwise.
+
+### GetProviderOk
+
+`func (o *GatewayPlacementIntent) GetProviderOk() (*string, bool)`
+
+GetProviderOk returns a tuple with the Provider field if it's non-nil, zero value otherwise
+and a boolean to check if the value has been set.
+
+### SetProvider
+
+`func (o *GatewayPlacementIntent) SetProvider(v string)`
+
+SetProvider sets Provider field to given value.
+
+### HasProvider
+
+`func (o *GatewayPlacementIntent) HasProvider() bool`
+
+HasProvider returns a boolean if a field has been set.
+
+### GetMode
+
+`func (o *GatewayPlacementIntent) GetMode() string`
+
+GetMode returns the Mode field if non-nil, zero value otherwise.
+
+### GetModeOk
+
+`func (o *GatewayPlacementIntent) GetModeOk() (*string, bool)`
+
+GetModeOk returns a tuple with the Mode field if it's non-nil, zero value otherwise
+and a boolean to check if the value has been set.
+
+### SetMode
+
+`func (o *GatewayPlacementIntent) SetMode(v string)`
+
+SetMode sets Mode field to given value.
+
+### HasMode
+
+`func (o *GatewayPlacementIntent) HasMode() bool`
+
+HasMode returns a boolean if a field has been set.
+
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
+
+
diff --git a/components/api-server/pkg/api/openapi/docs/ManagedCluster.md b/components/api-server/pkg/api/openapi/docs/ManagedCluster.md
index 8799634fc..09d1479ba 100644
--- a/components/api-server/pkg/api/openapi/docs/ManagedCluster.md
+++ b/components/api-server/pkg/api/openapi/docs/ManagedCluster.md
@@ -10,7 +10,8 @@ Name | Type | Description | Notes
**CreatedAt** | Pointer to **time.Time** | | [optional]
**UpdatedAt** | Pointer to **time.Time** | | [optional]
**Name** | **string** | |
-**Provider** | **string** | |
+**Provider** | **string** | Cloud provider capability used for gateway placement. |
+**Visibility** | Pointer to **string** | Network visibility supported by this control plane for gateway placement. | [optional] [readonly]
**Region** | Pointer to **string** | | [optional]
**KubeconfigSecret** | **string** | |
**Status** | Pointer to **string** | | [optional]
@@ -202,6 +203,31 @@ and a boolean to check if the value has been set.
SetProvider sets Provider field to given value.
+### GetVisibility
+
+`func (o *ManagedCluster) GetVisibility() string`
+
+GetVisibility returns the Visibility field if non-nil, zero value otherwise.
+
+### GetVisibilityOk
+
+`func (o *ManagedCluster) GetVisibilityOk() (*string, bool)`
+
+GetVisibilityOk returns a tuple with the Visibility field if it's non-nil, zero value otherwise
+and a boolean to check if the value has been set.
+
+### SetVisibility
+
+`func (o *ManagedCluster) SetVisibility(v string)`
+
+SetVisibility sets Visibility field to given value.
+
+### HasVisibility
+
+`func (o *ManagedCluster) HasVisibility() bool`
+
+HasVisibility returns a boolean if a field has been set.
+
### GetRegion
`func (o *ManagedCluster) GetRegion() string`
diff --git a/components/api-server/pkg/api/openapi/docs/ManagedClusterRegistrationRequest.md b/components/api-server/pkg/api/openapi/docs/ManagedClusterRegistrationRequest.md
index 7706e10e0..ea4cec65e 100644
--- a/components/api-server/pkg/api/openapi/docs/ManagedClusterRegistrationRequest.md
+++ b/components/api-server/pkg/api/openapi/docs/ManagedClusterRegistrationRequest.md
@@ -6,6 +6,8 @@ Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Name** | **string** | Human-readable spoke name, unique per fleet (e.g. hyp0-mc1). Must match on every subsequent call. |
**Description** | Pointer to **string** | Optional description of the spoke. | [optional]
+**Provider** | Pointer to **string** | Cloud provider hosting this control plane. | [optional]
+**Visibility** | Pointer to **string** | Network visibility supported for gateways on this control plane. | [optional]
## Methods
@@ -71,6 +73,56 @@ SetDescription sets Description field to given value.
HasDescription returns a boolean if a field has been set.
+### GetProvider
+
+`func (o *ManagedClusterRegistrationRequest) GetProvider() string`
+
+GetProvider returns the Provider field if non-nil, zero value otherwise.
+
+### GetProviderOk
+
+`func (o *ManagedClusterRegistrationRequest) GetProviderOk() (*string, bool)`
+
+GetProviderOk returns a tuple with the Provider field if it's non-nil, zero value otherwise
+and a boolean to check if the value has been set.
+
+### SetProvider
+
+`func (o *ManagedClusterRegistrationRequest) SetProvider(v string)`
+
+SetProvider sets Provider field to given value.
+
+### HasProvider
+
+`func (o *ManagedClusterRegistrationRequest) HasProvider() bool`
+
+HasProvider returns a boolean if a field has been set.
+
+### GetVisibility
+
+`func (o *ManagedClusterRegistrationRequest) GetVisibility() string`
+
+GetVisibility returns the Visibility field if non-nil, zero value otherwise.
+
+### GetVisibilityOk
+
+`func (o *ManagedClusterRegistrationRequest) GetVisibilityOk() (*string, bool)`
+
+GetVisibilityOk returns a tuple with the Visibility field if it's non-nil, zero value otherwise
+and a boolean to check if the value has been set.
+
+### SetVisibility
+
+`func (o *ManagedClusterRegistrationRequest) SetVisibility(v string)`
+
+SetVisibility sets Visibility field to given value.
+
+### HasVisibility
+
+`func (o *ManagedClusterRegistrationRequest) HasVisibility() bool`
+
+HasVisibility returns a boolean if a field has been set.
+
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
diff --git a/components/api-server/pkg/api/openapi/model_gateway_create_request.go b/components/api-server/pkg/api/openapi/model_gateway_create_request.go
index bab7ebcab..452d01010 100644
--- a/components/api-server/pkg/api/openapi/model_gateway_create_request.go
+++ b/components/api-server/pkg/api/openapi/model_gateway_create_request.go
@@ -21,13 +21,13 @@ var _ MappedNullable = &GatewayCreateRequest{}
// GatewayCreateRequest struct for GatewayCreateRequest
type GatewayCreateRequest struct {
- Name string `json:"name"`
- ClusterId string `json:"cluster_id"`
- ExternalDns *string `json:"external_dns,omitempty"`
- TlsMode *string `json:"tls_mode,omitempty"`
- ServiceType *string `json:"service_type,omitempty"`
- Status *string `json:"status,omitempty"`
- Phase *string `json:"phase,omitempty"`
+ Name string `json:"name"`
+ Placement NullableGatewayPlacementIntent `json:"placement"`
+ ExternalDns *string `json:"external_dns,omitempty"`
+ TlsMode *string `json:"tls_mode,omitempty"`
+ ServiceType *string `json:"service_type,omitempty"`
+ Status *string `json:"status,omitempty"`
+ Phase *string `json:"phase,omitempty"`
// Container image for the gateway deployment
Image *string `json:"image,omitempty"`
// Container image for the supervisor sidecar
@@ -48,10 +48,10 @@ type _GatewayCreateRequest GatewayCreateRequest
// This constructor will assign default values to properties that have it defined,
// and makes sure properties required by API are set, but the set of arguments
// will change when the set of required properties is changed
-func NewGatewayCreateRequest(name string, clusterId string) *GatewayCreateRequest {
+func NewGatewayCreateRequest(name string, placement NullableGatewayPlacementIntent) *GatewayCreateRequest {
this := GatewayCreateRequest{}
this.Name = name
- this.ClusterId = clusterId
+ this.Placement = placement
return &this
}
@@ -87,28 +87,30 @@ func (o *GatewayCreateRequest) SetName(v string) {
o.Name = v
}
-// GetClusterId returns the ClusterId field value
-func (o *GatewayCreateRequest) GetClusterId() string {
- if o == nil {
- var ret string
+// GetPlacement returns the Placement field value
+// If the value is explicit nil, the zero value for GatewayPlacementIntent will be returned
+func (o *GatewayCreateRequest) GetPlacement() GatewayPlacementIntent {
+ if o == nil || o.Placement.Get() == nil {
+ var ret GatewayPlacementIntent
return ret
}
- return o.ClusterId
+ return *o.Placement.Get()
}
-// GetClusterIdOk returns a tuple with the ClusterId field value
+// GetPlacementOk returns a tuple with the Placement field value
// and a boolean to check if the value has been set.
-func (o *GatewayCreateRequest) GetClusterIdOk() (*string, bool) {
+// NOTE: If the value is an explicit nil, `nil, true` will be returned
+func (o *GatewayCreateRequest) GetPlacementOk() (*GatewayPlacementIntent, bool) {
if o == nil {
return nil, false
}
- return &o.ClusterId, true
+ return o.Placement.Get(), o.Placement.IsSet()
}
-// SetClusterId sets field value
-func (o *GatewayCreateRequest) SetClusterId(v string) {
- o.ClusterId = v
+// SetPlacement sets field value
+func (o *GatewayCreateRequest) SetPlacement(v GatewayPlacementIntent) {
+ o.Placement.Set(&v)
}
// GetExternalDns returns the ExternalDns field value if set, zero value otherwise.
@@ -474,7 +476,7 @@ func (o GatewayCreateRequest) MarshalJSON() ([]byte, error) {
func (o GatewayCreateRequest) ToMap() (map[string]interface{}, error) {
toSerialize := map[string]interface{}{}
toSerialize["name"] = o.Name
- toSerialize["cluster_id"] = o.ClusterId
+ toSerialize["placement"] = o.Placement.Get()
if !IsNil(o.ExternalDns) {
toSerialize["external_dns"] = o.ExternalDns
}
@@ -517,7 +519,7 @@ func (o *GatewayCreateRequest) UnmarshalJSON(data []byte) (err error) {
// that every required field exists as a key in the generic map.
requiredProperties := []string{
"name",
- "cluster_id",
+ "placement",
}
allProperties := make(map[string]interface{})
diff --git a/components/api-server/pkg/api/openapi/model_gateway_placement_availability.go b/components/api-server/pkg/api/openapi/model_gateway_placement_availability.go
new file mode 100644
index 000000000..56e041210
--- /dev/null
+++ b/components/api-server/pkg/api/openapi/model_gateway_placement_availability.go
@@ -0,0 +1,340 @@
+/*
+HyperShell API
+
+HyperShell gateway management API
+
+API version: 1.0.0
+*/
+
+// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
+
+package openapi
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+)
+
+// checks if the GatewayPlacementAvailability type satisfies the MappedNullable interface at compile time
+var _ MappedNullable = &GatewayPlacementAvailability{}
+
+// GatewayPlacementAvailability struct for GatewayPlacementAvailability
+type GatewayPlacementAvailability struct {
+ AwsPublic bool `json:"aws_public"`
+ AwsVpn bool `json:"aws_vpn"`
+ IbmPublic bool `json:"ibm_public"`
+ IbmVpn bool `json:"ibm_vpn"`
+ LocalKind bool `json:"local_kind"`
+ AwsReason *string `json:"aws_reason,omitempty"`
+ IbmReason *string `json:"ibm_reason,omitempty"`
+}
+
+type _GatewayPlacementAvailability GatewayPlacementAvailability
+
+// NewGatewayPlacementAvailability instantiates a new GatewayPlacementAvailability object
+// This constructor will assign default values to properties that have it defined,
+// and makes sure properties required by API are set, but the set of arguments
+// will change when the set of required properties is changed
+func NewGatewayPlacementAvailability(awsPublic bool, awsVpn bool, ibmPublic bool, ibmVpn bool, localKind bool) *GatewayPlacementAvailability {
+ this := GatewayPlacementAvailability{}
+ this.AwsPublic = awsPublic
+ this.AwsVpn = awsVpn
+ this.IbmPublic = ibmPublic
+ this.IbmVpn = ibmVpn
+ this.LocalKind = localKind
+ return &this
+}
+
+// NewGatewayPlacementAvailabilityWithDefaults instantiates a new GatewayPlacementAvailability object
+// This constructor will only assign default values to properties that have it defined,
+// but it doesn't guarantee that properties required by API are set
+func NewGatewayPlacementAvailabilityWithDefaults() *GatewayPlacementAvailability {
+ this := GatewayPlacementAvailability{}
+ return &this
+}
+
+// GetAwsPublic returns the AwsPublic field value
+func (o *GatewayPlacementAvailability) GetAwsPublic() bool {
+ if o == nil {
+ var ret bool
+ return ret
+ }
+
+ return o.AwsPublic
+}
+
+// GetAwsPublicOk returns a tuple with the AwsPublic field value
+// and a boolean to check if the value has been set.
+func (o *GatewayPlacementAvailability) GetAwsPublicOk() (*bool, bool) {
+ if o == nil {
+ return nil, false
+ }
+ return &o.AwsPublic, true
+}
+
+// SetAwsPublic sets field value
+func (o *GatewayPlacementAvailability) SetAwsPublic(v bool) {
+ o.AwsPublic = v
+}
+
+// GetAwsVpn returns the AwsVpn field value
+func (o *GatewayPlacementAvailability) GetAwsVpn() bool {
+ if o == nil {
+ var ret bool
+ return ret
+ }
+
+ return o.AwsVpn
+}
+
+// GetAwsVpnOk returns a tuple with the AwsVpn field value
+// and a boolean to check if the value has been set.
+func (o *GatewayPlacementAvailability) GetAwsVpnOk() (*bool, bool) {
+ if o == nil {
+ return nil, false
+ }
+ return &o.AwsVpn, true
+}
+
+// SetAwsVpn sets field value
+func (o *GatewayPlacementAvailability) SetAwsVpn(v bool) {
+ o.AwsVpn = v
+}
+
+// GetIbmPublic returns the IbmPublic field value
+func (o *GatewayPlacementAvailability) GetIbmPublic() bool {
+ if o == nil {
+ var ret bool
+ return ret
+ }
+
+ return o.IbmPublic
+}
+
+// GetIbmPublicOk returns a tuple with the IbmPublic field value
+// and a boolean to check if the value has been set.
+func (o *GatewayPlacementAvailability) GetIbmPublicOk() (*bool, bool) {
+ if o == nil {
+ return nil, false
+ }
+ return &o.IbmPublic, true
+}
+
+// SetIbmPublic sets field value
+func (o *GatewayPlacementAvailability) SetIbmPublic(v bool) {
+ o.IbmPublic = v
+}
+
+// GetIbmVpn returns the IbmVpn field value
+func (o *GatewayPlacementAvailability) GetIbmVpn() bool {
+ if o == nil {
+ var ret bool
+ return ret
+ }
+
+ return o.IbmVpn
+}
+
+// GetIbmVpnOk returns a tuple with the IbmVpn field value
+// and a boolean to check if the value has been set.
+func (o *GatewayPlacementAvailability) GetIbmVpnOk() (*bool, bool) {
+ if o == nil {
+ return nil, false
+ }
+ return &o.IbmVpn, true
+}
+
+// SetIbmVpn sets field value
+func (o *GatewayPlacementAvailability) SetIbmVpn(v bool) {
+ o.IbmVpn = v
+}
+
+// GetLocalKind returns the LocalKind field value
+func (o *GatewayPlacementAvailability) GetLocalKind() bool {
+ if o == nil {
+ var ret bool
+ return ret
+ }
+
+ return o.LocalKind
+}
+
+// GetLocalKindOk returns a tuple with the LocalKind field value
+// and a boolean to check if the value has been set.
+func (o *GatewayPlacementAvailability) GetLocalKindOk() (*bool, bool) {
+ if o == nil {
+ return nil, false
+ }
+ return &o.LocalKind, true
+}
+
+// SetLocalKind sets field value
+func (o *GatewayPlacementAvailability) SetLocalKind(v bool) {
+ o.LocalKind = v
+}
+
+// GetAwsReason returns the AwsReason field value if set, zero value otherwise.
+func (o *GatewayPlacementAvailability) GetAwsReason() string {
+ if o == nil || IsNil(o.AwsReason) {
+ var ret string
+ return ret
+ }
+ return *o.AwsReason
+}
+
+// GetAwsReasonOk returns a tuple with the AwsReason field value if set, nil otherwise
+// and a boolean to check if the value has been set.
+func (o *GatewayPlacementAvailability) GetAwsReasonOk() (*string, bool) {
+ if o == nil || IsNil(o.AwsReason) {
+ return nil, false
+ }
+ return o.AwsReason, true
+}
+
+// HasAwsReason returns a boolean if a field has been set.
+func (o *GatewayPlacementAvailability) HasAwsReason() bool {
+ if o != nil && !IsNil(o.AwsReason) {
+ return true
+ }
+
+ return false
+}
+
+// SetAwsReason gets a reference to the given string and assigns it to the AwsReason field.
+func (o *GatewayPlacementAvailability) SetAwsReason(v string) {
+ o.AwsReason = &v
+}
+
+// GetIbmReason returns the IbmReason field value if set, zero value otherwise.
+func (o *GatewayPlacementAvailability) GetIbmReason() string {
+ if o == nil || IsNil(o.IbmReason) {
+ var ret string
+ return ret
+ }
+ return *o.IbmReason
+}
+
+// GetIbmReasonOk returns a tuple with the IbmReason field value if set, nil otherwise
+// and a boolean to check if the value has been set.
+func (o *GatewayPlacementAvailability) GetIbmReasonOk() (*string, bool) {
+ if o == nil || IsNil(o.IbmReason) {
+ return nil, false
+ }
+ return o.IbmReason, true
+}
+
+// HasIbmReason returns a boolean if a field has been set.
+func (o *GatewayPlacementAvailability) HasIbmReason() bool {
+ if o != nil && !IsNil(o.IbmReason) {
+ return true
+ }
+
+ return false
+}
+
+// SetIbmReason gets a reference to the given string and assigns it to the IbmReason field.
+func (o *GatewayPlacementAvailability) SetIbmReason(v string) {
+ o.IbmReason = &v
+}
+
+func (o GatewayPlacementAvailability) MarshalJSON() ([]byte, error) {
+ toSerialize, err := o.ToMap()
+ if err != nil {
+ return []byte{}, err
+ }
+ return json.Marshal(toSerialize)
+}
+
+func (o GatewayPlacementAvailability) ToMap() (map[string]interface{}, error) {
+ toSerialize := map[string]interface{}{}
+ toSerialize["aws_public"] = o.AwsPublic
+ toSerialize["aws_vpn"] = o.AwsVpn
+ toSerialize["ibm_public"] = o.IbmPublic
+ toSerialize["ibm_vpn"] = o.IbmVpn
+ toSerialize["local_kind"] = o.LocalKind
+ if !IsNil(o.AwsReason) {
+ toSerialize["aws_reason"] = o.AwsReason
+ }
+ if !IsNil(o.IbmReason) {
+ toSerialize["ibm_reason"] = o.IbmReason
+ }
+ return toSerialize, nil
+}
+
+func (o *GatewayPlacementAvailability) UnmarshalJSON(data []byte) (err error) {
+ // This validates that all required properties are included in the JSON object
+ // by unmarshalling the object into a generic map with string keys and checking
+ // that every required field exists as a key in the generic map.
+ requiredProperties := []string{
+ "aws_public",
+ "aws_vpn",
+ "ibm_public",
+ "ibm_vpn",
+ "local_kind",
+ }
+
+ allProperties := make(map[string]interface{})
+
+ err = json.Unmarshal(data, &allProperties)
+
+ if err != nil {
+ return err
+ }
+
+ for _, requiredProperty := range requiredProperties {
+ if _, exists := allProperties[requiredProperty]; !exists {
+ return fmt.Errorf("no value given for required property %v", requiredProperty)
+ }
+ }
+
+ varGatewayPlacementAvailability := _GatewayPlacementAvailability{}
+
+ decoder := json.NewDecoder(bytes.NewReader(data))
+ decoder.DisallowUnknownFields()
+ err = decoder.Decode(&varGatewayPlacementAvailability)
+
+ if err != nil {
+ return err
+ }
+
+ *o = GatewayPlacementAvailability(varGatewayPlacementAvailability)
+
+ return err
+}
+
+type NullableGatewayPlacementAvailability struct {
+ value *GatewayPlacementAvailability
+ isSet bool
+}
+
+func (v NullableGatewayPlacementAvailability) Get() *GatewayPlacementAvailability {
+ return v.value
+}
+
+func (v *NullableGatewayPlacementAvailability) Set(val *GatewayPlacementAvailability) {
+ v.value = val
+ v.isSet = true
+}
+
+func (v NullableGatewayPlacementAvailability) IsSet() bool {
+ return v.isSet
+}
+
+func (v *NullableGatewayPlacementAvailability) Unset() {
+ v.value = nil
+ v.isSet = false
+}
+
+func NewNullableGatewayPlacementAvailability(val *GatewayPlacementAvailability) *NullableGatewayPlacementAvailability {
+ return &NullableGatewayPlacementAvailability{value: val, isSet: true}
+}
+
+func (v NullableGatewayPlacementAvailability) MarshalJSON() ([]byte, error) {
+ return json.Marshal(v.value)
+}
+
+func (v *NullableGatewayPlacementAvailability) UnmarshalJSON(src []byte) error {
+ v.isSet = true
+ return json.Unmarshal(src, &v.value)
+}
diff --git a/components/api-server/pkg/api/openapi/model_gateway_placement_intent.go b/components/api-server/pkg/api/openapi/model_gateway_placement_intent.go
new file mode 100644
index 000000000..bf38526b8
--- /dev/null
+++ b/components/api-server/pkg/api/openapi/model_gateway_placement_intent.go
@@ -0,0 +1,197 @@
+/*
+HyperShell API
+
+HyperShell gateway management API
+
+API version: 1.0.0
+*/
+
+// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
+
+package openapi
+
+import (
+ "encoding/json"
+)
+
+// checks if the GatewayPlacementIntent type satisfies the MappedNullable interface at compile time
+var _ MappedNullable = &GatewayPlacementIntent{}
+
+// GatewayPlacementIntent Exactly one of network/provider or mode must be supplied.
+type GatewayPlacementIntent struct {
+ Network *string
+ // IBM Cloud supports public placement only; VPN requires AWS.
+ Provider *string
+ Mode *string
+}
+
+// NewGatewayPlacementIntent instantiates a new GatewayPlacementIntent object
+// This constructor will assign default values to properties that have it defined,
+// and makes sure properties required by API are set, but the set of arguments
+// will change when the set of required properties is changed
+func NewGatewayPlacementIntent() *GatewayPlacementIntent {
+ this := GatewayPlacementIntent{}
+ return &this
+}
+
+// NewGatewayPlacementIntentWithDefaults instantiates a new GatewayPlacementIntent object
+// This constructor will only assign default values to properties that have it defined,
+// but it doesn't guarantee that properties required by API are set
+func NewGatewayPlacementIntentWithDefaults() *GatewayPlacementIntent {
+ this := GatewayPlacementIntent{}
+ return &this
+}
+
+// GetNetwork returns the Network field value if set, zero value otherwise.
+func (o *GatewayPlacementIntent) GetNetwork() string {
+ if o == nil || IsNil(o.Network) {
+ var ret string
+ return ret
+ }
+ return *o.Network
+}
+
+// GetNetworkOk returns a tuple with the Network field value if set, nil otherwise
+// and a boolean to check if the value has been set.
+func (o *GatewayPlacementIntent) GetNetworkOk() (*string, bool) {
+ if o == nil || IsNil(o.Network) {
+ return nil, false
+ }
+ return o.Network, true
+}
+
+// HasNetwork returns a boolean if a field has been set.
+func (o *GatewayPlacementIntent) HasNetwork() bool {
+ if o != nil && !IsNil(o.Network) {
+ return true
+ }
+
+ return false
+}
+
+// SetNetwork gets a reference to the given string and assigns it to the Network field.
+func (o *GatewayPlacementIntent) SetNetwork(v string) {
+ o.Network = &v
+}
+
+// GetProvider returns the Provider field value if set, zero value otherwise.
+func (o *GatewayPlacementIntent) GetProvider() string {
+ if o == nil || IsNil(o.Provider) {
+ var ret string
+ return ret
+ }
+ return *o.Provider
+}
+
+// GetProviderOk returns a tuple with the Provider field value if set, nil otherwise
+// and a boolean to check if the value has been set.
+func (o *GatewayPlacementIntent) GetProviderOk() (*string, bool) {
+ if o == nil || IsNil(o.Provider) {
+ return nil, false
+ }
+ return o.Provider, true
+}
+
+// HasProvider returns a boolean if a field has been set.
+func (o *GatewayPlacementIntent) HasProvider() bool {
+ if o != nil && !IsNil(o.Provider) {
+ return true
+ }
+
+ return false
+}
+
+// SetProvider gets a reference to the given string and assigns it to the Provider field.
+func (o *GatewayPlacementIntent) SetProvider(v string) {
+ o.Provider = &v
+}
+
+// GetMode returns the Mode field value if set, zero value otherwise.
+func (o *GatewayPlacementIntent) GetMode() string {
+ if o == nil || IsNil(o.Mode) {
+ var ret string
+ return ret
+ }
+ return *o.Mode
+}
+
+// GetModeOk returns a tuple with the Mode field value if set, nil otherwise
+// and a boolean to check if the value has been set.
+func (o *GatewayPlacementIntent) GetModeOk() (*string, bool) {
+ if o == nil || IsNil(o.Mode) {
+ return nil, false
+ }
+ return o.Mode, true
+}
+
+// HasMode returns a boolean if a field has been set.
+func (o *GatewayPlacementIntent) HasMode() bool {
+ if o != nil && !IsNil(o.Mode) {
+ return true
+ }
+
+ return false
+}
+
+// SetMode gets a reference to the given string and assigns it to the Mode field.
+func (o *GatewayPlacementIntent) SetMode(v string) {
+ o.Mode = &v
+}
+
+func (o GatewayPlacementIntent) MarshalJSON() ([]byte, error) {
+ toSerialize, err := o.ToMap()
+ if err != nil {
+ return []byte{}, err
+ }
+ return json.Marshal(toSerialize)
+}
+
+func (o GatewayPlacementIntent) ToMap() (map[string]interface{}, error) {
+ toSerialize := map[string]interface{}{}
+ if !IsNil(o.Network) {
+ toSerialize["network"] = o.Network
+ }
+ if !IsNil(o.Provider) {
+ toSerialize["provider"] = o.Provider
+ }
+ if !IsNil(o.Mode) {
+ toSerialize["mode"] = o.Mode
+ }
+ return toSerialize, nil
+}
+
+type NullableGatewayPlacementIntent struct {
+ value *GatewayPlacementIntent
+ isSet bool
+}
+
+func (v NullableGatewayPlacementIntent) Get() *GatewayPlacementIntent {
+ return v.value
+}
+
+func (v *NullableGatewayPlacementIntent) Set(val *GatewayPlacementIntent) {
+ v.value = val
+ v.isSet = true
+}
+
+func (v NullableGatewayPlacementIntent) IsSet() bool {
+ return v.isSet
+}
+
+func (v *NullableGatewayPlacementIntent) Unset() {
+ v.value = nil
+ v.isSet = false
+}
+
+func NewNullableGatewayPlacementIntent(val *GatewayPlacementIntent) *NullableGatewayPlacementIntent {
+ return &NullableGatewayPlacementIntent{value: val, isSet: true}
+}
+
+func (v NullableGatewayPlacementIntent) MarshalJSON() ([]byte, error) {
+ return json.Marshal(v.value)
+}
+
+func (v *NullableGatewayPlacementIntent) UnmarshalJSON(src []byte) error {
+ v.isSet = true
+ return json.Unmarshal(src, &v.value)
+}
diff --git a/components/api-server/pkg/api/openapi/model_managed_cluster.go b/components/api-server/pkg/api/openapi/model_managed_cluster.go
index aba2ca4a4..a4d6b3acd 100644
--- a/components/api-server/pkg/api/openapi/model_managed_cluster.go
+++ b/components/api-server/pkg/api/openapi/model_managed_cluster.go
@@ -22,17 +22,20 @@ var _ MappedNullable = &ManagedCluster{}
// ManagedCluster struct for ManagedCluster
type ManagedCluster struct {
- Id *string `json:"id,omitempty"`
- Kind *string `json:"kind,omitempty"`
- Href *string `json:"href,omitempty"`
- CreatedAt *time.Time `json:"created_at,omitempty"`
- UpdatedAt *time.Time `json:"updated_at,omitempty"`
- Name string `json:"name"`
- Provider string `json:"provider"`
- Region *string `json:"region,omitempty"`
- KubeconfigSecret string `json:"kubeconfig_secret"`
- Status *string `json:"status,omitempty"`
- ApiServerUrl *string `json:"api_server_url,omitempty"`
+ Id *string `json:"id,omitempty"`
+ Kind *string `json:"kind,omitempty"`
+ Href *string `json:"href,omitempty"`
+ CreatedAt *time.Time `json:"created_at,omitempty"`
+ UpdatedAt *time.Time `json:"updated_at,omitempty"`
+ Name string `json:"name"`
+ // Cloud provider capability used for gateway placement.
+ Provider string `json:"provider"`
+ // Network visibility supported by this control plane for gateway placement.
+ Visibility *string `json:"visibility,omitempty"`
+ Region *string `json:"region,omitempty"`
+ KubeconfigSecret string `json:"kubeconfig_secret"`
+ Status *string `json:"status,omitempty"`
+ ApiServerUrl *string `json:"api_server_url,omitempty"`
// OIDC sub claim of the service account that registered this cluster. Server-assigned; not writable.
OidcSubject *string `json:"oidc_subject,omitempty"`
// Timestamp of the most recent registration call. Updated on every POST /registration.
@@ -269,6 +272,38 @@ func (o *ManagedCluster) SetProvider(v string) {
o.Provider = v
}
+// GetVisibility returns the Visibility field value if set, zero value otherwise.
+func (o *ManagedCluster) GetVisibility() string {
+ if o == nil || IsNil(o.Visibility) {
+ var ret string
+ return ret
+ }
+ return *o.Visibility
+}
+
+// GetVisibilityOk returns a tuple with the Visibility field value if set, nil otherwise
+// and a boolean to check if the value has been set.
+func (o *ManagedCluster) GetVisibilityOk() (*string, bool) {
+ if o == nil || IsNil(o.Visibility) {
+ return nil, false
+ }
+ return o.Visibility, true
+}
+
+// HasVisibility returns a boolean if a field has been set.
+func (o *ManagedCluster) HasVisibility() bool {
+ if o != nil && !IsNil(o.Visibility) {
+ return true
+ }
+
+ return false
+}
+
+// SetVisibility gets a reference to the given string and assigns it to the Visibility field.
+func (o *ManagedCluster) SetVisibility(v string) {
+ o.Visibility = &v
+}
+
// GetRegion returns the Region field value if set, zero value otherwise.
func (o *ManagedCluster) GetRegion() string {
if o == nil || IsNil(o.Region) {
@@ -480,6 +515,9 @@ func (o ManagedCluster) ToMap() (map[string]interface{}, error) {
}
toSerialize["name"] = o.Name
toSerialize["provider"] = o.Provider
+ if !IsNil(o.Visibility) {
+ toSerialize["visibility"] = o.Visibility
+ }
if !IsNil(o.Region) {
toSerialize["region"] = o.Region
}
diff --git a/components/api-server/pkg/api/openapi/model_managed_cluster_registration_request.go b/components/api-server/pkg/api/openapi/model_managed_cluster_registration_request.go
index 0ef47e4a2..3f253f8e2 100644
--- a/components/api-server/pkg/api/openapi/model_managed_cluster_registration_request.go
+++ b/components/api-server/pkg/api/openapi/model_managed_cluster_registration_request.go
@@ -25,6 +25,10 @@ type ManagedClusterRegistrationRequest struct {
Name string `json:"name"`
// Optional description of the spoke.
Description *string `json:"description,omitempty"`
+ // Cloud provider hosting this control plane.
+ Provider *string `json:"provider,omitempty"`
+ // Network visibility supported for gateways on this control plane.
+ Visibility *string `json:"visibility,omitempty"`
}
type _ManagedClusterRegistrationRequest ManagedClusterRegistrationRequest
@@ -103,6 +107,70 @@ func (o *ManagedClusterRegistrationRequest) SetDescription(v string) {
o.Description = &v
}
+// GetProvider returns the Provider field value if set, zero value otherwise.
+func (o *ManagedClusterRegistrationRequest) GetProvider() string {
+ if o == nil || IsNil(o.Provider) {
+ var ret string
+ return ret
+ }
+ return *o.Provider
+}
+
+// GetProviderOk returns a tuple with the Provider field value if set, nil otherwise
+// and a boolean to check if the value has been set.
+func (o *ManagedClusterRegistrationRequest) GetProviderOk() (*string, bool) {
+ if o == nil || IsNil(o.Provider) {
+ return nil, false
+ }
+ return o.Provider, true
+}
+
+// HasProvider returns a boolean if a field has been set.
+func (o *ManagedClusterRegistrationRequest) HasProvider() bool {
+ if o != nil && !IsNil(o.Provider) {
+ return true
+ }
+
+ return false
+}
+
+// SetProvider gets a reference to the given string and assigns it to the Provider field.
+func (o *ManagedClusterRegistrationRequest) SetProvider(v string) {
+ o.Provider = &v
+}
+
+// GetVisibility returns the Visibility field value if set, zero value otherwise.
+func (o *ManagedClusterRegistrationRequest) GetVisibility() string {
+ if o == nil || IsNil(o.Visibility) {
+ var ret string
+ return ret
+ }
+ return *o.Visibility
+}
+
+// GetVisibilityOk returns a tuple with the Visibility field value if set, nil otherwise
+// and a boolean to check if the value has been set.
+func (o *ManagedClusterRegistrationRequest) GetVisibilityOk() (*string, bool) {
+ if o == nil || IsNil(o.Visibility) {
+ return nil, false
+ }
+ return o.Visibility, true
+}
+
+// HasVisibility returns a boolean if a field has been set.
+func (o *ManagedClusterRegistrationRequest) HasVisibility() bool {
+ if o != nil && !IsNil(o.Visibility) {
+ return true
+ }
+
+ return false
+}
+
+// SetVisibility gets a reference to the given string and assigns it to the Visibility field.
+func (o *ManagedClusterRegistrationRequest) SetVisibility(v string) {
+ o.Visibility = &v
+}
+
func (o ManagedClusterRegistrationRequest) MarshalJSON() ([]byte, error) {
toSerialize, err := o.ToMap()
if err != nil {
@@ -117,6 +185,12 @@ func (o ManagedClusterRegistrationRequest) ToMap() (map[string]interface{}, erro
if !IsNil(o.Description) {
toSerialize["description"] = o.Description
}
+ if !IsNil(o.Provider) {
+ toSerialize["provider"] = o.Provider
+ }
+ if !IsNil(o.Visibility) {
+ toSerialize["visibility"] = o.Visibility
+ }
return toSerialize, nil
}
diff --git a/components/api-server/pkg/api/openapi_embed_test.go b/components/api-server/pkg/api/openapi_embed_test.go
index 05e6f7a6c..4a43be33c 100644
--- a/components/api-server/pkg/api/openapi_embed_test.go
+++ b/components/api-server/pkg/api/openapi_embed_test.go
@@ -55,8 +55,8 @@ func TestGetOpenAPISpecReturnsCompleteContract(t *testing.T) {
operationIDs[operation.OperationID] = method + " " + path
}
}
- if operationCount != 54 {
- t.Fatalf("embedded operation count = %d, want 54", operationCount)
+ if operationCount != 55 {
+ t.Fatalf("embedded operation count = %d, want 55", operationCount)
}
expectedDeletes := map[string]string{
diff --git a/components/api-server/plugins/gateways/availability_handler_test.go b/components/api-server/plugins/gateways/availability_handler_test.go
new file mode 100644
index 000000000..af5b5a43d
--- /dev/null
+++ b/components/api-server/plugins/gateways/availability_handler_test.go
@@ -0,0 +1,31 @@
+package gateways
+
+import (
+ "context"
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+
+ "github.com/openshift-online/hypershell/components/api-server/pkg/api/openapi"
+ "github.com/openshift-online/rh-trex-ai/components/api-server/pkg/errors"
+)
+
+func TestGetPlacementAvailabilityAcceptsEmptyGetBody(t *testing.T) {
+ handler := gatewayHandler{
+ availability: func(context.Context) (openapi.GatewayPlacementAvailability, *errors.ServiceError) {
+ return openapi.GatewayPlacementAvailability{LocalKind: true}, nil
+ },
+ }
+
+ request := httptest.NewRequest(http.MethodGet, "/gateways/placement-availability", nil)
+ response := httptest.NewRecorder()
+ handler.GetPlacementAvailability(response, request)
+
+ if response.Code != http.StatusOK {
+ t.Fatalf("status = %d, body = %s", response.Code, response.Body.String())
+ }
+ if !strings.Contains(response.Body.String(), `"local_kind":true`) {
+ t.Fatalf("response body = %s", response.Body.String())
+ }
+}
diff --git a/components/api-server/plugins/gateways/cluster_fixture_test.go b/components/api-server/plugins/gateways/cluster_fixture_test.go
index 9573f87d7..3663d5ccc 100644
--- a/components/api-server/plugins/gateways/cluster_fixture_test.go
+++ b/components/api-server/plugins/gateways/cluster_fixture_test.go
@@ -8,22 +8,31 @@ import (
. "github.com/onsi/gomega"
+ "github.com/openshift-online/hypershell/components/api-server/pkg/api/openapi"
"github.com/openshift-online/hypershell/components/api-server/plugins/managedClusters"
- "github.com/openshift-online/hypershell/components/api-server/test"
"github.com/openshift-online/rh-trex-ai/components/api-server/pkg/api"
"github.com/openshift-online/rh-trex-ai/components/api-server/pkg/environments"
)
// registerTestCluster registers a ManagedCluster the way a control plane does
// (a unique OIDC subject via POST /registration semantics) and returns its id.
-// Gateway create/update handlers accept only a cluster_id that references a
-// registered cluster (managed-cluster-registration.spec.md).
+// Placement resolution and gateway update handlers use only registered
+// clusters (managed-cluster-registration.spec.md).
func registerTestCluster(t *testing.T) string {
t.Helper()
id, _ := registerTestClusterWithSubject(t)
return id
}
+func managedGatewayCreateRequest(name string) openapi.GatewayCreateRequest {
+ request := openapi.GatewayCreateRequest{Name: name}
+ request.SetPlacement(openapi.GatewayPlacementIntent{
+ Network: openapi.PtrString("public"),
+ Provider: openapi.PtrString("aws"),
+ })
+ return request
+}
+
// registerTestClusterWithSubject is registerTestCluster that also returns the
// OIDC subject the cluster registered under, so a test can act as its control
// plane.
@@ -40,7 +49,7 @@ func mustRegisterCluster() (string, string) {
subject := "cp-" + suffix
name := fmt.Sprintf("mc-%s", suffix)
svc := managedClusters.Service(&environments.Environment().Services)
- cluster, _, svcErr := svc.Register(context.Background(), name, "", subject)
+ cluster, _, svcErr := svc.Register(context.Background(), name, "", "aws", "public", subject)
Expect(svcErr).To(BeNil(), "register test managed cluster %s", name)
return cluster.ID, subject
}
@@ -59,7 +68,3 @@ func createManualCluster(t *testing.T) string {
}
return cluster.ID
}
-
-func openapiErrorReason(_ *test.Helper, err error) string {
- return test.APIErrorReason(err)
-}
diff --git a/components/api-server/plugins/gateways/cluster_reference.go b/components/api-server/plugins/gateways/cluster_reference.go
index 6902797c3..d49b4c0c9 100644
--- a/components/api-server/plugins/gateways/cluster_reference.go
+++ b/components/api-server/plugins/gateways/cluster_reference.go
@@ -4,9 +4,42 @@ import (
"context"
"strings"
+ "github.com/openshift-online/hypershell/components/api-server/pkg/api/openapi"
"github.com/openshift-online/rh-trex-ai/components/api-server/pkg/errors"
)
+type PlacementResolver func(context.Context, openapi.GatewayPlacementIntent) (string, *errors.ServiceError)
+type PlacementAvailabilityResolver func(context.Context) (openapi.GatewayPlacementAvailability, *errors.ServiceError)
+
+func validatePlacementIntent(intent openapi.GatewayPlacementIntent) *errors.ServiceError {
+ mode, network, provider := "", "", ""
+ if intent.Mode != nil {
+ mode = *intent.Mode
+ }
+ if intent.Network != nil {
+ network = *intent.Network
+ }
+ if intent.Provider != nil {
+ provider = *intent.Provider
+ }
+ if mode != "" {
+ if mode != "local-kind" || network != "" || provider != "" {
+ return errors.Validation("placement mode must be local-kind and cannot include network or provider")
+ }
+ return nil
+ }
+ if network != "public" && network != "vpn" {
+ return errors.Validation("placement.network must be public or vpn")
+ }
+ if provider != "aws" && provider != "ibm" {
+ return errors.Validation("placement.provider must be aws or ibm")
+ }
+ if network == "vpn" && provider != "aws" {
+ return errors.Validation("VPN placement requires provider aws")
+ }
+ return nil
+}
+
// RegisteredClusterLookup reports whether id names a ManagedCluster that a
// control plane registered (non-empty oidc_subject). It returns (false, nil) for
// an unknown id or a manually created record, and an error only when the lookup
diff --git a/components/api-server/plugins/gateways/grpc_handler.go b/components/api-server/plugins/gateways/grpc_handler.go
index 1730d3c67..8136b86ab 100644
--- a/components/api-server/plugins/gateways/grpc_handler.go
+++ b/components/api-server/plugins/gateways/grpc_handler.go
@@ -11,6 +11,7 @@ import (
"google.golang.org/grpc/status"
pb "github.com/openshift-online/hypershell/components/api-server/pkg/api/grpc/hypershell/v1"
+ "github.com/openshift-online/hypershell/components/api-server/pkg/api/openapi"
"github.com/openshift-online/hypershell/components/api-server/pkg/gatewayhealth"
"github.com/openshift-online/rh-trex-ai/components/api-server/pkg/api"
pkgserver "github.com/openshift-online/rh-trex-ai/components/api-server/pkg/server"
@@ -24,10 +25,15 @@ type gatewayGRPCHandler struct {
generic services.GenericService
brokerFunc func() *pkgserver.EventBroker
clusters RegisteredClusterLookup
+ placement PlacementResolver
}
-func NewGatewayGRPCHandler(svc GatewayService, generic services.GenericService, brokerFunc func() *pkgserver.EventBroker, clusters RegisteredClusterLookup) pb.GatewayServiceServer {
- return &gatewayGRPCHandler{service: svc, generic: generic, brokerFunc: brokerFunc, clusters: clusters}
+func NewGatewayGRPCHandler(svc GatewayService, generic services.GenericService, brokerFunc func() *pkgserver.EventBroker, clusters RegisteredClusterLookup, placement ...PlacementResolver) pb.GatewayServiceServer {
+ h := &gatewayGRPCHandler{service: svc, generic: generic, brokerFunc: brokerFunc, clusters: clusters}
+ if len(placement) > 0 {
+ h.placement = placement[0]
+ }
+ return h
}
// validateGatewayPhase rejects a phase outside the canonical vocabulary. An
@@ -58,13 +64,37 @@ func (h *gatewayGRPCHandler) CreateGateway(ctx context.Context, req *pb.CreateGa
if err := grpcutil.ValidateStringField("name", req.Name, true); err != nil {
return nil, err
}
- if err := grpcutil.ValidateStringField("cluster_id", req.ClusterId, true); err != nil {
+ if err := validateGatewayPhase(req.Phase); err != nil {
return nil, err
}
- if err := validateGatewayPhase(req.Phase); err != nil {
+ clusterID := req.ClusterId
+ if req.Placement != nil {
+ if h.placement == nil {
+ return nil, status.Error(codes.FailedPrecondition, "gateway placement resolver is unavailable")
+ }
+ intent := openapi.GatewayPlacementIntent{}
+ if network := req.Placement.GetNetworkProvider(); network != nil {
+ intent.Network = &network.Network
+ intent.Provider = &network.Provider
+ } else if req.Placement.GetLocalKind() != nil {
+ mode := "local-kind"
+ intent.Mode = &mode
+ } else {
+ return nil, status.Error(codes.InvalidArgument, "placement intent is empty")
+ }
+ if svcErr := validatePlacementIntent(intent); svcErr != nil {
+ return nil, grpcutil.ServiceErrorToGRPC(svcErr)
+ }
+ resolved, svcErr := h.placement(ctx, intent)
+ if svcErr != nil {
+ return nil, grpcutil.ServiceErrorToGRPC(svcErr)
+ }
+ clusterID = resolved
+ }
+ if err := grpcutil.ValidateStringField("cluster_id", clusterID, true); err != nil {
return nil, err
}
- if svcErr := validateClusterReference(ctx, h.clusters, req.ClusterId); svcErr != nil {
+ if svcErr := validateClusterReference(ctx, h.clusters, clusterID); svcErr != nil {
return nil, grpcutil.ServiceErrorToGRPC(svcErr)
}
var serverDnsNamesJSON *string
@@ -76,7 +106,7 @@ func (h *gatewayGRPCHandler) CreateGateway(ctx context.Context, req *pb.CreateGa
gateway := &Gateway{
Name: req.Name,
- ClusterId: req.ClusterId,
+ ClusterId: clusterID,
ExternalDns: req.ExternalDns,
TlsMode: req.TlsMode,
ServiceType: req.ServiceType,
diff --git a/components/api-server/plugins/gateways/grpc_integration_test.go b/components/api-server/plugins/gateways/grpc_integration_test.go
index 8d0334b52..f27c9d775 100644
--- a/components/api-server/plugins/gateways/grpc_integration_test.go
+++ b/components/api-server/plugins/gateways/grpc_integration_test.go
@@ -13,7 +13,6 @@ import (
"google.golang.org/grpc/credentials/insecure"
pb "github.com/openshift-online/hypershell/components/api-server/pkg/api/grpc/hypershell/v1"
- "github.com/openshift-online/hypershell/components/api-server/pkg/api/openapi"
"github.com/openshift-online/hypershell/components/api-server/test"
)
@@ -151,7 +150,7 @@ func TestGRPCWatchGateways(t *testing.T) {
wg.Add(2)
sinkReady := make(chan struct{})
- watchClusterID := registerTestCluster(t)
+ registerTestCluster(t)
go func() {
defer wg.Done()
@@ -159,10 +158,7 @@ func TestGRPCWatchGateways(t *testing.T) {
time.Sleep(100 * time.Millisecond)
for name := range itemNames {
- gatewayInput := openapi.GatewayCreateRequest{
- Name: name,
- ClusterId: watchClusterID,
- }
+ gatewayInput := managedGatewayCreateRequest(name)
_, resp, postErr := client.DefaultAPI.CreateGateway(ctx).GatewayCreateRequest(gatewayInput).Execute()
if postErr != nil {
sourceErr = fmt.Errorf("REST POST failed for %s: %v", name, postErr)
diff --git a/components/api-server/plugins/gateways/handler.go b/components/api-server/plugins/gateways/handler.go
index 8b1e2a71c..2f6b2d439 100644
--- a/components/api-server/plugins/gateways/handler.go
+++ b/components/api-server/plugins/gateways/handler.go
@@ -40,6 +40,24 @@ type gatewayHandler struct {
visibilityFilter GatewayVisibilityFilter
ownerLookup GatewayOwnerLookup
clusters RegisteredClusterLookup
+ placement PlacementResolver
+ availability PlacementAvailabilityResolver
+}
+
+func (h gatewayHandler) GetPlacementAvailability(w http.ResponseWriter, r *http.Request) {
+ if h.availability == nil {
+ handlers.HandleGet(w, r, &handlers.HandlerConfig{Action: func() (interface{}, *errors.ServiceError) {
+ return nil, errors.GeneralError("gateway placement resolver is unavailable")
+ }, ErrorHandler: handlers.HandleError})
+ return
+ }
+ handlers.HandleGet(w, r, &handlers.HandlerConfig{Action: func() (interface{}, *errors.ServiceError) {
+ availability, svcErr := h.availability(r.Context())
+ if svcErr != nil {
+ return nil, svcErr
+ }
+ return availability, nil
+ }, ErrorHandler: handlers.HandleError})
}
// validateGatewayPhaseValue rejects a phase outside the canonical vocabulary. An
@@ -54,15 +72,18 @@ func validateGatewayPhaseValue(phase *string) *errors.ServiceError {
return nil
}
-func NewGatewayHandler(gateway GatewayService, generic services.GenericService, ownerBinding OwnerBindingCreator, visibilityFilter GatewayVisibilityFilter, ownerLookup GatewayOwnerLookup, clusters RegisteredClusterLookup) *gatewayHandler {
- return &gatewayHandler{
+func NewGatewayHandler(gateway GatewayService, generic services.GenericService, ownerBinding OwnerBindingCreator, visibilityFilter GatewayVisibilityFilter, ownerLookup GatewayOwnerLookup, clusters RegisteredClusterLookup, placement PlacementResolver, availability PlacementAvailabilityResolver) *gatewayHandler {
+ h := &gatewayHandler{
gateway: gateway,
generic: generic,
ownerBinding: ownerBinding,
visibilityFilter: visibilityFilter,
ownerLookup: ownerLookup,
clusters: clusters,
+ placement: placement,
+ availability: availability,
}
+ return h
}
func (h gatewayHandler) Create(w http.ResponseWriter, r *http.Request) {
@@ -73,6 +94,18 @@ func (h gatewayHandler) Create(w http.ResponseWriter, r *http.Request) {
Action: func() (interface{}, *errors.ServiceError) {
ctx := r.Context()
gatewayModel := ConvertGateway(gateway)
+ placement := gateway.GetPlacement()
+ if placementErr := validatePlacementIntent(placement); placementErr != nil {
+ return nil, placementErr
+ }
+ if h.placement == nil {
+ return nil, errors.GeneralError("gateway placement resolver is unavailable")
+ }
+ clusterID, placementErr := h.placement(ctx, placement)
+ if placementErr != nil {
+ return nil, placementErr
+ }
+ gatewayModel.ClusterId = clusterID
if phaseErr := validateGatewayPhaseValue(gatewayModel.Phase); phaseErr != nil {
return nil, phaseErr
}
diff --git a/components/api-server/plugins/gateways/integration_test.go b/components/api-server/plugins/gateways/integration_test.go
index e7d9dccee..b3b338d61 100644
--- a/components/api-server/plugins/gateways/integration_test.go
+++ b/components/api-server/plugins/gateways/integration_test.go
@@ -50,15 +50,13 @@ func TestGatewayPost(t *testing.T) {
account := h.NewRandAccount()
ctx := h.NewAuthenticatedContext(account)
- gatewayInput := openapi.GatewayCreateRequest{
- Name: "test-name",
- ClusterId: registerTestCluster(t),
- ExternalDns: openapi.PtrString("test-external_dns"),
- TlsMode: openapi.PtrString("test-tls_mode"),
- ServiceType: openapi.PtrString("test-service_type"),
- Status: openapi.PtrString("test-status"),
- Phase: openapi.PtrString("Provisioning"),
- }
+ clusterID := registerTestCluster(t)
+ gatewayInput := managedGatewayCreateRequest("test-name")
+ gatewayInput.ExternalDns = openapi.PtrString("test-external_dns")
+ gatewayInput.TlsMode = openapi.PtrString("test-tls_mode")
+ gatewayInput.ServiceType = openapi.PtrString("test-service_type")
+ gatewayInput.Status = openapi.PtrString("test-status")
+ gatewayInput.Phase = openapi.PtrString("Provisioning")
gatewayOutput, resp, err := client.DefaultAPI.CreateGateway(ctx).GatewayCreateRequest(gatewayInput).Execute()
Expect(err).NotTo(HaveOccurred(), "Error posting object: %v", err)
@@ -66,6 +64,7 @@ func TestGatewayPost(t *testing.T) {
Expect(*gatewayOutput.Id).NotTo(BeEmpty(), "Expected ID assigned on creation")
Expect(*gatewayOutput.Kind).To(Equal("Gateway"))
Expect(*gatewayOutput.Href).To(Equal(fmt.Sprintf("/api/hypershell/v1/gateways/%s", *gatewayOutput.Id)))
+ Expect(gatewayOutput.ClusterId).To(Equal(clusterID))
Expect(gatewayOutput.Namespace).To(MatchRegexp(`^openshell-[0-9a-f]{16}$`))
jwtToken := ctx.Value(openapi.ContextAccessToken)
@@ -85,10 +84,7 @@ func TestGatewayPostMinimalFields(t *testing.T) {
account := h.NewRandAccount()
ctx := h.NewAuthenticatedContext(account)
clusterID := registerTestCluster(t)
- gatewayInput := openapi.GatewayCreateRequest{
- Name: "local-gateway",
- ClusterId: clusterID,
- }
+ gatewayInput := managedGatewayCreateRequest("local-gateway")
gatewayOutput, resp, err := client.DefaultAPI.CreateGateway(ctx).GatewayCreateRequest(gatewayInput).Execute()
Expect(err).NotTo(HaveOccurred(), "Error posting gateway with minimal fields: %v", err)
@@ -97,43 +93,24 @@ func TestGatewayPostMinimalFields(t *testing.T) {
Expect(gatewayOutput.Namespace).To(MatchRegexp(`^openshell-[0-9a-f]{16}$`))
}
-// Gateways Reference a Registered Cluster: an empty cluster_id is a 400 naming
-// cluster_id, and no gateway is created.
-func TestGatewayPostRejectsEmptyClusterID(t *testing.T) {
+// Gateway creation accepts placement intent only. A legacy direct cluster_id
+// is rejected as an unknown request field even when valid placement is present.
+func TestGatewayPostRejectsDirectClusterID(t *testing.T) {
h, client := test.RegisterIntegration(t)
account := h.NewRandAccount()
ctx := h.NewAuthenticatedContext(account)
-
- _, resp, err := client.DefaultAPI.CreateGateway(ctx).GatewayCreateRequest(openapi.GatewayCreateRequest{
- Name: "no-cluster",
- ClusterId: "",
- }).Execute()
- Expect(err).To(HaveOccurred())
- Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
- Expect(openapiErrorReason(h, err)).To(ContainSubstring("cluster_id"))
- expectNoGatewayNamed(ctx, client, "no-cluster")
-}
-
-// Gateways Reference a Registered Cluster: a cluster_id naming a manually
-// created ManagedCluster (empty oidc_subject) or no ManagedCluster at all is a
-// 400 stating the cluster has no registered control plane.
-func TestGatewayPostRejectsUnregisteredCluster(t *testing.T) {
- h, client := test.RegisterIntegration(t)
-
- account := h.NewRandAccount()
- ctx := h.NewAuthenticatedContext(account)
-
- for _, clusterID := range []string{createManualCluster(t), "2doesnotexist000000000000000"} {
- _, resp, err := client.DefaultAPI.CreateGateway(ctx).GatewayCreateRequest(openapi.GatewayCreateRequest{
- Name: "unregistered-cluster",
- ClusterId: clusterID,
- }).Execute()
- Expect(err).To(HaveOccurred(), "cluster_id %s must be rejected", clusterID)
- Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
- Expect(openapiErrorReason(h, err)).To(ContainSubstring("registered control plane"))
- }
- expectNoGatewayNamed(ctx, client, "unregistered-cluster")
+ registerTestCluster(t)
+ jwToken := ctx.Value(openapi.ContextAccessToken)
+ resp, err := resty.R().
+ SetHeader("Content-Type", "application/json").
+ SetHeader("Authorization", fmt.Sprintf("Bearer %s", jwToken)).
+ SetBody(`{"name":"direct-cluster","placement":{"network":"public","provider":"aws"},"cluster_id":"legacy-cluster"}`).
+ Post(h.RestURL("/gateways"))
+ Expect(err).NotTo(HaveOccurred())
+ Expect(resp.StatusCode()).To(Equal(http.StatusBadRequest))
+ Expect(string(resp.Body())).To(ContainSubstring("cluster_id"))
+ expectNoGatewayNamed(ctx, client, "direct-cluster")
}
// A PATCH that moves a gateway to an unregistered cluster is rejected; one that
@@ -144,11 +121,8 @@ func TestGatewayPatchValidatesClusterReassignment(t *testing.T) {
account := h.NewRandAccount()
ctx := h.NewAuthenticatedContext(account)
- clusterID := registerTestCluster(t)
- created, _, err := client.DefaultAPI.CreateGateway(ctx).GatewayCreateRequest(openapi.GatewayCreateRequest{
- Name: "patch-cluster",
- ClusterId: clusterID,
- }).Execute()
+ registerTestCluster(t)
+ created, _, err := client.DefaultAPI.CreateGateway(ctx).GatewayCreateRequest(managedGatewayCreateRequest("patch-cluster")).Execute()
Expect(err).NotTo(HaveOccurred())
_, resp, err := client.DefaultAPI.UpdateGateway(ctx, *created.Id).GatewayPatchRequest(openapi.GatewayPatchRequest{
@@ -195,10 +169,8 @@ func TestGatewayPostWithoutRouteRemainsUnrouted(t *testing.T) {
account := h.NewRandAccount()
ctx := h.NewAuthenticatedContext(account)
- gatewayInput := openapi.GatewayCreateRequest{
- Name: "route-default-test",
- ClusterId: registerTestCluster(t),
- }
+ registerTestCluster(t)
+ gatewayInput := managedGatewayCreateRequest("route-default-test")
gatewayOutput, resp, err := client.DefaultAPI.CreateGateway(ctx).GatewayCreateRequest(gatewayInput).Execute()
Expect(err).NotTo(HaveOccurred())
@@ -213,11 +185,9 @@ func TestGatewayPostPreservesExplicitRoute(t *testing.T) {
ctx := h.NewAuthenticatedContext(account)
customRoute := `{"enabled":true,"host":"custom.example.com"}`
- gatewayInput := openapi.GatewayCreateRequest{
- Name: "route-explicit-test",
- ClusterId: registerTestCluster(t),
- Route: openapi.PtrString(customRoute),
- }
+ registerTestCluster(t)
+ gatewayInput := managedGatewayCreateRequest("route-explicit-test")
+ gatewayInput.Route = openapi.PtrString(customRoute)
gatewayOutput, resp, err := client.DefaultAPI.CreateGateway(ctx).GatewayCreateRequest(gatewayInput).Execute()
Expect(err).NotTo(HaveOccurred())
@@ -332,11 +302,9 @@ func TestGatewayPostWithCredentialDriver(t *testing.T) {
ctx := h.NewAuthenticatedContext(account)
credDriver := `{"type":"kubernetes-secrets","kubernetes_secrets":{"namespace":"creds-ns"}}`
- gatewayInput := openapi.GatewayCreateRequest{
- Name: "test-cred-driver",
- ClusterId: registerTestCluster(t),
- CredentialDriver: openapi.PtrString(credDriver),
- }
+ registerTestCluster(t)
+ gatewayInput := managedGatewayCreateRequest("test-cred-driver")
+ gatewayInput.CredentialDriver = openapi.PtrString(credDriver)
gatewayOutput, resp, err := client.DefaultAPI.CreateGateway(ctx).GatewayCreateRequest(gatewayInput).Execute()
Expect(err).NotTo(HaveOccurred(), "Error posting gateway with credential_driver: %v", err)
diff --git a/components/api-server/plugins/gateways/phase_validation_test.go b/components/api-server/plugins/gateways/phase_validation_test.go
index 1d1ef86fc..9a79a3075 100644
--- a/components/api-server/plugins/gateways/phase_validation_test.go
+++ b/components/api-server/plugins/gateways/phase_validation_test.go
@@ -43,6 +43,7 @@ func TestGRPCGatewayRejectsUnknownPhase(t *testing.T) {
_, err = grpcClient.CreateGateway(ctx, &pb.CreateGatewayRequest{
Name: "reject-create",
ClusterId: registerTestCluster(t),
+ ReleaseId: "test-release_id",
Phase: &badPhase,
})
Expect(err).To(HaveOccurred(), "create with an unknown phase must be rejected")
@@ -53,6 +54,7 @@ func TestGRPCGatewayRejectsUnknownPhase(t *testing.T) {
created, err := grpcClient.CreateGateway(ctx, &pb.CreateGatewayRequest{
Name: "accept-create",
ClusterId: registerTestCluster(t),
+ ReleaseId: "test-release_id",
Phase: &goodPhase,
})
Expect(err).NotTo(HaveOccurred())
@@ -82,6 +84,7 @@ func TestGRPCGatewayRejectsUnknownPhase(t *testing.T) {
_, err = grpcClient.CreateGateway(ctx, &pb.CreateGatewayRequest{
Name: "accept-absent-phase",
ClusterId: registerTestCluster(t),
+ ReleaseId: "test-release_id",
})
Expect(err).NotTo(HaveOccurred(), "create without a phase must be accepted")
}
@@ -120,11 +123,10 @@ func TestRESTGatewayRejectsUnknownPhase(t *testing.T) {
account := h.NewRandAccount()
ctx := h.NewAuthenticatedContext(account)
- _, resp, err := client.DefaultAPI.CreateGateway(ctx).GatewayCreateRequest(openapi.GatewayCreateRequest{
- Name: "reject-rest-create",
- ClusterId: registerTestCluster(t),
- Phase: openapi.PtrString("Booting"),
- }).Execute()
+ registerTestCluster(t)
+ request := managedGatewayCreateRequest("reject-rest-create")
+ request.Phase = openapi.PtrString("Booting")
+ _, resp, err := client.DefaultAPI.CreateGateway(ctx).GatewayCreateRequest(request).Execute()
Expect(err).To(HaveOccurred(), "REST create with an unknown phase must be rejected")
Expect(resp.StatusCode).To(Equal(http.StatusBadRequest))
}
diff --git a/components/api-server/plugins/gateways/placement.go b/components/api-server/plugins/gateways/placement.go
new file mode 100644
index 000000000..490f5ac61
--- /dev/null
+++ b/components/api-server/plugins/gateways/placement.go
@@ -0,0 +1,87 @@
+package gateways
+
+import (
+ "crypto/rand"
+ "errors"
+ "fmt"
+ "math/big"
+ "time"
+)
+
+var errNoEligiblePlacement = errors.New("no eligible placement is available")
+
+// PlacementIntent is the client-facing placement request. Cluster IDs are
+// deliberately absent: they are selected by the API server at create time.
+type PlacementIntent struct {
+ Mode string `json:"mode,omitempty"`
+ Network string `json:"network,omitempty"`
+ Provider string `json:"provider,omitempty"`
+}
+
+const managedClusterConnectedMaxAge = 5 * time.Minute
+
+func PlacementControlPlaneConnected(lastSeen *time.Time, now time.Time) bool {
+ if lastSeen == nil {
+ return false
+ }
+ age := now.Sub(*lastSeen)
+ return age >= 0 && age < managedClusterConnectedMaxAge
+}
+
+type PlacementCandidate struct {
+ ID string
+ Provider string
+ Visibility string
+ Connected bool
+}
+
+func PlacementSupported(network, provider string) bool {
+ switch provider {
+ case "aws":
+ return network == "public" || network == "vpn"
+ case "ibm":
+ return network == "public"
+ default:
+ return false
+ }
+}
+
+func eligiblePlacementCandidates(intent PlacementIntent, candidates []PlacementCandidate) []PlacementCandidate {
+ eligible := make([]PlacementCandidate, 0, len(candidates))
+ for _, candidate := range candidates {
+ if candidate.Connected && candidate.Provider == intent.Provider && candidate.Visibility == intent.Network {
+ eligible = append(eligible, candidate)
+ }
+ }
+ return eligible
+}
+
+func randomPlacementIndex(size int) (int, error) {
+ index, err := rand.Int(rand.Reader, big.NewInt(int64(size)))
+ if err != nil {
+ return 0, fmt.Errorf("select random placement: %w", err)
+ }
+ return int(index.Int64()), nil
+}
+
+func resolvePlacement(intent PlacementIntent, candidates []PlacementCandidate, selectIndex func(int) (int, error)) (string, error) {
+ if !PlacementSupported(intent.Network, intent.Provider) {
+ return "", fmt.Errorf("placement %s/%s is unsupported", intent.Provider, intent.Network)
+ }
+ eligible := eligiblePlacementCandidates(intent, candidates)
+ if len(eligible) == 0 {
+ return "", errNoEligiblePlacement
+ }
+ index, err := selectIndex(len(eligible))
+ if err != nil {
+ return "", err
+ }
+ if index < 0 || index >= len(eligible) {
+ return "", fmt.Errorf("placement selector returned invalid index %d", index)
+ }
+ return eligible[index].ID, nil
+}
+
+func ResolvePlacement(intent PlacementIntent, candidates []PlacementCandidate) (string, error) {
+ return resolvePlacement(intent, candidates, randomPlacementIndex)
+}
diff --git a/components/api-server/plugins/gateways/placement_test.go b/components/api-server/plugins/gateways/placement_test.go
new file mode 100644
index 000000000..8f1c3e2a8
--- /dev/null
+++ b/components/api-server/plugins/gateways/placement_test.go
@@ -0,0 +1,90 @@
+package gateways
+
+import (
+ "errors"
+ "testing"
+ "time"
+)
+
+func TestPlacementControlPlaneConnectedUsesHeartbeatWindow(t *testing.T) {
+ now := time.Now()
+ healthy := now.Add(-time.Minute)
+ offline := now.Add(-31 * time.Minute)
+ if !PlacementControlPlaneConnected(&healthy, now) {
+ t.Fatal("expected a recent heartbeat to be connected")
+ }
+ if PlacementControlPlaneConnected(&offline, now) || PlacementControlPlaneConnected(nil, now) {
+ t.Fatal("expected an absent or stale heartbeat to be disconnected")
+ }
+}
+
+func TestPlacementSupported(t *testing.T) {
+ tests := []struct {
+ network string
+ provider string
+ want bool
+ }{
+ {network: "public", provider: "aws", want: true},
+ {network: "vpn", provider: "aws", want: true},
+ {network: "public", provider: "ibm", want: true},
+ {network: "vpn", provider: "ibm", want: false},
+ }
+ for _, test := range tests {
+ if got := PlacementSupported(test.network, test.provider); got != test.want {
+ t.Errorf("PlacementSupported(%q, %q) = %t, want %t", test.network, test.provider, got, test.want)
+ }
+ }
+}
+
+func TestResolvePlacementSelectsRandomEligibleCandidate(t *testing.T) {
+ selectedSize := 0
+ got, err := resolvePlacement(PlacementIntent{Network: "public", Provider: "aws"}, []PlacementCandidate{
+ {ID: "disconnected", Provider: "aws", Connected: false},
+ {ID: "ibm", Provider: "ibm", Connected: true},
+ {ID: "aws-a", Provider: "aws", Visibility: "public", Connected: true},
+ {ID: "aws-b", Provider: "aws", Visibility: "public", Connected: true},
+ }, func(size int) (int, error) {
+ selectedSize = size
+ return 1, nil
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if selectedSize != 2 || got != "aws-b" {
+ t.Fatalf("eligible size = %d, selected = %q; want 2 and aws-b", selectedSize, got)
+ }
+}
+
+func TestResolvePlacementRejectsUnsupportedAndUnavailablePlacement(t *testing.T) {
+ if _, err := ResolvePlacement(PlacementIntent{Network: "vpn", Provider: "ibm"}, nil); err == nil {
+ t.Fatal("expected unsupported placement error")
+ }
+ if _, err := ResolvePlacement(PlacementIntent{Network: "public", Provider: "aws"}, nil); err == nil {
+ t.Fatal("expected unavailable placement error")
+ }
+}
+
+func TestResolvePlacementReturnsRandomSourceFailure(t *testing.T) {
+ want := errors.New("random unavailable")
+ _, err := resolvePlacement(
+ PlacementIntent{Network: "public", Provider: "aws"},
+ []PlacementCandidate{{ID: "aws", Provider: "aws", Visibility: "public", Connected: true}},
+ func(int) (int, error) { return 0, want },
+ )
+ if !errors.Is(err, want) {
+ t.Fatalf("error = %v, want %v", err, want)
+ }
+}
+
+func TestManagedPlacementAvailableRequiresMatchingVisibility(t *testing.T) {
+ snapshot := placementSnapshot{providers: map[string]*providerPlacementState{
+ "aws": {candidates: []PlacementCandidate{{ID: "public-aws", Provider: "aws", Visibility: "public", Connected: true}}},
+ }}
+
+ if !managedPlacementAvailable(snapshot, "public", "aws") {
+ t.Fatal("expected public AWS placement to be available")
+ }
+ if managedPlacementAvailable(snapshot, "vpn", "aws") {
+ t.Fatal("expected VPN AWS placement to be unavailable without a VPN cluster")
+ }
+}
diff --git a/components/api-server/plugins/gateways/plugin.go b/components/api-server/plugins/gateways/plugin.go
index 0128e3c2a..600224c31 100644
--- a/components/api-server/plugins/gateways/plugin.go
+++ b/components/api-server/plugins/gateways/plugin.go
@@ -2,12 +2,19 @@ package gateways
import (
"context"
+ stderrors "errors"
+ "fmt"
"net/http"
+ "os"
+ "strings"
+ "time"
+ "github.com/golang/glog"
"github.com/gorilla/mux"
"google.golang.org/grpc"
pb "github.com/openshift-online/hypershell/components/api-server/pkg/api/grpc/hypershell/v1"
+ "github.com/openshift-online/hypershell/components/api-server/pkg/api/openapi"
"github.com/openshift-online/hypershell/components/api-server/pkg/rbac"
"github.com/openshift-online/hypershell/components/api-server/plugins/managedClusters"
"github.com/openshift-online/hypershell/components/api-server/plugins/roleBindings"
@@ -110,6 +117,134 @@ func registeredClusterLookup(s *environments.Services) RegisteredClusterLookup {
}
}
+type providerPlacementState struct {
+ candidates []PlacementCandidate
+}
+
+type placementSnapshot struct {
+ providers map[string]*providerPlacementState
+ localID string
+}
+
+type registeredPlacementService struct {
+ services *environments.Services
+ now func() time.Time
+}
+
+func newRegisteredPlacementService(s *environments.Services) *registeredPlacementService {
+ return ®isteredPlacementService{services: s, now: time.Now}
+}
+
+func normalizePlacementProvider(provider string) string {
+ provider = strings.ToLower(strings.TrimSpace(provider))
+ if provider == "ibm cloud" {
+ return "ibm"
+ }
+ return provider
+}
+
+func (p *registeredPlacementService) snapshot(ctx context.Context) (placementSnapshot, *errors.ServiceError) {
+ result := placementSnapshot{providers: map[string]*providerPlacementState{"aws": {}, "ibm": {}}}
+ svc := managedClusters.Service(p.services)
+ if svc == nil {
+ return result, errors.GeneralError("managed cluster service is not available")
+ }
+ clusters, svcErr := svc.All(ctx)
+ if svcErr != nil {
+ return result, svcErr
+ }
+ for _, cluster := range clusters {
+ if cluster == nil || cluster.OIDCSubject == "" || !PlacementControlPlaneConnected(cluster.LastSeenAt, p.now()) {
+ continue
+ }
+ provider := normalizePlacementProvider(cluster.Provider)
+ isLocal := cluster.Name == "local-kind"
+ if isLocal {
+ if os.Getenv("HYPERSHELL_PLATFORM_KIND") == "true" {
+ result.localID = cluster.ID
+ }
+ continue
+ }
+ state := result.providers[provider]
+ if state == nil {
+ continue
+ }
+ state.candidates = append(state.candidates, PlacementCandidate{ID: cluster.ID, Provider: provider, Visibility: cluster.Visibility, Connected: true})
+ }
+ return result, nil
+}
+
+func (p *registeredPlacementService) selectManaged(snapshot placementSnapshot, network, provider string) (string, error) {
+ state := snapshot.providers[provider]
+ if state == nil {
+ return "", fmt.Errorf("unsupported provider %q", provider)
+ }
+ return ResolvePlacement(PlacementIntent{Network: network, Provider: provider}, state.candidates)
+}
+
+func managedPlacementAvailable(snapshot placementSnapshot, network, provider string) bool {
+ state := snapshot.providers[provider]
+ if !PlacementSupported(network, provider) || state == nil {
+ return false
+ }
+ for _, candidate := range state.candidates {
+ if candidate.Visibility == network {
+ return true
+ }
+ }
+ return false
+}
+
+func (p *registeredPlacementService) Resolve(ctx context.Context, intent openapi.GatewayPlacementIntent) (string, *errors.ServiceError) {
+ snapshot, svcErr := p.snapshot(ctx)
+ if svcErr != nil {
+ return "", svcErr
+ }
+ if intent.Mode != nil && *intent.Mode == "local-kind" {
+ if os.Getenv("HYPERSHELL_PLATFORM_KIND") != "true" {
+ return "", errors.Validation("local-kind placement is only available in the Kind development environment")
+ }
+ if snapshot.localID == "" {
+ return "", errors.Validation("local-kind placement is unavailable")
+ }
+ return snapshot.localID, nil
+ }
+ if intent.Network == nil || intent.Provider == nil || !PlacementSupported(*intent.Network, *intent.Provider) {
+ return "", errors.Validation("the requested network and provider placement is unsupported")
+ }
+ selected, err := p.selectManaged(snapshot, *intent.Network, *intent.Provider)
+ if err != nil {
+ if stderrors.Is(err, errNoEligiblePlacement) {
+ return "", errors.Validation("no eligible managed cluster is available for the requested placement")
+ }
+ glog.Errorf("failed to resolve managed cluster placement provider=%s network=%s: %v", *intent.Provider, *intent.Network, err)
+ return "", errors.GeneralError("failed to resolve managed cluster placement")
+ }
+ return selected, nil
+}
+
+func (p *registeredPlacementService) Availability(ctx context.Context) (openapi.GatewayPlacementAvailability, *errors.ServiceError) {
+ snapshot, svcErr := p.snapshot(ctx)
+ if svcErr != nil {
+ return openapi.GatewayPlacementAvailability{}, svcErr
+ }
+ availability := openapi.GatewayPlacementAvailability{}
+ availability.AwsPublic = managedPlacementAvailable(snapshot, "public", "aws")
+ availability.AwsVpn = managedPlacementAvailable(snapshot, "vpn", "aws")
+ availability.IbmPublic = managedPlacementAvailable(snapshot, "public", "ibm")
+ availability.IbmVpn = false
+ if !availability.AwsPublic && !availability.AwsVpn {
+ reason := "no-eligible-cluster"
+ availability.AwsReason = &reason
+ }
+ if !availability.IbmPublic {
+ reason := "no-eligible-cluster"
+ availability.IbmReason = &reason
+ }
+ availability.LocalKind = os.Getenv("HYPERSHELL_PLATFORM_KIND") == "true" && snapshot.localID != ""
+ return availability, nil
+}
+
func init() {
registry.RegisterService("Gateways", func(env interface{}) interface{} {
return NewServiceLocator(env.(*environments.Env))
@@ -132,10 +267,12 @@ func init() {
})
ownerLookup = rbService
}
- gatewayHandler := NewGatewayHandler(Service(envServices), listService(envServices), ownerBinding, visibilityFilter, ownerLookup, registeredClusterLookup(envServices))
+ placement := newRegisteredPlacementService(envServices)
+ gatewayHandler := NewGatewayHandler(Service(envServices), listService(envServices), ownerBinding, visibilityFilter, ownerLookup, registeredClusterLookup(envServices), placement.Resolve, placement.Availability)
gatewaysRouter := apiV1Router.PathPrefix("/gateways").Subrouter()
gatewaysRouter.HandleFunc("", gatewayHandler.List).Methods(http.MethodGet)
+ gatewaysRouter.HandleFunc("/placement-availability", gatewayHandler.GetPlacementAvailability).Methods(http.MethodGet)
gatewaysRouter.HandleFunc("/{id}", gatewayHandler.Get).Methods(http.MethodGet)
gatewaysRouter.HandleFunc("", gatewayHandler.Create).Methods(http.MethodPost)
gatewaysRouter.HandleFunc("/{id}", gatewayHandler.Patch).Methods(http.MethodPatch)
@@ -172,7 +309,8 @@ func init() {
}
return nil
}
- pb.RegisterGatewayServiceServer(grpcServer, NewGatewayGRPCHandler(gatewayService, genericService, brokerFunc, registeredClusterLookup(envServices)))
+ placement := newRegisteredPlacementService(envServices)
+ pb.RegisterGatewayServiceServer(grpcServer, NewGatewayGRPCHandler(gatewayService, genericService, brokerFunc, registeredClusterLookup(envServices), placement.Resolve))
})
presenters.RegisterPath(Gateway{}, "gateways")
diff --git a/components/api-server/plugins/gateways/presenter.go b/components/api-server/plugins/gateways/presenter.go
index a94da0182..ad1b039b0 100644
--- a/components/api-server/plugins/gateways/presenter.go
+++ b/components/api-server/plugins/gateways/presenter.go
@@ -11,7 +11,8 @@ import (
func ConvertGateway(gateway openapi.GatewayCreateRequest) *Gateway {
c := &Gateway{}
c.Name = gateway.Name
- c.ClusterId = gateway.ClusterId
+ // Placement resolves the concrete cluster in the create handler before the
+ // Gateway model is persisted.
c.ExternalDns = gateway.ExternalDns
c.TlsMode = gateway.TlsMode
c.ServiceType = gateway.ServiceType
diff --git a/components/api-server/plugins/managedClusters/dao.go b/components/api-server/plugins/managedClusters/dao.go
index 7f4fd4853..484710155 100644
--- a/components/api-server/plugins/managedClusters/dao.go
+++ b/components/api-server/plugins/managedClusters/dao.go
@@ -24,8 +24,8 @@ type ManagedClusterDao interface {
// (oidc_subject, name) spans soft-deleted rows, so there is at most one.
FindDeletedBySubjectAndName(ctx context.Context, subject, name string) (*ManagedCluster, error)
// Restore clears deleted_at on a soft-deleted record, keeping its id, and
- // stamps last_seen_at.
- Restore(ctx context.Context, id string, lastSeenAt time.Time) (*ManagedCluster, error)
+ // atomically refreshes its placement metadata from the new registration.
+ Restore(ctx context.Context, id, provider, visibility string, lastSeenAt time.Time) (*ManagedCluster, error)
InventorySnapshot(ctx context.Context, evaluationTime time.Time) (*ClusterInventorySnapshot, error)
}
@@ -122,10 +122,16 @@ func (d *sqlManagedClusterDao) FindDeletedBySubjectAndName(ctx context.Context,
return &managedCluster, nil
}
-func (d *sqlManagedClusterDao) Restore(ctx context.Context, id string, lastSeenAt time.Time) (*ManagedCluster, error) {
+func (d *sqlManagedClusterDao) Restore(ctx context.Context, id, provider, visibility string, lastSeenAt time.Time) (*ManagedCluster, error) {
g2 := (*d.sessionFactory).New(ctx)
if err := g2.Unscoped().Model(&ManagedCluster{}).Where("id = ?", id).
- Updates(map[string]interface{}{"deleted_at": nil, "last_seen_at": lastSeenAt, "updated_at": time.Now()}).Error; err != nil {
+ Updates(map[string]interface{}{
+ "deleted_at": nil,
+ "provider": provider,
+ "visibility": visibility,
+ "last_seen_at": lastSeenAt,
+ "updated_at": time.Now(),
+ }).Error; err != nil {
db.MarkForRollback(ctx, err)
return nil, err
}
diff --git a/components/api-server/plugins/managedClusters/handler.go b/components/api-server/plugins/managedClusters/handler.go
index d16d811cc..f0d477133 100644
--- a/components/api-server/plugins/managedClusters/handler.go
+++ b/components/api-server/plugins/managedClusters/handler.go
@@ -59,6 +59,28 @@ func (h managedClusterHandler) Register(w http.ResponseWriter, r *http.Request)
))
return
}
+ provider := req.GetProvider()
+ visibility := req.GetVisibility()
+ // Provider and visibility were added after managed-cluster registration was
+ // already deployed. Accept an omitted pair while older control planes are
+ // still posting heartbeats; the service preserves any placement metadata
+ // previously supplied by a newer client.
+ if (provider == "") != (visibility == "") {
+ handlers.HandleError(r.Context(), w, errors.Validation("provider and visibility must be supplied together"))
+ return
+ }
+ if provider != "" && provider != "aws" && provider != "ibm" && provider != "kind" {
+ handlers.HandleError(r.Context(), w, errors.Validation("provider must be aws, ibm, or kind"))
+ return
+ }
+ if visibility != "" && visibility != "public" && visibility != "vpn" {
+ handlers.HandleError(r.Context(), w, errors.Validation("visibility must be public or vpn"))
+ return
+ }
+ if provider == "ibm" && visibility == "vpn" {
+ handlers.HandleError(r.Context(), w, errors.Validation("IBM placement does not support VPN visibility"))
+ return
+ }
ctx := r.Context()
token, tokenErr := auth.TokenFromContext(ctx)
@@ -82,7 +104,7 @@ func (h managedClusterHandler) Register(w http.ResponseWriter, r *http.Request)
description = *req.Description
}
- cluster, created, svcErr := h.managedCluster.Register(ctx, req.Name, description, oidcSubject)
+ cluster, created, svcErr := h.managedCluster.Register(ctx, req.Name, description, provider, visibility, oidcSubject)
if svcErr != nil {
handlers.HandleError(r.Context(), w, svcErr)
return
diff --git a/components/api-server/plugins/managedClusters/migration.go b/components/api-server/plugins/managedClusters/migration.go
index 38e561aeb..3cc75cce2 100644
--- a/components/api-server/plugins/managedClusters/migration.go
+++ b/components/api-server/plugins/managedClusters/migration.go
@@ -40,6 +40,18 @@ func migrationAddRegistrationFields() *gormigrate.Migration {
}
}
+func migrationAddPlacementVisibility() *gormigrate.Migration {
+ return &gormigrate.Migration{
+ ID: "2026092900000001",
+ Migrate: func(tx *gorm.DB) error {
+ return tx.Exec(`ALTER TABLE managed_clusters ADD COLUMN IF NOT EXISTS visibility TEXT`).Error
+ },
+ Rollback: func(tx *gorm.DB) error {
+ return tx.Exec(`ALTER TABLE managed_clusters DROP COLUMN IF EXISTS visibility`).Error
+ },
+ }
+}
+
// migrationUniqueName makes managed_clusters.name unique across all live
// records, registered or not, so discovery by name (seed scripts, e2e,
// operators) is unambiguous and a registration can never create a second
diff --git a/components/api-server/plugins/managedClusters/mock_dao.go b/components/api-server/plugins/managedClusters/mock_dao.go
index 3eff7bf52..d502e1513 100644
--- a/components/api-server/plugins/managedClusters/mock_dao.go
+++ b/components/api-server/plugins/managedClusters/mock_dao.go
@@ -77,7 +77,7 @@ func (d *managedClusterDaoMock) FindDeletedBySubjectAndName(ctx context.Context,
return nil, gorm.ErrRecordNotFound
}
-func (d *managedClusterDaoMock) Restore(ctx context.Context, id string, lastSeenAt time.Time) (*ManagedCluster, error) {
+func (d *managedClusterDaoMock) Restore(ctx context.Context, id, provider, visibility string, lastSeenAt time.Time) (*ManagedCluster, error) {
return nil, errors.NotImplemented("ManagedCluster").AsError()
}
diff --git a/components/api-server/plugins/managedClusters/model.go b/components/api-server/plugins/managedClusters/model.go
index 149830caf..e21cdb554 100644
--- a/components/api-server/plugins/managedClusters/model.go
+++ b/components/api-server/plugins/managedClusters/model.go
@@ -13,6 +13,7 @@ type ManagedCluster struct {
hypershellapi.TraceMeta
Name string `json:"name"`
Provider string `json:"provider"`
+ Visibility string `json:"visibility" gorm:"column:visibility"`
Region *string `json:"region"`
KubeconfigSecret string `json:"kubeconfig_secret"`
Status *string `json:"status"`
diff --git a/components/api-server/plugins/managedClusters/plugin.go b/components/api-server/plugins/managedClusters/plugin.go
index aab2a17d8..4cf073565 100644
--- a/components/api-server/plugins/managedClusters/plugin.go
+++ b/components/api-server/plugins/managedClusters/plugin.go
@@ -100,5 +100,6 @@ func init() {
db.RegisterMigration(migrationDropFleetId())
db.RegisterMigration(migrationAddTraceContext())
db.RegisterMigration(migrationAddRegistrationFields())
+ db.RegisterMigration(migrationAddPlacementVisibility())
db.RegisterMigration(migrationUniqueName())
}
diff --git a/components/api-server/plugins/managedClusters/presenter.go b/components/api-server/plugins/managedClusters/presenter.go
index 7404edc94..a1d857e77 100644
--- a/components/api-server/plugins/managedClusters/presenter.go
+++ b/components/api-server/plugins/managedClusters/presenter.go
@@ -15,6 +15,7 @@ func ConvertManagedCluster(managedCluster openapi.ManagedCluster) *ManagedCluste
}
c.Name = managedCluster.Name
c.Provider = managedCluster.Provider
+ c.Visibility = managedCluster.GetVisibility()
c.Region = managedCluster.Region
c.KubeconfigSecret = managedCluster.KubeconfigSecret
c.Status = managedCluster.Status
@@ -30,6 +31,10 @@ func ConvertManagedCluster(managedCluster openapi.ManagedCluster) *ManagedCluste
func PresentManagedCluster(managedCluster *ManagedCluster) openapi.ManagedCluster {
reference := presenters.PresentReference(managedCluster.ID, managedCluster)
+ var visibility *string
+ if managedCluster.Visibility != "" {
+ visibility = &managedCluster.Visibility
+ }
result := openapi.ManagedCluster{
Id: reference.Id,
Kind: reference.Kind,
@@ -38,6 +43,7 @@ func PresentManagedCluster(managedCluster *ManagedCluster) openapi.ManagedCluste
UpdatedAt: openapi.PtrTime(managedCluster.UpdatedAt),
Name: managedCluster.Name,
Provider: managedCluster.Provider,
+ Visibility: visibility,
Region: managedCluster.Region,
KubeconfigSecret: managedCluster.KubeconfigSecret,
Status: managedCluster.Status,
diff --git a/components/api-server/plugins/managedClusters/registration_integration_test.go b/components/api-server/plugins/managedClusters/registration_integration_test.go
index 18b4fe47f..a68552f74 100644
--- a/components/api-server/plugins/managedClusters/registration_integration_test.go
+++ b/components/api-server/plugins/managedClusters/registration_integration_test.go
@@ -23,7 +23,7 @@ func controlPlaneContext(h *test.Helper, subject string) context.Context {
func register(client *openapi.APIClient, ctx context.Context, name string) (*openapi.ManagedClusterRegistrationResponse, *http.Response, error) {
return client.DefaultAPI.RegisterManagedCluster(ctx).
- ManagedClusterRegistrationRequest(openapi.ManagedClusterRegistrationRequest{Name: name}).
+ ManagedClusterRegistrationRequest(openapi.ManagedClusterRegistrationRequest{Name: name, Provider: openapi.PtrString("aws"), Visibility: openapi.PtrString("public")}).
Execute()
}
@@ -58,6 +58,87 @@ func TestManagedClusterRegistrationIdempotent(t *testing.T) {
Expect(resp.StatusCode).To(Equal(http.StatusConflict))
}
+func TestManagedClusterRegistrationAcceptsLegacyHeartbeatWithoutErasingPlacement(t *testing.T) {
+ h, client := test.RegisterIntegration(t)
+ ctx := controlPlaneContext(h, uniqueName("cp"))
+ name := uniqueName("hyp0-mc")
+
+ legacy := openapi.ManagedClusterRegistrationRequest{Name: name}
+ first, resp, err := client.DefaultAPI.RegisterManagedCluster(ctx).
+ ManagedClusterRegistrationRequest(legacy).
+ Execute()
+ Expect(err).NotTo(HaveOccurred())
+ Expect(resp.StatusCode).To(Equal(http.StatusCreated))
+
+ _, resp, err = client.DefaultAPI.RegisterManagedCluster(ctx).
+ ManagedClusterRegistrationRequest(openapi.ManagedClusterRegistrationRequest{
+ Name: name,
+ Provider: openapi.PtrString("ibm"),
+ Visibility: openapi.PtrString("public"),
+ }).
+ Execute()
+ Expect(err).NotTo(HaveOccurred())
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ _, resp, err = client.DefaultAPI.RegisterManagedCluster(ctx).
+ ManagedClusterRegistrationRequest(legacy).
+ Execute()
+ Expect(err).NotTo(HaveOccurred())
+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
+
+ cluster, _, err := client.DefaultAPI.GetManagedCluster(ctx, first.ClusterId).Execute()
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cluster.Provider).To(Equal("ibm"))
+ Expect(cluster.GetVisibility()).To(Equal("public"))
+
+ resp, err = client.DefaultAPI.DeleteManagedCluster(ctx, first.ClusterId).Execute()
+ Expect(err).NotTo(HaveOccurred())
+ Expect(resp.StatusCode).To(Equal(http.StatusNoContent))
+
+ _, resp, err = client.DefaultAPI.RegisterManagedCluster(ctx).
+ ManagedClusterRegistrationRequest(legacy).
+ Execute()
+ Expect(err).NotTo(HaveOccurred())
+ Expect(resp.StatusCode).To(Equal(http.StatusCreated))
+
+ cluster, _, err = client.DefaultAPI.GetManagedCluster(ctx, first.ClusterId).Execute()
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cluster.Provider).To(Equal("ibm"))
+ Expect(cluster.GetVisibility()).To(Equal("public"))
+}
+
+// Re-registration restores placement metadata from the current registration,
+// rather than retaining the provider and visibility from the deleted record.
+func TestManagedClusterRegistrationRestoreRefreshesPlacementMetadata(t *testing.T) {
+ h, client := test.RegisterIntegration(t)
+ ctx := controlPlaneContext(h, uniqueName("cp"))
+ name := uniqueName("hyp0-mc")
+
+ first, resp, err := register(client, ctx, name)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(resp.StatusCode).To(Equal(http.StatusCreated))
+
+ resp, err = client.DefaultAPI.DeleteManagedCluster(ctx, first.ClusterId).Execute()
+ Expect(err).NotTo(HaveOccurred())
+ Expect(resp.StatusCode).To(Equal(http.StatusNoContent))
+
+ restored, resp, err := client.DefaultAPI.RegisterManagedCluster(ctx).
+ ManagedClusterRegistrationRequest(openapi.ManagedClusterRegistrationRequest{
+ Name: name,
+ Provider: openapi.PtrString("ibm"),
+ Visibility: openapi.PtrString("public"),
+ }).Execute()
+ Expect(err).NotTo(HaveOccurred())
+ Expect(resp.StatusCode).To(Equal(http.StatusCreated))
+ Expect(restored.ClusterId).To(Equal(first.ClusterId))
+
+ cluster, _, err := client.DefaultAPI.GetManagedCluster(ctx, restored.ClusterId).Execute()
+ Expect(err).NotTo(HaveOccurred())
+ Expect(cluster.Provider).To(Equal("ibm"))
+ Expect(cluster.GetVisibility()).To(Equal("public"))
+ Expect(cluster.LastSeenAt).NotTo(BeNil())
+}
+
// Name Collision Is a Conflict: a name held by a manually created record (empty
// oidc_subject) is a 409 naming the record, nothing is created or adopted, and
// deleting the record lets the control plane register (201, new id).
diff --git a/components/api-server/plugins/managedClusters/service.go b/components/api-server/plugins/managedClusters/service.go
index ba9138546..512324d44 100644
--- a/components/api-server/plugins/managedClusters/service.go
+++ b/components/api-server/plugins/managedClusters/service.go
@@ -31,7 +31,7 @@ type ManagedClusterService interface {
// held by a record with a different or empty oidc_subject, or a subject
// already registered under another name, is a 409 Conflict: registration
// never creates a duplicate name and never adopts an existing record.
- Register(ctx context.Context, name, description, oidcSubject string) (*ManagedCluster, bool, *errors.ServiceError)
+ Register(ctx context.Context, name, description, provider, visibility, oidcSubject string) (*ManagedCluster, bool, *errors.ServiceError)
// FindRegisteredBySubject returns the ManagedCluster a control plane
// registered under the given OIDC subject, or (nil, nil) when the subject
// has not registered. An empty subject never matches.
@@ -169,7 +169,7 @@ func (s *sqlManagedClusterService) All(ctx context.Context) (ManagedClusterList,
return managedClusters, nil
}
-func (s *sqlManagedClusterService) Register(ctx context.Context, name, description, oidcSubject string) (*ManagedCluster, bool, *errors.ServiceError) {
+func (s *sqlManagedClusterService) Register(ctx context.Context, name, description, provider, visibility, oidcSubject string) (*ManagedCluster, bool, *errors.ServiceError) {
lockOwnerID, lockErr := s.lockFactory.NewAdvisoryLock(ctx, oidcSubject, managedClustersLockType)
if lockErr != nil {
return nil, false, errors.DatabaseAdvisoryLock(lockErr)
@@ -187,6 +187,12 @@ func (s *sqlManagedClusterService) Register(ctx context.Context, name, descripti
}
now := time.Now()
existing.LastSeenAt = &now
+ // A legacy control plane omits placement metadata. Its heartbeat must
+ // refresh connectivity without erasing values from a newer registration.
+ if provider != "" {
+ existing.Provider = provider
+ existing.Visibility = visibility
+ }
updated, replaceErr := s.managedClusterDao.Replace(ctx, existing)
if replaceErr != nil {
return nil, false, services.HandleUpdateError("ManagedCluster", replaceErr)
@@ -219,7 +225,11 @@ func (s *sqlManagedClusterService) Register(ctx context.Context, name, descripti
return nil, false, errors.GeneralError("registration lookup failed: %s", delErr)
}
if deleted != nil {
- restored, restoreErr := s.managedClusterDao.Restore(ctx, deleted.ID, now)
+ if provider == "" {
+ provider = deleted.Provider
+ visibility = deleted.Visibility
+ }
+ restored, restoreErr := s.managedClusterDao.Restore(ctx, deleted.ID, provider, visibility, now)
if restoreErr != nil {
if isUniqueViolation(restoreErr) {
if winner, err := s.managedClusterDao.FindByName(ctx, name); err == nil && winner != nil {
@@ -242,6 +252,8 @@ func (s *sqlManagedClusterService) Register(ctx context.Context, name, descripti
Name: name,
OIDCSubject: oidcSubject,
LastSeenAt: &now,
+ Provider: provider,
+ Visibility: visibility,
}
cluster.CaptureTraceContext(ctx)
created, createErr := s.managedClusterDao.Create(ctx, cluster)
diff --git a/components/api-server/plugins/rbac/cluster_binding_integration_test.go b/components/api-server/plugins/rbac/cluster_binding_integration_test.go
index cdef5e5b5..03e468d83 100644
--- a/components/api-server/plugins/rbac/cluster_binding_integration_test.go
+++ b/components/api-server/plugins/rbac/cluster_binding_integration_test.go
@@ -14,7 +14,7 @@ import (
"google.golang.org/grpc/status"
pb "github.com/openshift-online/hypershell/components/api-server/pkg/api/grpc/hypershell/v1"
- "github.com/openshift-online/hypershell/components/api-server/pkg/api/openapi"
+ "github.com/openshift-online/hypershell/components/api-server/plugins/gateways"
"github.com/openshift-online/hypershell/components/api-server/plugins/managedClusters"
"github.com/openshift-online/hypershell/components/api-server/test"
"github.com/openshift-online/rh-trex-ai/components/api-server/pkg/api"
@@ -50,7 +50,7 @@ func registerTestClusterWithSubject(t *testing.T) (string, string) {
suffix := strings.ToLower(api.NewID())
subject := "cp-" + suffix
svc := managedClusters.Service(&environments.Environment().Services)
- cluster, _, svcErr := svc.Register(context.Background(), fmt.Sprintf("mc-%s", suffix), "", subject)
+ cluster, _, svcErr := svc.Register(context.Background(), fmt.Sprintf("mc-%s", suffix), "", "aws", "public", subject)
if svcErr != nil {
t.Fatalf("register test managed cluster: %v", svcErr)
}
@@ -68,7 +68,7 @@ func registerTestCluster(t *testing.T) string {
// own cluster. Own id is accepted and delivers only that cluster's gateways; a
// foreign id is PERMISSION_DENIED; a missing id is INVALID_ARGUMENT.
func TestGRPCClusterCallerBinding(t *testing.T) {
- h, client := test.RegisterIntegration(t)
+ h, _ := test.RegisterIntegration(t)
h.StartControllersServer()
ownID, subject := registerTestClusterWithSubject(t)
@@ -114,23 +114,20 @@ func TestGRPCClusterCallerBinding(t *testing.T) {
_, err = stream.Header()
Expect(err).NotTo(HaveOccurred(), "own cluster watch must be accepted")
- foreignGw, _, err := client.DefaultAPI.CreateGateway(userCtx).GatewayCreateRequest(openapi.GatewayCreateRequest{
- Name: "binding-foreign", ClusterId: foreignID,
- }).Execute()
- Expect(err).NotTo(HaveOccurred())
- ownGw, _, err := client.DefaultAPI.CreateGateway(userCtx).GatewayCreateRequest(openapi.GatewayCreateRequest{
- Name: "binding-own", ClusterId: ownID,
- }).Execute()
- Expect(err).NotTo(HaveOccurred())
+ service := gateways.Service(&environments.Environment().Services)
+ foreignGw, svcErr := service.Create(userCtx, &gateways.Gateway{Name: "binding-foreign", ClusterId: foreignID})
+ Expect(svcErr).NotTo(HaveOccurred())
+ ownGw, svcErr := service.Create(userCtx, &gateways.Gateway{Name: "binding-own", ClusterId: ownID})
+ Expect(svcErr).NotTo(HaveOccurred())
for {
evt, recvErr := stream.Recv()
Expect(recvErr).NotTo(HaveOccurred(), "stream closed before the own-cluster event")
- Expect(evt.ResourceId).NotTo(Equal(*foreignGw.Id), "a foreign cluster's gateway was delivered")
+ Expect(evt.ResourceId).NotTo(Equal(foreignGw.ID), "a foreign cluster's gateway was delivered")
if evt.GetGateway() != nil {
Expect(evt.GetGateway().GetClusterId()).To(Equal(ownID))
}
- if evt.ResourceId == *ownGw.Id {
+ if evt.ResourceId == ownGw.ID {
break
}
}
diff --git a/components/api-server/plugins/roleBindings/grpc_integration_test.go b/components/api-server/plugins/roleBindings/grpc_integration_test.go
index 2f6c12d12..ab086e90b 100644
--- a/components/api-server/plugins/roleBindings/grpc_integration_test.go
+++ b/components/api-server/plugins/roleBindings/grpc_integration_test.go
@@ -105,22 +105,20 @@ func registerRoleBindingTestCluster(t *testing.T) string {
t.Helper()
suffix := strings.ToLower(api.NewID())
svc := managedClusters.Service(&environments.Environment().Services)
- cluster, _, svcErr := svc.Register(context.Background(), fmt.Sprintf("mc-%s", suffix), "", "cp-"+suffix)
+ cluster, _, svcErr := svc.Register(context.Background(), fmt.Sprintf("mc-%s", suffix), "", "aws", "public", "cp-"+suffix)
if svcErr != nil {
t.Fatalf("register test managed cluster: %v", svcErr)
}
return cluster.ID
}
-// createGatewayWithOwnerBinding creates a gateway on clusterID through the REST
-// API, grants userID gateway:owner on it, and returns the gateway id and that
-// binding's id.
+// createGatewayWithOwnerBinding creates an internal gateway fixture on
+// clusterID, grants userID gateway:owner on it, and returns both ids.
func createGatewayWithOwnerBinding(ctx context.Context, client *openapi.APIClient, userID, name, clusterID string) (string, string) {
- gw, _, err := client.DefaultAPI.CreateGateway(ctx).GatewayCreateRequest(openapi.GatewayCreateRequest{
- Name: name, ClusterId: clusterID,
- }).Execute()
- Expect(err).NotTo(HaveOccurred(), "create gateway %s", name)
- gatewayID := *gw.Id
+ _ = client
+ gw, svcErr := gateways.Service(&environments.Environment().Services).Create(ctx, &gateways.Gateway{Name: name, ClusterId: clusterID})
+ Expect(svcErr).NotTo(HaveOccurred(), "create gateway %s", name)
+ gatewayID := gw.ID
// The integration environment does not provision the caller into the
// request context, so the create path does not bootstrap the owner binding;
diff --git a/components/api-server/proto/hypershell/v1/gateways.proto b/components/api-server/proto/hypershell/v1/gateways.proto
index e25985818..7ce3043e1 100644
--- a/components/api-server/proto/hypershell/v1/gateways.proto
+++ b/components/api-server/proto/hypershell/v1/gateways.proto
@@ -20,6 +20,20 @@ message ProvisioningCondition {
string message = 3;
}
+message GatewayPlacementIntent {
+ oneof placement {
+ NetworkProviderPlacement network_provider = 1;
+ LocalKindPlacement local_kind = 2;
+ }
+}
+
+message NetworkProviderPlacement {
+ string network = 1;
+ string provider = 2;
+}
+
+message LocalKindPlacement {}
+
message Gateway {
ObjectReference metadata = 1;
string name = 2;
@@ -74,6 +88,7 @@ message CreateGatewayRequest {
optional string oidc = 14;
optional string route = 15;
optional string credential_driver = 17;
+ GatewayPlacementIntent placement = 18;
}
message CreateGatewayResponse {
diff --git a/components/api-server/test/authz/authz_integration_test.go b/components/api-server/test/authz/authz_integration_test.go
index 979f82d0f..b41539e1d 100644
--- a/components/api-server/test/authz/authz_integration_test.go
+++ b/components/api-server/test/authz/authz_integration_test.go
@@ -17,8 +17,11 @@ import (
pb "github.com/openshift-online/hypershell/components/api-server/pkg/api/grpc/hypershell/v1"
"github.com/openshift-online/hypershell/components/api-server/pkg/api/openapi"
+ "github.com/openshift-online/hypershell/components/api-server/plugins/roleBindings"
+ "github.com/openshift-online/hypershell/components/api-server/plugins/users"
"github.com/openshift-online/hypershell/components/api-server/test"
"github.com/openshift-online/rh-trex-ai/components/api-server/pkg/api"
+ "github.com/openshift-online/rh-trex-ai/components/api-server/pkg/environments"
)
// These tests pin the authorization of ManagedCluster records and of the
@@ -258,11 +261,20 @@ func TestReRegistrationAfterDeleteDoesNotReclaimATakenName(t *testing.T) {
func createGateway(t *testing.T, client *openapi.APIClient, owner principal, clusterID string) *openapi.Gateway {
t.Helper()
- gw, httpResp, err := client.DefaultAPI.CreateGateway(owner.rest).GatewayCreateRequest(openapi.GatewayCreateRequest{
- Name: fmt.Sprintf("gw-%s", strings.ToLower(api.NewID())[:10]), ClusterId: clusterID,
- }).Execute()
- Expect(err).NotTo(HaveOccurred(), "create gateway: HTTP %d %s", statusOf(httpResp), test.APIErrorReason(err))
- return gw
+ _ = client
+ created, err := pb.NewGatewayServiceClient(owner.conn).CreateGateway(context.Background(), &pb.CreateGatewayRequest{
+ Name: fmt.Sprintf("gw-%s", strings.ToLower(api.NewID())[:10]),
+ ClusterId: clusterID,
+ ReleaseId: "test-release",
+ })
+ Expect(err).NotTo(HaveOccurred(), "create gateway")
+ id := created.GetGateway().GetMetadata().GetId()
+ user, svcErr := users.Service(&environments.Environment().Services).GetByUsername(context.Background(), owner.name)
+ Expect(svcErr).NotTo(HaveOccurred(), "find gateway owner")
+ Expect(roleBindings.Service(&environments.Environment().Services).CreateGatewayOwnerBinding(
+ context.Background(), user.ID, id,
+ )).To(Succeed(), "bind gateway owner")
+ return &openapi.Gateway{Id: &id, Namespace: created.GetGateway().GetNamespace()}
}
func TestGRPCControlPlaneWritesAreScopedToItsCluster(t *testing.T) {
diff --git a/components/cli/data/generated/tui/descriptor.json b/components/cli/data/generated/tui/descriptor.json
index f675de985..091ec418a 100644
--- a/components/cli/data/generated/tui/descriptor.json
+++ b/components/cli/data/generated/tui/descriptor.json
@@ -545,6 +545,65 @@
"listOperationId": "listSecretSources",
"source": {}
},
+ {
+ "id": "collection:/api/hypershell/v1/gateways/placement-availability:#/schemas/GatewayPlacementAvailability",
+ "kind": "collection",
+ "schemaRef": "#/schemas/GatewayPlacementAvailability",
+ "label": "GatewayPlacementAvailability",
+ "defaultSort": "aws_public",
+ "columns": [
+ {
+ "property": "aws_public",
+ "label": "AWS PUBLIC",
+ "priority": 0,
+ "type": "boolean"
+ },
+ {
+ "property": "aws_reason",
+ "label": "AWS REASON",
+ "priority": 0,
+ "type": "string"
+ },
+ {
+ "property": "aws_vpn",
+ "label": "AWS VPN",
+ "priority": 0,
+ "type": "boolean"
+ },
+ {
+ "property": "ibm_public",
+ "label": "IBM PUBLIC",
+ "priority": 0,
+ "type": "boolean"
+ },
+ {
+ "property": "ibm_reason",
+ "label": "IBM REASON",
+ "priority": 0,
+ "type": "string"
+ },
+ {
+ "property": "ibm_vpn",
+ "label": "IBM VPN",
+ "priority": 0,
+ "type": "boolean"
+ },
+ {
+ "property": "local_kind",
+ "label": "LOCAL KIND",
+ "priority": 0,
+ "type": "boolean"
+ }
+ ],
+ "operationIds": [
+ "getGatewayPlacementAvailability"
+ ],
+ "capabilities": [
+ "get"
+ ],
+ "getOperationId": "getGatewayPlacementAvailability",
+ "source": {}
+ },
{
"id": "collection:/api/hypershell/v1/gateways/{gateway_id}/service_accounts/{service_account_id}/revoke:#/schemas/OpenShellGatewayServiceAccountListItem",
"kind": "collection",
@@ -1062,6 +1121,12 @@
"priority": 0,
"type": "string",
"format": "date-time"
+ },
+ {
+ "property": "visibility",
+ "label": "VISIBILITY",
+ "priority": 0,
+ "type": "string"
}
],
"operationIds": [
@@ -2264,6 +2329,12 @@
"priority": 0,
"type": "string",
"format": "date-time"
+ },
+ {
+ "property": "visibility",
+ "label": "VISIBILITY",
+ "priority": 0,
+ "type": "string"
}
],
"operationIds": [
@@ -2638,11 +2709,6 @@
"required": true,
"contentType": "application/json",
"fields": [
- {
- "name": "cluster_id",
- "type": "string",
- "required": true
- },
{
"name": "credential_driver",
"type": "string",
@@ -2676,6 +2742,12 @@
"type": "string",
"required": false
},
+ {
+ "name": "placement",
+ "type": "object",
+ "required": true,
+ "description": "Exactly one of network/provider or mode must be supplied."
+ },
{
"name": "route",
"type": "string",
@@ -2974,7 +3046,8 @@
{
"name": "provider",
"type": "string",
- "required": true
+ "required": true,
+ "description": "Cloud provider capability used for gateway placement."
},
{
"name": "region",
@@ -4195,6 +4268,44 @@
"summary": "Get an gateway by id",
"presentation": {}
},
+ {
+ "id": "getGatewayPlacementAvailability",
+ "method": "GET",
+ "pathParts": [
+ {
+ "literal": "/api/hypershell/v1/gateways/placement-availability"
+ }
+ ],
+ "response": {
+ "contentType": "application/json"
+ },
+ "successStatuses": [
+ "200"
+ ],
+ "servers": [
+ {
+ "url": "http://localhost:8000"
+ },
+ {
+ "url": "/"
+ }
+ ],
+ "security": {
+ "none": false,
+ "requirements": [
+ {
+ "schemes": [
+ "Bearer"
+ ]
+ }
+ ]
+ },
+ "capabilities": [
+ "get"
+ ],
+ "summary": "Returns current provider placement eligibility",
+ "presentation": {}
+ },
{
"id": "getGatewayServiceAccount",
"method": "GET",
@@ -5889,6 +6000,27 @@
"type": "string",
"required": true,
"description": "Human-readable spoke name, unique per fleet (e.g. hyp0-mc1). Must match on every subsequent call."
+ },
+ {
+ "name": "provider",
+ "type": "string",
+ "required": false,
+ "description": "Cloud provider hosting this control plane.",
+ "enum": [
+ "aws",
+ "ibm",
+ "kind"
+ ]
+ },
+ {
+ "name": "visibility",
+ "type": "string",
+ "required": false,
+ "description": "Network visibility supported for gateways on this control plane.",
+ "enum": [
+ "public",
+ "vpn"
+ ]
}
]
},
diff --git a/components/control-plane/cmd/hypershell-controller/main.go b/components/control-plane/cmd/hypershell-controller/main.go
index 7fa19ba96..eb0dd16a9 100644
--- a/components/control-plane/cmd/hypershell-controller/main.go
+++ b/components/control-plane/cmd/hypershell-controller/main.go
@@ -291,7 +291,7 @@ func main() {
// service-account provisioner above is not cluster-scoped and is already
// serving, so the pod's probes stay green while registration retries (for
// example while the hub API server is still starting).
- regClient := registration.NewClient(cfg.APIServerURL, cfg.ManagedClusterName, tokenProvider)
+ regClient := registration.NewClientWithPlacement(cfg.APIServerURL, cfg.ManagedClusterName, cfg.ManagedClusterProvider, cfg.ManagedClusterVisibility, tokenProvider)
clusterID, regErr := registerWithBackoff(ctx, regClient, time.Second)
if regErr != nil {
if ctx.Err() != nil {
diff --git a/components/control-plane/internal/config/config.go b/components/control-plane/internal/config/config.go
index b0a772f22..c8477cf0c 100644
--- a/components/control-plane/internal/config/config.go
+++ b/components/control-plane/internal/config/config.go
@@ -39,7 +39,9 @@ type Config struct {
// unregistered (unfiltered) mode, and a cluster id is never read from
// configuration. Sourced from HYPERSHELL_MANAGED_CLUSTER_NAME.
// See specs/platform/control-plane.spec.md ("Mandatory Cluster Identity").
- ManagedClusterName string
+ ManagedClusterName string
+ ManagedClusterProvider string
+ ManagedClusterVisibility string
// OIDC client credentials used both for registration and as per-RPC bearer
// credentials on every gRPC call (including the watch streams). All three
@@ -102,6 +104,8 @@ func Load() (*Config, error) {
Namespace: getEnv("HYPERSHELL_NAMESPACE", "hypershell"),
LogLevel: strings.ToLower(getEnv("HYPERSHELL_LOG_LEVEL", "info")),
ManagedClusterName: getEnv("HYPERSHELL_MANAGED_CLUSTER_NAME", ""),
+ ManagedClusterProvider: strings.ToLower(strings.TrimSpace(getEnv("HYPERSHELL_MANAGED_CLUSTER_PROVIDER", ""))),
+ ManagedClusterVisibility: strings.ToLower(strings.TrimSpace(getEnv("HYPERSHELL_MANAGED_CLUSTER_VISIBILITY", ""))),
OIDCIssuer: getEnv("OIDC_ISSUER", ""),
OIDCClientID: getEnv("OIDC_CLIENT_ID", ""),
OIDCClientSecret: getEnv("OIDC_CLIENT_SECRET", ""),
@@ -134,6 +138,8 @@ func Load() (*Config, error) {
// the first missing variable.
required := []struct{ name, value string }{
{"HYPERSHELL_MANAGED_CLUSTER_NAME", cfg.ManagedClusterName},
+ {"HYPERSHELL_MANAGED_CLUSTER_PROVIDER", cfg.ManagedClusterProvider},
+ {"HYPERSHELL_MANAGED_CLUSTER_VISIBILITY", cfg.ManagedClusterVisibility},
{"OIDC_ISSUER", cfg.OIDCIssuer},
{"OIDC_CLIENT_ID", cfg.OIDCClientID},
{"OIDC_CLIENT_SECRET", cfg.OIDCClientSecret},
@@ -143,6 +149,12 @@ func Load() (*Config, error) {
return nil, fmt.Errorf("%s is required: every control plane registers with the hub as a managed cluster (specs/platform/control-plane.spec.md, Mandatory Cluster Identity)", r.name)
}
}
+ if (cfg.ManagedClusterProvider != "aws" && cfg.ManagedClusterProvider != "ibm" && cfg.ManagedClusterProvider != "kind") ||
+ (cfg.ManagedClusterVisibility != "public" && cfg.ManagedClusterVisibility != "vpn") ||
+ (cfg.ManagedClusterProvider == "ibm" && cfg.ManagedClusterVisibility == "vpn") ||
+ (cfg.ManagedClusterProvider == "kind" && cfg.ManagedClusterVisibility != "public") {
+ return nil, fmt.Errorf("invalid managed cluster placement: provider=%q visibility=%q", cfg.ManagedClusterProvider, cfg.ManagedClusterVisibility)
+ }
// An invalid GATEWAY_RESOURCES fails startup rather than falling back to the
// defaults like the other tunables: silently ignoring an operator's sizing
diff --git a/components/control-plane/internal/config/config_test.go b/components/control-plane/internal/config/config_test.go
index 50a11dd51..a6c2b2747 100644
--- a/components/control-plane/internal/config/config_test.go
+++ b/components/control-plane/internal/config/config_test.go
@@ -12,6 +12,8 @@ func setRequiredEnv(t *testing.T) {
t.Helper()
t.Setenv("HYPERSHELL_GRPC_SERVER_ADDR", "localhost:9000")
t.Setenv("HYPERSHELL_MANAGED_CLUSTER_NAME", "local-kind")
+ t.Setenv("HYPERSHELL_MANAGED_CLUSTER_PROVIDER", "kind")
+ t.Setenv("HYPERSHELL_MANAGED_CLUSTER_VISIBILITY", "public")
t.Setenv("OIDC_ISSUER", "http://keycloak.example/realms/hypershell")
t.Setenv("OIDC_CLIENT_ID", "hypershell-control-plane")
t.Setenv("OIDC_CLIENT_SECRET", "secret")
@@ -23,6 +25,8 @@ func setRequiredEnv(t *testing.T) {
func TestLoadRequiresClusterIdentity(t *testing.T) {
for _, name := range []string{
"HYPERSHELL_MANAGED_CLUSTER_NAME",
+ "HYPERSHELL_MANAGED_CLUSTER_PROVIDER",
+ "HYPERSHELL_MANAGED_CLUSTER_VISIBILITY",
"OIDC_ISSUER",
"OIDC_CLIENT_ID",
"OIDC_CLIENT_SECRET",
diff --git a/components/control-plane/internal/helm/values.go b/components/control-plane/internal/helm/values.go
index a05edc980..60ac82127 100644
--- a/components/control-plane/internal/helm/values.go
+++ b/components/control-plane/internal/helm/values.go
@@ -146,6 +146,11 @@ func (b *ValuesBuilder) buildCoreValues(values map[string]interface{}) error {
// Workload configuration
setNestedValue(values, "deployment", "workload", "kind")
setNestedValue(values, 1, "replicaCount")
+ // Keep the gateway workload requests and limits explicit.
+ setNestedValue(values, map[string]interface{}{
+ "requests": map[string]interface{}{"cpu": "100m", "memory": "256Mi"},
+ "limits": map[string]interface{}{"cpu": "500m", "memory": "512Mi"},
+ }, "resources")
// Gateway container resources. Always set: the upstream chart defaults to
// `resources: {}`, which would run the gateway BestEffort.
diff --git a/components/control-plane/internal/registration/client.go b/components/control-plane/internal/registration/client.go
index ab9b8f451..b9eb7aefa 100644
--- a/components/control-plane/internal/registration/client.go
+++ b/components/control-plane/internal/registration/client.go
@@ -34,22 +34,32 @@ type TokenSource interface {
type Client struct {
apiServerURL string
clusterName string
+ provider string
+ visibility string
tokens TokenSource
httpClient *http.Client
}
// NewClient creates a registration Client.
func NewClient(apiServerURL, clusterName string, tokens TokenSource) *Client {
+ return NewClientWithPlacement(apiServerURL, clusterName, "", "", tokens)
+}
+
+func NewClientWithPlacement(apiServerURL, clusterName, provider, visibility string, tokens TokenSource) *Client {
return &Client{
apiServerURL: strings.TrimRight(apiServerURL, "/"),
clusterName: clusterName,
+ provider: provider,
+ visibility: visibility,
tokens: tokens,
httpClient: &http.Client{Timeout: 30 * time.Second},
}
}
type registrationRequest struct {
- Name string `json:"name"`
+ Name string `json:"name"`
+ Provider string `json:"provider,omitempty"`
+ Visibility string `json:"visibility,omitempty"`
}
type registrationResponse struct {
@@ -66,7 +76,7 @@ func (c *Client) Register(ctx context.Context) (string, error) {
return "", fmt.Errorf("get OIDC token: %w", err)
}
- body, err := json.Marshal(registrationRequest{Name: c.clusterName})
+ body, err := json.Marshal(registrationRequest{Name: c.clusterName, Provider: c.provider, Visibility: c.visibility})
if err != nil {
return "", fmt.Errorf("marshal registration request: %w", err)
}
diff --git a/components/sdk-go/client/agent_runtime_api.go b/components/sdk-go/client/agent_runtime_api.go
index 9c34a007e..5ef17dbbb 100644
--- a/components/sdk-go/client/agent_runtime_api.go
+++ b/components/sdk-go/client/agent_runtime_api.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package client
diff --git a/components/sdk-go/client/client.go b/components/sdk-go/client/client.go
index a70246831..60f9c16dd 100644
--- a/components/sdk-go/client/client.go
+++ b/components/sdk-go/client/client.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package client
diff --git a/components/sdk-go/client/gateway_api.go b/components/sdk-go/client/gateway_api.go
index 9b4e06763..f78e2ff11 100644
--- a/components/sdk-go/client/gateway_api.go
+++ b/components/sdk-go/client/gateway_api.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package client
@@ -22,6 +22,14 @@ func (c *Client) Gateways() *GatewayAPI {
return &GatewayAPI{client: c}
}
+func (a *GatewayAPI) PlacementAvailability(ctx context.Context) (*types.GatewayPlacementAvailability, error) {
+ var result types.GatewayPlacementAvailability
+ if err := a.client.do(ctx, http.MethodGet, "/api/hypershell/v1/gateways/placement-availability", nil, http.StatusOK, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
func (a *GatewayAPI) Create(ctx context.Context, resource *types.Gateway) (*types.Gateway, error) {
body, err := json.Marshal(resource)
if err != nil {
diff --git a/components/sdk-go/client/inference_route_api.go b/components/sdk-go/client/inference_route_api.go
index 6b5487cae..7d770df5a 100644
--- a/components/sdk-go/client/inference_route_api.go
+++ b/components/sdk-go/client/inference_route_api.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package client
diff --git a/components/sdk-go/client/iterator.go b/components/sdk-go/client/iterator.go
index 6ec370aab..a0e3ca9ef 100644
--- a/components/sdk-go/client/iterator.go
+++ b/components/sdk-go/client/iterator.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package client
diff --git a/components/sdk-go/client/managed_cluster_api.go b/components/sdk-go/client/managed_cluster_api.go
index 9ac26b306..45869c2f6 100644
--- a/components/sdk-go/client/managed_cluster_api.go
+++ b/components/sdk-go/client/managed_cluster_api.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package client
diff --git a/components/sdk-go/client/open_shell_gateway_service_account_api.go b/components/sdk-go/client/open_shell_gateway_service_account_api.go
index b059bfc4a..481f50e84 100644
--- a/components/sdk-go/client/open_shell_gateway_service_account_api.go
+++ b/components/sdk-go/client/open_shell_gateway_service_account_api.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package client
@@ -28,7 +28,7 @@ func (a *OpenShellGatewayServiceAccountAPI) Create(ctx context.Context, gatewayI
return nil, fmt.Errorf("marshal open_shell_gateway_service_account create request: %w", err)
}
var result types.OpenShellGatewayServiceAccountCreateResponse
- if _, err := a.client.doAny(ctx, http.MethodPost, fmt.Sprintf("/api/hypershell/v1/gateways/%s/service_accounts", url.PathEscape(gatewayID)), body, &result, http.StatusCreated); err != nil {
+ if _, err := a.client.doAny(ctx, http.MethodPost, fmt.Sprintf("/v1/gateways/%s/service_accounts", url.PathEscape(gatewayID)), body, &result, http.StatusCreated); err != nil {
return nil, err
}
return &result, nil
@@ -36,14 +36,14 @@ func (a *OpenShellGatewayServiceAccountAPI) Create(ctx context.Context, gatewayI
func (a *OpenShellGatewayServiceAccountAPI) Get(ctx context.Context, gatewayID string, serviceAccountID string) (*types.OpenShellGatewayServiceAccountGetResponse, error) {
var result types.OpenShellGatewayServiceAccountGetResponse
- if _, err := a.client.doAny(ctx, http.MethodGet, fmt.Sprintf("/api/hypershell/v1/gateways/%s/service_accounts/%s", url.PathEscape(gatewayID), url.PathEscape(serviceAccountID)), nil, &result, http.StatusOK); err != nil {
+ if _, err := a.client.doAny(ctx, http.MethodGet, fmt.Sprintf("/v1/gateways/%s/service_accounts/%s", url.PathEscape(gatewayID), url.PathEscape(serviceAccountID)), nil, &result, http.StatusOK); err != nil {
return nil, err
}
return &result, nil
}
func (a *OpenShellGatewayServiceAccountAPI) List(ctx context.Context, gatewayID string, opts *types.OpenShellGatewayServiceAccountListOptions) (*types.OpenShellGatewayServiceAccountList, error) {
- path := fmt.Sprintf("/api/hypershell/v1/gateways/%s/service_accounts", url.PathEscape(gatewayID))
+ path := fmt.Sprintf("/v1/gateways/%s/service_accounts", url.PathEscape(gatewayID))
if opts != nil {
params := url.Values{}
if opts.Page > 0 {
@@ -77,7 +77,7 @@ func (a *OpenShellGatewayServiceAccountAPI) List(ctx context.Context, gatewayID
func (a *OpenShellGatewayServiceAccountAPI) Revoke(ctx context.Context, gatewayID string, serviceAccountID string) (*types.OpenShellGatewayServiceAccountListItem, error) {
var result types.OpenShellGatewayServiceAccountListItem
- if _, err := a.client.doAny(ctx, http.MethodPost, fmt.Sprintf("/api/hypershell/v1/gateways/%s/service_accounts/%s", url.PathEscape(gatewayID), url.PathEscape(serviceAccountID))+"/revoke", nil, &result, http.StatusOK, http.StatusAccepted); err != nil {
+ if _, err := a.client.doAny(ctx, http.MethodPost, fmt.Sprintf("/v1/gateways/%s/service_accounts/%s", url.PathEscape(gatewayID), url.PathEscape(serviceAccountID))+"/revoke", nil, &result, http.StatusOK, http.StatusAccepted); err != nil {
return nil, err
}
return &result, nil
@@ -85,7 +85,7 @@ func (a *OpenShellGatewayServiceAccountAPI) Revoke(ctx context.Context, gatewayI
func (a *OpenShellGatewayServiceAccountAPI) Delete(ctx context.Context, gatewayID string, serviceAccountID string) (*types.OpenShellGatewayServiceAccountListItem, error) {
var result types.OpenShellGatewayServiceAccountListItem
- status, err := a.client.doAny(ctx, http.MethodDelete, fmt.Sprintf("/api/hypershell/v1/gateways/%s/service_accounts/%s", url.PathEscape(gatewayID), url.PathEscape(serviceAccountID)), nil, &result, http.StatusNoContent, http.StatusAccepted)
+ status, err := a.client.doAny(ctx, http.MethodDelete, fmt.Sprintf("/v1/gateways/%s/service_accounts/%s", url.PathEscape(gatewayID), url.PathEscape(serviceAccountID)), nil, &result, http.StatusNoContent, http.StatusAccepted)
if err != nil {
return nil, err
}
diff --git a/components/sdk-go/client/provider_binding_api.go b/components/sdk-go/client/provider_binding_api.go
index 795ab3d91..55fbd5cb2 100644
--- a/components/sdk-go/client/provider_binding_api.go
+++ b/components/sdk-go/client/provider_binding_api.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package client
diff --git a/components/sdk-go/client/provider_spec_api.go b/components/sdk-go/client/provider_spec_api.go
index 41f4a2384..ba9c3b810 100644
--- a/components/sdk-go/client/provider_spec_api.go
+++ b/components/sdk-go/client/provider_spec_api.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package client
diff --git a/components/sdk-go/client/role_api.go b/components/sdk-go/client/role_api.go
index 9eab829a8..ebfef98dd 100644
--- a/components/sdk-go/client/role_api.go
+++ b/components/sdk-go/client/role_api.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package client
diff --git a/components/sdk-go/client/role_binding_api.go b/components/sdk-go/client/role_binding_api.go
index 626e20b43..293336a0b 100644
--- a/components/sdk-go/client/role_binding_api.go
+++ b/components/sdk-go/client/role_binding_api.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package client
diff --git a/components/sdk-go/client/sandbox_template_api.go b/components/sdk-go/client/sandbox_template_api.go
index 93f7df7ac..ddebeabdf 100644
--- a/components/sdk-go/client/sandbox_template_api.go
+++ b/components/sdk-go/client/sandbox_template_api.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package client
diff --git a/components/sdk-go/client/secret_source_api.go b/components/sdk-go/client/secret_source_api.go
index c30ec4853..a1b36adef 100644
--- a/components/sdk-go/client/secret_source_api.go
+++ b/components/sdk-go/client/secret_source_api.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package client
diff --git a/components/sdk-go/client/user_api.go b/components/sdk-go/client/user_api.go
index 9cad600d0..89090e27e 100644
--- a/components/sdk-go/client/user_api.go
+++ b/components/sdk-go/client/user_api.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package client
diff --git a/components/sdk-go/types/agent_runtime.go b/components/sdk-go/types/agent_runtime.go
index cb7904353..eec996a6e 100644
--- a/components/sdk-go/types/agent_runtime.go
+++ b/components/sdk-go/types/agent_runtime.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package types
diff --git a/components/sdk-go/types/base.go b/components/sdk-go/types/base.go
index c150f3724..4eb1af4ef 100644
--- a/components/sdk-go/types/base.go
+++ b/components/sdk-go/types/base.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package types
diff --git a/components/sdk-go/types/gateway.go b/components/sdk-go/types/gateway.go
index cbdfa67b4..1f5f44841 100644
--- a/components/sdk-go/types/gateway.go
+++ b/components/sdk-go/types/gateway.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package types
@@ -9,6 +9,22 @@ import (
"fmt"
)
+type GatewayPlacementAvailability struct {
+ AwsPublic bool `json:"aws_public"`
+ AwsReason string `json:"aws_reason,omitempty"`
+ AwsVpn bool `json:"aws_vpn"`
+ IbmPublic bool `json:"ibm_public"`
+ IbmReason string `json:"ibm_reason,omitempty"`
+ IbmVpn bool `json:"ibm_vpn"`
+ LocalKind bool `json:"local_kind"`
+}
+
+type GatewayPlacementIntent struct {
+ Mode string `json:"mode,omitempty"`
+ Network string `json:"network,omitempty"`
+ Provider string `json:"provider,omitempty"`
+}
+
type Gateway struct {
ObjectReference
@@ -34,6 +50,8 @@ type Gateway struct {
Status string `json:"status,omitempty"`
SupervisorImage string `json:"supervisor_image,omitempty"`
TLSMode string `json:"tls_mode,omitempty"`
+
+ Placement GatewayPlacementIntent `json:"placement,omitempty"`
}
type GatewayList struct {
@@ -47,19 +65,15 @@ func (l *GatewayList) GetPage() int { return l.Page }
func (l *GatewayList) GetSize() int { return l.Size }
type GatewayBuilder struct {
- resource Gateway
- errors []error
+ resource Gateway
+ errors []error
+ placementSet bool
}
func NewGatewayBuilder() *GatewayBuilder {
return &GatewayBuilder{}
}
-func (b *GatewayBuilder) ClusterID(v string) *GatewayBuilder {
- b.resource.ClusterID = v
- return b
-}
-
func (b *GatewayBuilder) CredentialDriver(v string) *GatewayBuilder {
b.resource.CredentialDriver = v
return b
@@ -80,11 +94,22 @@ func (b *GatewayBuilder) Name(v string) *GatewayBuilder {
return b
}
+func (b *GatewayBuilder) Oidc(v string) *GatewayBuilder {
+ b.resource.Oidc = v
+ return b
+}
+
func (b *GatewayBuilder) Phase(v string) *GatewayBuilder {
b.resource.Phase = v
return b
}
+func (b *GatewayBuilder) Placement(v GatewayPlacementIntent) *GatewayBuilder {
+ b.resource.Placement = v
+ b.placementSet = true
+ return b
+}
+
func (b *GatewayBuilder) Route(v string) *GatewayBuilder {
b.resource.Route = v
return b
@@ -116,14 +141,11 @@ func (b *GatewayBuilder) TLSMode(v string) *GatewayBuilder {
}
func (b *GatewayBuilder) Build() (*Gateway, error) {
- if b.resource.ClusterID == "" {
- b.errors = append(b.errors, fmt.Errorf("cluster_id is required"))
- }
if b.resource.Name == "" {
b.errors = append(b.errors, fmt.Errorf("name is required"))
}
- if b.resource.Namespace == "" {
- b.errors = append(b.errors, fmt.Errorf("namespace is required"))
+ if !b.placementSet {
+ b.errors = append(b.errors, fmt.Errorf("placement is required"))
}
if len(b.errors) > 0 {
return nil, fmt.Errorf("validation failed: %w", errors.Join(b.errors...))
diff --git a/components/sdk-go/types/inference_route.go b/components/sdk-go/types/inference_route.go
index 34b306770..9b44c53f1 100644
--- a/components/sdk-go/types/inference_route.go
+++ b/components/sdk-go/types/inference_route.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package types
diff --git a/components/sdk-go/types/list_options.go b/components/sdk-go/types/list_options.go
index 42887b639..e1cfc1347 100644
--- a/components/sdk-go/types/list_options.go
+++ b/components/sdk-go/types/list_options.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package types
diff --git a/components/sdk-go/types/managed_cluster.go b/components/sdk-go/types/managed_cluster.go
index e7b44512c..e51e2e2eb 100644
--- a/components/sdk-go/types/managed_cluster.go
+++ b/components/sdk-go/types/managed_cluster.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package types
@@ -21,6 +21,7 @@ type ManagedCluster struct {
Provider string `json:"provider"`
Region string `json:"region,omitempty"`
Status string `json:"status,omitempty"`
+ Visibility string `json:"visibility,omitempty"`
}
type ManagedClusterList struct {
diff --git a/components/sdk-go/types/open_shell_gateway_service_account.go b/components/sdk-go/types/open_shell_gateway_service_account.go
index 5a4a9b2e3..c25321be9 100644
--- a/components/sdk-go/types/open_shell_gateway_service_account.go
+++ b/components/sdk-go/types/open_shell_gateway_service_account.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package types
diff --git a/components/sdk-go/types/provider_binding.go b/components/sdk-go/types/provider_binding.go
index fbc991fc2..a2ce63a9f 100644
--- a/components/sdk-go/types/provider_binding.go
+++ b/components/sdk-go/types/provider_binding.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package types
diff --git a/components/sdk-go/types/provider_spec.go b/components/sdk-go/types/provider_spec.go
index 70c2638cb..802f844a0 100644
--- a/components/sdk-go/types/provider_spec.go
+++ b/components/sdk-go/types/provider_spec.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package types
diff --git a/components/sdk-go/types/role.go b/components/sdk-go/types/role.go
index 5910f2f47..2eb79bfc0 100644
--- a/components/sdk-go/types/role.go
+++ b/components/sdk-go/types/role.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package types
diff --git a/components/sdk-go/types/role_binding.go b/components/sdk-go/types/role_binding.go
index 9b3c81cf5..19516384b 100644
--- a/components/sdk-go/types/role_binding.go
+++ b/components/sdk-go/types/role_binding.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package types
diff --git a/components/sdk-go/types/sandbox_template.go b/components/sdk-go/types/sandbox_template.go
index dbc4f56a9..fc1e0a92d 100644
--- a/components/sdk-go/types/sandbox_template.go
+++ b/components/sdk-go/types/sandbox_template.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package types
diff --git a/components/sdk-go/types/secret_source.go b/components/sdk-go/types/secret_source.go
index b31935435..c81f80a27 100644
--- a/components/sdk-go/types/secret_source.go
+++ b/components/sdk-go/types/secret_source.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package types
diff --git a/components/sdk-go/types/user.go b/components/sdk-go/types/user.go
index e06fb898b..9d083c20c 100644
--- a/components/sdk-go/types/user.go
+++ b/components/sdk-go/types/user.go
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
package types
diff --git a/components/sdk-typescript/src/agent_runtime.ts b/components/sdk-typescript/src/agent_runtime.ts
index af222decf..76471d473 100644
--- a/components/sdk-typescript/src/agent_runtime.ts
+++ b/components/sdk-typescript/src/agent_runtime.ts
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
import type { ObjectReference, ListMeta } from './base.js';
diff --git a/components/sdk-typescript/src/agent_runtime_api.ts b/components/sdk-typescript/src/agent_runtime_api.ts
index edb7f37e7..5d0c6d8d3 100644
--- a/components/sdk-typescript/src/agent_runtime_api.ts
+++ b/components/sdk-typescript/src/agent_runtime_api.ts
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
import type { SDKClientConfig, ListOptions, RequestOptions } from './base.js';
import { sdkFetch, buildQueryString } from './base.js';
diff --git a/components/sdk-typescript/src/base.ts b/components/sdk-typescript/src/base.ts
index 935513a51..248c52f24 100644
--- a/components/sdk-typescript/src/base.ts
+++ b/components/sdk-typescript/src/base.ts
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
export type ObjectReference = {
id: string;
diff --git a/components/sdk-typescript/src/client.ts b/components/sdk-typescript/src/client.ts
index 453f4104a..f37715bdb 100644
--- a/components/sdk-typescript/src/client.ts
+++ b/components/sdk-typescript/src/client.ts
@@ -1,6 +1,6 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
import type { SDKClientConfig } from './base.js';
import { AgentRuntimeAPI } from './agent_runtime_api.js';
diff --git a/components/sdk-typescript/src/gateway.ts b/components/sdk-typescript/src/gateway.ts
index 454a962a7..9976499b5 100644
--- a/components/sdk-typescript/src/gateway.ts
+++ b/components/sdk-typescript/src/gateway.ts
@@ -1,8 +1,26 @@
// Code generated by trex-sdk-generator from openapi.yaml - DO NOT EDIT.
// Source: components/api-server/openapi/openapi.yaml
-// Spec SHA256: e6bcd9eeb2b0f1844ca3cefb9576ac8b1acb78c6d19e0a83166f2a3c8acfdbd2
+// Spec SHA256: 4baf5c692945496c1ba8a1c195d838e0f028eb1471cf283b226daf69880cdc1d
import type { ObjectReference, ListMeta } from './base.js';
+export type GatewayPlacementAvailability = {
+ aws_public: boolean;
+ aws_reason?: "no-eligible-cluster";
+ aws_vpn: boolean;
+ ibm_public: boolean;
+ ibm_reason?: "no-eligible-cluster";
+ ibm_vpn: boolean;
+ local_kind: boolean;
+};
+
+
+
+export type GatewayPlacementIntent =
+ | { mode: 'local-kind' }
+ | { network: 'public'; provider: 'aws' | 'ibm' }
+ | { network: 'vpn'; provider: 'aws' };
+
+
export type Gateway = ObjectReference & {
active_sandbox_count: number;
@@ -34,12 +52,13 @@ export type GatewayList = ListMeta & {
};
export type GatewayCreateRequest = {
- cluster_id: string;
credential_driver?: string;
external_dns?: string;
image?: string;
name: string;
+ oidc?: string;
phase?: string;
+ placement: GatewayPlacementIntent;
route?: string;
server_dns_names?: string;
service_type?: string;
@@ -69,11 +88,6 @@ export class GatewayBuilder {
private data: Record
+ {description}
+
+ ) : descriptionLabel ? (
+
+ {description}
+
+ ) : (
+ description
+ )}
+
+