Migrate GetTunnelConnections/GetAllTunnelConnections to gRPC (#66066)

* hack on migrating list RPC

* Fix tests

* Tidy up/fix tests

* Use `clientutils.CollectWithFallback`

* Use clearer c.APIClient rather than rely on embeding

* Cover ListTunnelConnections in cache test

* tweak logging

* update deprecation version

* Move fallback impls

* fix span ctx prop

* fix pagination bug when unmarshal bad

* USe t.Context()

* fix ctx propagation

* Update tunn conns to use range pattern - thanks luke

* fix unneeded dependency

* fix deprecation

* env: dev
use opaque API
This commit is contained in:
Noah Stride
2026-06-11 12:44:50 +00:00
committed by GitHub
parent 76372472d2
commit a43fd71911
27 changed files with 1391 additions and 248 deletions
+18
View File
@@ -2538,6 +2538,24 @@ func (c *Client) RangeTrustedClusters(ctx context.Context, start, end string) it
return clientutils.RangeResources(ctx, start, end, c.ListTrustedClusters, types.TrustedCluster.GetName)
}
// ListTunnelConnections returns a page of tunnel connections matching the
// given filter.
func (c *Client) ListTunnelConnections(ctx context.Context, pageSize int, pageToken string, filter *trustpb.ListTunnelConnectionsFilter) ([]types.TunnelConnection, string, error) {
resp, err := c.TrustClient().ListTunnelConnections(ctx, &trustpb.ListTunnelConnectionsRequest{
PageSize: int32(pageSize),
PageToken: pageToken,
Filter: filter,
})
if err != nil {
return nil, "", trace.Wrap(err)
}
conns := make([]types.TunnelConnection, len(resp.TunnelConnections))
for i, v2 := range resp.TunnelConnections {
conns[i] = v2
}
return conns, resp.NextPageToken, nil
}
// UpsertTrustedCluster creates or updates a Trusted Cluster.
//
// Deprecated: Use [Client.UpsertTrustedClusterV2] instead.
@@ -1687,6 +1687,251 @@ func (b0 DeleteTunnelConnectionRequest_builder) Build() *DeleteTunnelConnectionR
return m0
}
// ListTunnelConnectionsRequest is the request for ListTunnelConnections.
type ListTunnelConnectionsRequest struct {
state protoimpl.MessageState `protogen:"hybrid.v1"`
// The maximum number of items to return.
// The server may impose a different page size at its discretion.
PageSize int32 `protobuf:"varint,1,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
// The next_page_token value returned from a previous List request, if any.
PageToken string `protobuf:"bytes,2,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
// Filter optionally narrows the returned tunnel connections.
Filter *ListTunnelConnectionsFilter `protobuf:"bytes,3,opt,name=filter,proto3" json:"filter,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListTunnelConnectionsRequest) Reset() {
*x = ListTunnelConnectionsRequest{}
mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListTunnelConnectionsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListTunnelConnectionsRequest) ProtoMessage() {}
func (x *ListTunnelConnectionsRequest) ProtoReflect() protoreflect.Message {
mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[20]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
func (x *ListTunnelConnectionsRequest) GetPageSize() int32 {
if x != nil {
return x.PageSize
}
return 0
}
func (x *ListTunnelConnectionsRequest) GetPageToken() string {
if x != nil {
return x.PageToken
}
return ""
}
func (x *ListTunnelConnectionsRequest) GetFilter() *ListTunnelConnectionsFilter {
if x != nil {
return x.Filter
}
return nil
}
func (x *ListTunnelConnectionsRequest) SetPageSize(v int32) {
x.PageSize = v
}
func (x *ListTunnelConnectionsRequest) SetPageToken(v string) {
x.PageToken = v
}
func (x *ListTunnelConnectionsRequest) SetFilter(v *ListTunnelConnectionsFilter) {
x.Filter = v
}
func (x *ListTunnelConnectionsRequest) HasFilter() bool {
if x == nil {
return false
}
return x.Filter != nil
}
func (x *ListTunnelConnectionsRequest) ClearFilter() {
x.Filter = nil
}
type ListTunnelConnectionsRequest_builder struct {
_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
// The maximum number of items to return.
// The server may impose a different page size at its discretion.
PageSize int32
// The next_page_token value returned from a previous List request, if any.
PageToken string
// Filter optionally narrows the returned tunnel connections.
Filter *ListTunnelConnectionsFilter
}
func (b0 ListTunnelConnectionsRequest_builder) Build() *ListTunnelConnectionsRequest {
m0 := &ListTunnelConnectionsRequest{}
b, x := &b0, m0
_, _ = b, x
x.PageSize = b.PageSize
x.PageToken = b.PageToken
x.Filter = b.Filter
return m0
}
// ListTunnelConnectionsFilter narrows the results of ListTunnelConnections.
type ListTunnelConnectionsFilter struct {
state protoimpl.MessageState `protogen:"hybrid.v1"`
// cluster_name, when set, limits results to tunnel connections for that
// cluster.
ClusterName string `protobuf:"bytes,1,opt,name=cluster_name,json=clusterName,proto3" json:"cluster_name,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListTunnelConnectionsFilter) Reset() {
*x = ListTunnelConnectionsFilter{}
mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListTunnelConnectionsFilter) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListTunnelConnectionsFilter) ProtoMessage() {}
func (x *ListTunnelConnectionsFilter) ProtoReflect() protoreflect.Message {
mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[21]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
func (x *ListTunnelConnectionsFilter) GetClusterName() string {
if x != nil {
return x.ClusterName
}
return ""
}
func (x *ListTunnelConnectionsFilter) SetClusterName(v string) {
x.ClusterName = v
}
type ListTunnelConnectionsFilter_builder struct {
_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
// cluster_name, when set, limits results to tunnel connections for that
// cluster.
ClusterName string
}
func (b0 ListTunnelConnectionsFilter_builder) Build() *ListTunnelConnectionsFilter {
m0 := &ListTunnelConnectionsFilter{}
b, x := &b0, m0
_, _ = b, x
x.ClusterName = b.ClusterName
return m0
}
// ListTunnelConnectionsResponse is the response for ListTunnelConnections.
type ListTunnelConnectionsResponse struct {
state protoimpl.MessageState `protogen:"hybrid.v1"`
// TunnelConnections is a page of tunnel connection resources.
TunnelConnections []*types.TunnelConnectionV2 `protobuf:"bytes,1,rep,name=tunnel_connections,json=tunnelConnections,proto3" json:"tunnel_connections,omitempty"`
// Token to retrieve the next page of results, or empty if there are no
// more results in the list.
NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListTunnelConnectionsResponse) Reset() {
*x = ListTunnelConnectionsResponse{}
mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListTunnelConnectionsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListTunnelConnectionsResponse) ProtoMessage() {}
func (x *ListTunnelConnectionsResponse) ProtoReflect() protoreflect.Message {
mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[22]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
func (x *ListTunnelConnectionsResponse) GetTunnelConnections() []*types.TunnelConnectionV2 {
if x != nil {
return x.TunnelConnections
}
return nil
}
func (x *ListTunnelConnectionsResponse) GetNextPageToken() string {
if x != nil {
return x.NextPageToken
}
return ""
}
func (x *ListTunnelConnectionsResponse) SetTunnelConnections(v []*types.TunnelConnectionV2) {
x.TunnelConnections = v
}
func (x *ListTunnelConnectionsResponse) SetNextPageToken(v string) {
x.NextPageToken = v
}
type ListTunnelConnectionsResponse_builder struct {
_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
// TunnelConnections is a page of tunnel connection resources.
TunnelConnections []*types.TunnelConnectionV2
// Token to retrieve the next page of results, or empty if there are no
// more results in the list.
NextPageToken string
}
func (b0 ListTunnelConnectionsResponse_builder) Build() *ListTunnelConnectionsResponse {
m0 := &ListTunnelConnectionsResponse{}
b, x := &b0, m0
_, _ = b, x
x.TunnelConnections = b.TunnelConnections
x.NextPageToken = b.NextPageToken
return m0
}
var File_teleport_trust_v1_trust_service_proto protoreflect.FileDescriptor
const file_teleport_trust_v1_trust_service_proto_rawDesc = "" +
@@ -1753,7 +1998,17 @@ const file_teleport_trust_v1_trust_service_proto_rawDesc = "" +
"\x11tunnel_connection\x18\x01 \x01(\v2\x19.types.TunnelConnectionV2R\x10tunnelConnection\"k\n" +
"\x1dDeleteTunnelConnectionRequest\x12!\n" +
"\fcluster_name\x18\x01 \x01(\tR\vclusterName\x12'\n" +
"\x0fconnection_name\x18\x02 \x01(\tR\x0econnectionName2\x83\v\n" +
"\x0fconnection_name\x18\x02 \x01(\tR\x0econnectionName\"\xa2\x01\n" +
"\x1cListTunnelConnectionsRequest\x12\x1b\n" +
"\tpage_size\x18\x01 \x01(\x05R\bpageSize\x12\x1d\n" +
"\n" +
"page_token\x18\x02 \x01(\tR\tpageToken\x12F\n" +
"\x06filter\x18\x03 \x01(\v2..teleport.trust.v1.ListTunnelConnectionsFilterR\x06filter\"@\n" +
"\x1bListTunnelConnectionsFilter\x12!\n" +
"\fcluster_name\x18\x01 \x01(\tR\vclusterName\"\x91\x01\n" +
"\x1dListTunnelConnectionsResponse\x12H\n" +
"\x12tunnel_connections\x18\x01 \x03(\v2\x19.types.TunnelConnectionV2R\x11tunnelConnections\x12&\n" +
"\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken2\xff\v\n" +
"\fTrustService\x12V\n" +
"\x10GetCertAuthority\x12*.teleport.trust.v1.GetCertAuthorityRequest\x1a\x16.types.CertAuthorityV2\x12q\n" +
"\x12GetCertAuthorities\x12,.teleport.trust.v1.GetCertAuthoritiesRequest\x1a-.teleport.trust.v1.GetCertAuthoritiesResponse\x12\\\n" +
@@ -1767,9 +2022,10 @@ const file_teleport_trust_v1_trust_service_proto_rawDesc = "" +
"\x14UpdateTrustedCluster\x12..teleport.trust.v1.UpdateTrustedClusterRequest\x1a\x17.types.TrustedClusterV2\x12t\n" +
"\x13ListTrustedClusters\x12-.teleport.trust.v1.ListTrustedClustersRequest\x1a..teleport.trust.v1.ListTrustedClustersResponse\x12}\n" +
"\x16UpsertTunnelConnection\x120.teleport.trust.v1.UpsertTunnelConnectionRequest\x1a1.teleport.trust.v1.UpsertTunnelConnectionResponse\x12b\n" +
"\x16DeleteTunnelConnection\x120.teleport.trust.v1.DeleteTunnelConnectionRequest\x1a\x16.google.protobuf.EmptyBNZLgithub.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1;trustv1b\x06proto3"
"\x16DeleteTunnelConnection\x120.teleport.trust.v1.DeleteTunnelConnectionRequest\x1a\x16.google.protobuf.Empty\x12z\n" +
"\x15ListTunnelConnections\x12/.teleport.trust.v1.ListTunnelConnectionsRequest\x1a0.teleport.trust.v1.ListTunnelConnectionsResponseBNZLgithub.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1;trustv1b\x06proto3"
var file_teleport_trust_v1_trust_service_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
var file_teleport_trust_v1_trust_service_proto_msgTypes = make([]protoimpl.MessageInfo, 23)
var file_teleport_trust_v1_trust_service_proto_goTypes = []any{
(*UpsertTrustedClusterRequest)(nil), // 0: teleport.trust.v1.UpsertTrustedClusterRequest
(*CreateTrustedClusterRequest)(nil), // 1: teleport.trust.v1.CreateTrustedClusterRequest
@@ -1791,60 +2047,67 @@ var file_teleport_trust_v1_trust_service_proto_goTypes = []any{
(*UpsertTunnelConnectionRequest)(nil), // 17: teleport.trust.v1.UpsertTunnelConnectionRequest
(*UpsertTunnelConnectionResponse)(nil), // 18: teleport.trust.v1.UpsertTunnelConnectionResponse
(*DeleteTunnelConnectionRequest)(nil), // 19: teleport.trust.v1.DeleteTunnelConnectionRequest
(*types.TrustedClusterV2)(nil), // 20: types.TrustedClusterV2
(*types.CertAuthorityV2)(nil), // 21: types.CertAuthorityV2
(*durationpb.Duration)(nil), // 22: google.protobuf.Duration
(*timestamppb.Timestamp)(nil), // 23: google.protobuf.Timestamp
(*types.TunnelConnectionV2)(nil), // 24: types.TunnelConnectionV2
(*emptypb.Empty)(nil), // 25: google.protobuf.Empty
(*ListTunnelConnectionsRequest)(nil), // 20: teleport.trust.v1.ListTunnelConnectionsRequest
(*ListTunnelConnectionsFilter)(nil), // 21: teleport.trust.v1.ListTunnelConnectionsFilter
(*ListTunnelConnectionsResponse)(nil), // 22: teleport.trust.v1.ListTunnelConnectionsResponse
(*types.TrustedClusterV2)(nil), // 23: types.TrustedClusterV2
(*types.CertAuthorityV2)(nil), // 24: types.CertAuthorityV2
(*durationpb.Duration)(nil), // 25: google.protobuf.Duration
(*timestamppb.Timestamp)(nil), // 26: google.protobuf.Timestamp
(*types.TunnelConnectionV2)(nil), // 27: types.TunnelConnectionV2
(*emptypb.Empty)(nil), // 28: google.protobuf.Empty
}
var file_teleport_trust_v1_trust_service_proto_depIdxs = []int32{
20, // 0: teleport.trust.v1.UpsertTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2
20, // 1: teleport.trust.v1.CreateTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2
20, // 2: teleport.trust.v1.UpdateTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2
21, // 3: teleport.trust.v1.GetCertAuthoritiesResponse.cert_authorities_v2:type_name -> types.CertAuthorityV2
21, // 4: teleport.trust.v1.UpsertCertAuthorityRequest.cert_authority:type_name -> types.CertAuthorityV2
22, // 5: teleport.trust.v1.RotateCertAuthorityRequest.grace_period:type_name -> google.protobuf.Duration
23, // 0: teleport.trust.v1.UpsertTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2
23, // 1: teleport.trust.v1.CreateTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2
23, // 2: teleport.trust.v1.UpdateTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2
24, // 3: teleport.trust.v1.GetCertAuthoritiesResponse.cert_authorities_v2:type_name -> types.CertAuthorityV2
24, // 4: teleport.trust.v1.UpsertCertAuthorityRequest.cert_authority:type_name -> types.CertAuthorityV2
25, // 5: teleport.trust.v1.RotateCertAuthorityRequest.grace_period:type_name -> google.protobuf.Duration
9, // 6: teleport.trust.v1.RotateCertAuthorityRequest.schedule:type_name -> teleport.trust.v1.RotationSchedule
23, // 7: teleport.trust.v1.RotationSchedule.update_clients:type_name -> google.protobuf.Timestamp
23, // 8: teleport.trust.v1.RotationSchedule.update_servers:type_name -> google.protobuf.Timestamp
23, // 9: teleport.trust.v1.RotationSchedule.standby:type_name -> google.protobuf.Timestamp
21, // 10: teleport.trust.v1.RotateExternalCertAuthorityRequest.cert_authority:type_name -> types.CertAuthorityV2
22, // 11: teleport.trust.v1.GenerateHostCertRequest.ttl:type_name -> google.protobuf.Duration
20, // 12: teleport.trust.v1.ListTrustedClustersResponse.trusted_clusters:type_name -> types.TrustedClusterV2
24, // 13: teleport.trust.v1.UpsertTunnelConnectionRequest.tunnel_connection:type_name -> types.TunnelConnectionV2
24, // 14: teleport.trust.v1.UpsertTunnelConnectionResponse.tunnel_connection:type_name -> types.TunnelConnectionV2
3, // 15: teleport.trust.v1.TrustService.GetCertAuthority:input_type -> teleport.trust.v1.GetCertAuthorityRequest
4, // 16: teleport.trust.v1.TrustService.GetCertAuthorities:input_type -> teleport.trust.v1.GetCertAuthoritiesRequest
6, // 17: teleport.trust.v1.TrustService.DeleteCertAuthority:input_type -> teleport.trust.v1.DeleteCertAuthorityRequest
7, // 18: teleport.trust.v1.TrustService.UpsertCertAuthority:input_type -> teleport.trust.v1.UpsertCertAuthorityRequest
8, // 19: teleport.trust.v1.TrustService.RotateCertAuthority:input_type -> teleport.trust.v1.RotateCertAuthorityRequest
11, // 20: teleport.trust.v1.TrustService.RotateExternalCertAuthority:input_type -> teleport.trust.v1.RotateExternalCertAuthorityRequest
13, // 21: teleport.trust.v1.TrustService.GenerateHostCert:input_type -> teleport.trust.v1.GenerateHostCertRequest
0, // 22: teleport.trust.v1.TrustService.UpsertTrustedCluster:input_type -> teleport.trust.v1.UpsertTrustedClusterRequest
1, // 23: teleport.trust.v1.TrustService.CreateTrustedCluster:input_type -> teleport.trust.v1.CreateTrustedClusterRequest
2, // 24: teleport.trust.v1.TrustService.UpdateTrustedCluster:input_type -> teleport.trust.v1.UpdateTrustedClusterRequest
15, // 25: teleport.trust.v1.TrustService.ListTrustedClusters:input_type -> teleport.trust.v1.ListTrustedClustersRequest
17, // 26: teleport.trust.v1.TrustService.UpsertTunnelConnection:input_type -> teleport.trust.v1.UpsertTunnelConnectionRequest
19, // 27: teleport.trust.v1.TrustService.DeleteTunnelConnection:input_type -> teleport.trust.v1.DeleteTunnelConnectionRequest
21, // 28: teleport.trust.v1.TrustService.GetCertAuthority:output_type -> types.CertAuthorityV2
5, // 29: teleport.trust.v1.TrustService.GetCertAuthorities:output_type -> teleport.trust.v1.GetCertAuthoritiesResponse
25, // 30: teleport.trust.v1.TrustService.DeleteCertAuthority:output_type -> google.protobuf.Empty
21, // 31: teleport.trust.v1.TrustService.UpsertCertAuthority:output_type -> types.CertAuthorityV2
10, // 32: teleport.trust.v1.TrustService.RotateCertAuthority:output_type -> teleport.trust.v1.RotateCertAuthorityResponse
12, // 33: teleport.trust.v1.TrustService.RotateExternalCertAuthority:output_type -> teleport.trust.v1.RotateExternalCertAuthorityResponse
14, // 34: teleport.trust.v1.TrustService.GenerateHostCert:output_type -> teleport.trust.v1.GenerateHostCertResponse
20, // 35: teleport.trust.v1.TrustService.UpsertTrustedCluster:output_type -> types.TrustedClusterV2
20, // 36: teleport.trust.v1.TrustService.CreateTrustedCluster:output_type -> types.TrustedClusterV2
20, // 37: teleport.trust.v1.TrustService.UpdateTrustedCluster:output_type -> types.TrustedClusterV2
16, // 38: teleport.trust.v1.TrustService.ListTrustedClusters:output_type -> teleport.trust.v1.ListTrustedClustersResponse
18, // 39: teleport.trust.v1.TrustService.UpsertTunnelConnection:output_type -> teleport.trust.v1.UpsertTunnelConnectionResponse
25, // 40: teleport.trust.v1.TrustService.DeleteTunnelConnection:output_type -> google.protobuf.Empty
28, // [28:41] is the sub-list for method output_type
15, // [15:28] is the sub-list for method input_type
15, // [15:15] is the sub-list for extension type_name
15, // [15:15] is the sub-list for extension extendee
0, // [0:15] is the sub-list for field type_name
26, // 7: teleport.trust.v1.RotationSchedule.update_clients:type_name -> google.protobuf.Timestamp
26, // 8: teleport.trust.v1.RotationSchedule.update_servers:type_name -> google.protobuf.Timestamp
26, // 9: teleport.trust.v1.RotationSchedule.standby:type_name -> google.protobuf.Timestamp
24, // 10: teleport.trust.v1.RotateExternalCertAuthorityRequest.cert_authority:type_name -> types.CertAuthorityV2
25, // 11: teleport.trust.v1.GenerateHostCertRequest.ttl:type_name -> google.protobuf.Duration
23, // 12: teleport.trust.v1.ListTrustedClustersResponse.trusted_clusters:type_name -> types.TrustedClusterV2
27, // 13: teleport.trust.v1.UpsertTunnelConnectionRequest.tunnel_connection:type_name -> types.TunnelConnectionV2
27, // 14: teleport.trust.v1.UpsertTunnelConnectionResponse.tunnel_connection:type_name -> types.TunnelConnectionV2
21, // 15: teleport.trust.v1.ListTunnelConnectionsRequest.filter:type_name -> teleport.trust.v1.ListTunnelConnectionsFilter
27, // 16: teleport.trust.v1.ListTunnelConnectionsResponse.tunnel_connections:type_name -> types.TunnelConnectionV2
3, // 17: teleport.trust.v1.TrustService.GetCertAuthority:input_type -> teleport.trust.v1.GetCertAuthorityRequest
4, // 18: teleport.trust.v1.TrustService.GetCertAuthorities:input_type -> teleport.trust.v1.GetCertAuthoritiesRequest
6, // 19: teleport.trust.v1.TrustService.DeleteCertAuthority:input_type -> teleport.trust.v1.DeleteCertAuthorityRequest
7, // 20: teleport.trust.v1.TrustService.UpsertCertAuthority:input_type -> teleport.trust.v1.UpsertCertAuthorityRequest
8, // 21: teleport.trust.v1.TrustService.RotateCertAuthority:input_type -> teleport.trust.v1.RotateCertAuthorityRequest
11, // 22: teleport.trust.v1.TrustService.RotateExternalCertAuthority:input_type -> teleport.trust.v1.RotateExternalCertAuthorityRequest
13, // 23: teleport.trust.v1.TrustService.GenerateHostCert:input_type -> teleport.trust.v1.GenerateHostCertRequest
0, // 24: teleport.trust.v1.TrustService.UpsertTrustedCluster:input_type -> teleport.trust.v1.UpsertTrustedClusterRequest
1, // 25: teleport.trust.v1.TrustService.CreateTrustedCluster:input_type -> teleport.trust.v1.CreateTrustedClusterRequest
2, // 26: teleport.trust.v1.TrustService.UpdateTrustedCluster:input_type -> teleport.trust.v1.UpdateTrustedClusterRequest
15, // 27: teleport.trust.v1.TrustService.ListTrustedClusters:input_type -> teleport.trust.v1.ListTrustedClustersRequest
17, // 28: teleport.trust.v1.TrustService.UpsertTunnelConnection:input_type -> teleport.trust.v1.UpsertTunnelConnectionRequest
19, // 29: teleport.trust.v1.TrustService.DeleteTunnelConnection:input_type -> teleport.trust.v1.DeleteTunnelConnectionRequest
20, // 30: teleport.trust.v1.TrustService.ListTunnelConnections:input_type -> teleport.trust.v1.ListTunnelConnectionsRequest
24, // 31: teleport.trust.v1.TrustService.GetCertAuthority:output_type -> types.CertAuthorityV2
5, // 32: teleport.trust.v1.TrustService.GetCertAuthorities:output_type -> teleport.trust.v1.GetCertAuthoritiesResponse
28, // 33: teleport.trust.v1.TrustService.DeleteCertAuthority:output_type -> google.protobuf.Empty
24, // 34: teleport.trust.v1.TrustService.UpsertCertAuthority:output_type -> types.CertAuthorityV2
10, // 35: teleport.trust.v1.TrustService.RotateCertAuthority:output_type -> teleport.trust.v1.RotateCertAuthorityResponse
12, // 36: teleport.trust.v1.TrustService.RotateExternalCertAuthority:output_type -> teleport.trust.v1.RotateExternalCertAuthorityResponse
14, // 37: teleport.trust.v1.TrustService.GenerateHostCert:output_type -> teleport.trust.v1.GenerateHostCertResponse
23, // 38: teleport.trust.v1.TrustService.UpsertTrustedCluster:output_type -> types.TrustedClusterV2
23, // 39: teleport.trust.v1.TrustService.CreateTrustedCluster:output_type -> types.TrustedClusterV2
23, // 40: teleport.trust.v1.TrustService.UpdateTrustedCluster:output_type -> types.TrustedClusterV2
16, // 41: teleport.trust.v1.TrustService.ListTrustedClusters:output_type -> teleport.trust.v1.ListTrustedClustersResponse
18, // 42: teleport.trust.v1.TrustService.UpsertTunnelConnection:output_type -> teleport.trust.v1.UpsertTunnelConnectionResponse
28, // 43: teleport.trust.v1.TrustService.DeleteTunnelConnection:output_type -> google.protobuf.Empty
22, // 44: teleport.trust.v1.TrustService.ListTunnelConnections:output_type -> teleport.trust.v1.ListTunnelConnectionsResponse
31, // [31:45] is the sub-list for method output_type
17, // [17:31] is the sub-list for method input_type
17, // [17:17] is the sub-list for extension type_name
17, // [17:17] is the sub-list for extension extendee
0, // [0:17] is the sub-list for field type_name
}
func init() { file_teleport_trust_v1_trust_service_proto_init() }
@@ -1858,7 +2121,7 @@ func file_teleport_trust_v1_trust_service_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_teleport_trust_v1_trust_service_proto_rawDesc), len(file_teleport_trust_v1_trust_service_proto_rawDesc)),
NumEnums: 0,
NumMessages: 20,
NumMessages: 23,
NumExtensions: 0,
NumServices: 1,
},
@@ -48,6 +48,7 @@ const (
TrustService_ListTrustedClusters_FullMethodName = "/teleport.trust.v1.TrustService/ListTrustedClusters"
TrustService_UpsertTunnelConnection_FullMethodName = "/teleport.trust.v1.TrustService/UpsertTunnelConnection"
TrustService_DeleteTunnelConnection_FullMethodName = "/teleport.trust.v1.TrustService/DeleteTunnelConnection"
TrustService_ListTunnelConnections_FullMethodName = "/teleport.trust.v1.TrustService/ListTunnelConnections"
)
// TrustServiceClient is the client API for TrustService service.
@@ -85,6 +86,9 @@ type TrustServiceClient interface {
// DeleteTunnelConnection removes a single tunnel connection record by
// cluster name and connection name.
DeleteTunnelConnection(ctx context.Context, in *DeleteTunnelConnectionRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// ListTunnelConnections returns a page of tunnel connection records,
// optionally filtered.
ListTunnelConnections(ctx context.Context, in *ListTunnelConnectionsRequest, opts ...grpc.CallOption) (*ListTunnelConnectionsResponse, error)
}
type trustServiceClient struct {
@@ -225,6 +229,16 @@ func (c *trustServiceClient) DeleteTunnelConnection(ctx context.Context, in *Del
return out, nil
}
func (c *trustServiceClient) ListTunnelConnections(ctx context.Context, in *ListTunnelConnectionsRequest, opts ...grpc.CallOption) (*ListTunnelConnectionsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ListTunnelConnectionsResponse)
err := c.cc.Invoke(ctx, TrustService_ListTunnelConnections_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// TrustServiceServer is the server API for TrustService service.
// All implementations must embed UnimplementedTrustServiceServer
// for forward compatibility.
@@ -260,6 +274,9 @@ type TrustServiceServer interface {
// DeleteTunnelConnection removes a single tunnel connection record by
// cluster name and connection name.
DeleteTunnelConnection(context.Context, *DeleteTunnelConnectionRequest) (*emptypb.Empty, error)
// ListTunnelConnections returns a page of tunnel connection records,
// optionally filtered.
ListTunnelConnections(context.Context, *ListTunnelConnectionsRequest) (*ListTunnelConnectionsResponse, error)
mustEmbedUnimplementedTrustServiceServer()
}
@@ -309,6 +326,9 @@ func (UnimplementedTrustServiceServer) UpsertTunnelConnection(context.Context, *
func (UnimplementedTrustServiceServer) DeleteTunnelConnection(context.Context, *DeleteTunnelConnectionRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteTunnelConnection not implemented")
}
func (UnimplementedTrustServiceServer) ListTunnelConnections(context.Context, *ListTunnelConnectionsRequest) (*ListTunnelConnectionsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListTunnelConnections not implemented")
}
func (UnimplementedTrustServiceServer) mustEmbedUnimplementedTrustServiceServer() {}
func (UnimplementedTrustServiceServer) testEmbeddedByValue() {}
@@ -564,6 +584,24 @@ func _TrustService_DeleteTunnelConnection_Handler(srv interface{}, ctx context.C
return interceptor(ctx, in, info, handler)
}
func _TrustService_ListTunnelConnections_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListTunnelConnectionsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TrustServiceServer).ListTunnelConnections(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: TrustService_ListTunnelConnections_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TrustServiceServer).ListTunnelConnections(ctx, req.(*ListTunnelConnectionsRequest))
}
return interceptor(ctx, in, info, handler)
}
// TrustService_ServiceDesc is the grpc.ServiceDesc for TrustService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -623,6 +661,10 @@ var TrustService_ServiceDesc = grpc.ServiceDesc{
MethodName: "DeleteTunnelConnection",
Handler: _TrustService_DeleteTunnelConnection_Handler,
},
{
MethodName: "ListTunnelConnections",
Handler: _TrustService_ListTunnelConnections_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "teleport/trust/v1/trust_service.proto",
@@ -1641,6 +1641,244 @@ func (b0 DeleteTunnelConnectionRequest_builder) Build() *DeleteTunnelConnectionR
return m0
}
// ListTunnelConnectionsRequest is the request for ListTunnelConnections.
type ListTunnelConnectionsRequest struct {
state protoimpl.MessageState `protogen:"opaque.v1"`
xxx_hidden_PageSize int32 `protobuf:"varint,1,opt,name=page_size,json=pageSize,proto3"`
xxx_hidden_PageToken string `protobuf:"bytes,2,opt,name=page_token,json=pageToken,proto3"`
xxx_hidden_Filter *ListTunnelConnectionsFilter `protobuf:"bytes,3,opt,name=filter,proto3"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListTunnelConnectionsRequest) Reset() {
*x = ListTunnelConnectionsRequest{}
mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListTunnelConnectionsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListTunnelConnectionsRequest) ProtoMessage() {}
func (x *ListTunnelConnectionsRequest) ProtoReflect() protoreflect.Message {
mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[20]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
func (x *ListTunnelConnectionsRequest) GetPageSize() int32 {
if x != nil {
return x.xxx_hidden_PageSize
}
return 0
}
func (x *ListTunnelConnectionsRequest) GetPageToken() string {
if x != nil {
return x.xxx_hidden_PageToken
}
return ""
}
func (x *ListTunnelConnectionsRequest) GetFilter() *ListTunnelConnectionsFilter {
if x != nil {
return x.xxx_hidden_Filter
}
return nil
}
func (x *ListTunnelConnectionsRequest) SetPageSize(v int32) {
x.xxx_hidden_PageSize = v
}
func (x *ListTunnelConnectionsRequest) SetPageToken(v string) {
x.xxx_hidden_PageToken = v
}
func (x *ListTunnelConnectionsRequest) SetFilter(v *ListTunnelConnectionsFilter) {
x.xxx_hidden_Filter = v
}
func (x *ListTunnelConnectionsRequest) HasFilter() bool {
if x == nil {
return false
}
return x.xxx_hidden_Filter != nil
}
func (x *ListTunnelConnectionsRequest) ClearFilter() {
x.xxx_hidden_Filter = nil
}
type ListTunnelConnectionsRequest_builder struct {
_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
// The maximum number of items to return.
// The server may impose a different page size at its discretion.
PageSize int32
// The next_page_token value returned from a previous List request, if any.
PageToken string
// Filter optionally narrows the returned tunnel connections.
Filter *ListTunnelConnectionsFilter
}
func (b0 ListTunnelConnectionsRequest_builder) Build() *ListTunnelConnectionsRequest {
m0 := &ListTunnelConnectionsRequest{}
b, x := &b0, m0
_, _ = b, x
x.xxx_hidden_PageSize = b.PageSize
x.xxx_hidden_PageToken = b.PageToken
x.xxx_hidden_Filter = b.Filter
return m0
}
// ListTunnelConnectionsFilter narrows the results of ListTunnelConnections.
type ListTunnelConnectionsFilter struct {
state protoimpl.MessageState `protogen:"opaque.v1"`
xxx_hidden_ClusterName string `protobuf:"bytes,1,opt,name=cluster_name,json=clusterName,proto3"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListTunnelConnectionsFilter) Reset() {
*x = ListTunnelConnectionsFilter{}
mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListTunnelConnectionsFilter) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListTunnelConnectionsFilter) ProtoMessage() {}
func (x *ListTunnelConnectionsFilter) ProtoReflect() protoreflect.Message {
mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[21]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
func (x *ListTunnelConnectionsFilter) GetClusterName() string {
if x != nil {
return x.xxx_hidden_ClusterName
}
return ""
}
func (x *ListTunnelConnectionsFilter) SetClusterName(v string) {
x.xxx_hidden_ClusterName = v
}
type ListTunnelConnectionsFilter_builder struct {
_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
// cluster_name, when set, limits results to tunnel connections for that
// cluster.
ClusterName string
}
func (b0 ListTunnelConnectionsFilter_builder) Build() *ListTunnelConnectionsFilter {
m0 := &ListTunnelConnectionsFilter{}
b, x := &b0, m0
_, _ = b, x
x.xxx_hidden_ClusterName = b.ClusterName
return m0
}
// ListTunnelConnectionsResponse is the response for ListTunnelConnections.
type ListTunnelConnectionsResponse struct {
state protoimpl.MessageState `protogen:"opaque.v1"`
xxx_hidden_TunnelConnections *[]*types.TunnelConnectionV2 `protobuf:"bytes,1,rep,name=tunnel_connections,json=tunnelConnections,proto3"`
xxx_hidden_NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListTunnelConnectionsResponse) Reset() {
*x = ListTunnelConnectionsResponse{}
mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListTunnelConnectionsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListTunnelConnectionsResponse) ProtoMessage() {}
func (x *ListTunnelConnectionsResponse) ProtoReflect() protoreflect.Message {
mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[22]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
func (x *ListTunnelConnectionsResponse) GetTunnelConnections() []*types.TunnelConnectionV2 {
if x != nil {
if x.xxx_hidden_TunnelConnections != nil {
return *x.xxx_hidden_TunnelConnections
}
}
return nil
}
func (x *ListTunnelConnectionsResponse) GetNextPageToken() string {
if x != nil {
return x.xxx_hidden_NextPageToken
}
return ""
}
func (x *ListTunnelConnectionsResponse) SetTunnelConnections(v []*types.TunnelConnectionV2) {
x.xxx_hidden_TunnelConnections = &v
}
func (x *ListTunnelConnectionsResponse) SetNextPageToken(v string) {
x.xxx_hidden_NextPageToken = v
}
type ListTunnelConnectionsResponse_builder struct {
_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
// TunnelConnections is a page of tunnel connection resources.
TunnelConnections []*types.TunnelConnectionV2
// Token to retrieve the next page of results, or empty if there are no
// more results in the list.
NextPageToken string
}
func (b0 ListTunnelConnectionsResponse_builder) Build() *ListTunnelConnectionsResponse {
m0 := &ListTunnelConnectionsResponse{}
b, x := &b0, m0
_, _ = b, x
x.xxx_hidden_TunnelConnections = &b.TunnelConnections
x.xxx_hidden_NextPageToken = b.NextPageToken
return m0
}
var File_teleport_trust_v1_trust_service_proto protoreflect.FileDescriptor
const file_teleport_trust_v1_trust_service_proto_rawDesc = "" +
@@ -1707,7 +1945,17 @@ const file_teleport_trust_v1_trust_service_proto_rawDesc = "" +
"\x11tunnel_connection\x18\x01 \x01(\v2\x19.types.TunnelConnectionV2R\x10tunnelConnection\"k\n" +
"\x1dDeleteTunnelConnectionRequest\x12!\n" +
"\fcluster_name\x18\x01 \x01(\tR\vclusterName\x12'\n" +
"\x0fconnection_name\x18\x02 \x01(\tR\x0econnectionName2\x83\v\n" +
"\x0fconnection_name\x18\x02 \x01(\tR\x0econnectionName\"\xa2\x01\n" +
"\x1cListTunnelConnectionsRequest\x12\x1b\n" +
"\tpage_size\x18\x01 \x01(\x05R\bpageSize\x12\x1d\n" +
"\n" +
"page_token\x18\x02 \x01(\tR\tpageToken\x12F\n" +
"\x06filter\x18\x03 \x01(\v2..teleport.trust.v1.ListTunnelConnectionsFilterR\x06filter\"@\n" +
"\x1bListTunnelConnectionsFilter\x12!\n" +
"\fcluster_name\x18\x01 \x01(\tR\vclusterName\"\x91\x01\n" +
"\x1dListTunnelConnectionsResponse\x12H\n" +
"\x12tunnel_connections\x18\x01 \x03(\v2\x19.types.TunnelConnectionV2R\x11tunnelConnections\x12&\n" +
"\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken2\xff\v\n" +
"\fTrustService\x12V\n" +
"\x10GetCertAuthority\x12*.teleport.trust.v1.GetCertAuthorityRequest\x1a\x16.types.CertAuthorityV2\x12q\n" +
"\x12GetCertAuthorities\x12,.teleport.trust.v1.GetCertAuthoritiesRequest\x1a-.teleport.trust.v1.GetCertAuthoritiesResponse\x12\\\n" +
@@ -1721,9 +1969,10 @@ const file_teleport_trust_v1_trust_service_proto_rawDesc = "" +
"\x14UpdateTrustedCluster\x12..teleport.trust.v1.UpdateTrustedClusterRequest\x1a\x17.types.TrustedClusterV2\x12t\n" +
"\x13ListTrustedClusters\x12-.teleport.trust.v1.ListTrustedClustersRequest\x1a..teleport.trust.v1.ListTrustedClustersResponse\x12}\n" +
"\x16UpsertTunnelConnection\x120.teleport.trust.v1.UpsertTunnelConnectionRequest\x1a1.teleport.trust.v1.UpsertTunnelConnectionResponse\x12b\n" +
"\x16DeleteTunnelConnection\x120.teleport.trust.v1.DeleteTunnelConnectionRequest\x1a\x16.google.protobuf.EmptyBNZLgithub.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1;trustv1b\x06proto3"
"\x16DeleteTunnelConnection\x120.teleport.trust.v1.DeleteTunnelConnectionRequest\x1a\x16.google.protobuf.Empty\x12z\n" +
"\x15ListTunnelConnections\x12/.teleport.trust.v1.ListTunnelConnectionsRequest\x1a0.teleport.trust.v1.ListTunnelConnectionsResponseBNZLgithub.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1;trustv1b\x06proto3"
var file_teleport_trust_v1_trust_service_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
var file_teleport_trust_v1_trust_service_proto_msgTypes = make([]protoimpl.MessageInfo, 23)
var file_teleport_trust_v1_trust_service_proto_goTypes = []any{
(*UpsertTrustedClusterRequest)(nil), // 0: teleport.trust.v1.UpsertTrustedClusterRequest
(*CreateTrustedClusterRequest)(nil), // 1: teleport.trust.v1.CreateTrustedClusterRequest
@@ -1745,60 +1994,67 @@ var file_teleport_trust_v1_trust_service_proto_goTypes = []any{
(*UpsertTunnelConnectionRequest)(nil), // 17: teleport.trust.v1.UpsertTunnelConnectionRequest
(*UpsertTunnelConnectionResponse)(nil), // 18: teleport.trust.v1.UpsertTunnelConnectionResponse
(*DeleteTunnelConnectionRequest)(nil), // 19: teleport.trust.v1.DeleteTunnelConnectionRequest
(*types.TrustedClusterV2)(nil), // 20: types.TrustedClusterV2
(*types.CertAuthorityV2)(nil), // 21: types.CertAuthorityV2
(*durationpb.Duration)(nil), // 22: google.protobuf.Duration
(*timestamppb.Timestamp)(nil), // 23: google.protobuf.Timestamp
(*types.TunnelConnectionV2)(nil), // 24: types.TunnelConnectionV2
(*emptypb.Empty)(nil), // 25: google.protobuf.Empty
(*ListTunnelConnectionsRequest)(nil), // 20: teleport.trust.v1.ListTunnelConnectionsRequest
(*ListTunnelConnectionsFilter)(nil), // 21: teleport.trust.v1.ListTunnelConnectionsFilter
(*ListTunnelConnectionsResponse)(nil), // 22: teleport.trust.v1.ListTunnelConnectionsResponse
(*types.TrustedClusterV2)(nil), // 23: types.TrustedClusterV2
(*types.CertAuthorityV2)(nil), // 24: types.CertAuthorityV2
(*durationpb.Duration)(nil), // 25: google.protobuf.Duration
(*timestamppb.Timestamp)(nil), // 26: google.protobuf.Timestamp
(*types.TunnelConnectionV2)(nil), // 27: types.TunnelConnectionV2
(*emptypb.Empty)(nil), // 28: google.protobuf.Empty
}
var file_teleport_trust_v1_trust_service_proto_depIdxs = []int32{
20, // 0: teleport.trust.v1.UpsertTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2
20, // 1: teleport.trust.v1.CreateTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2
20, // 2: teleport.trust.v1.UpdateTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2
21, // 3: teleport.trust.v1.GetCertAuthoritiesResponse.cert_authorities_v2:type_name -> types.CertAuthorityV2
21, // 4: teleport.trust.v1.UpsertCertAuthorityRequest.cert_authority:type_name -> types.CertAuthorityV2
22, // 5: teleport.trust.v1.RotateCertAuthorityRequest.grace_period:type_name -> google.protobuf.Duration
23, // 0: teleport.trust.v1.UpsertTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2
23, // 1: teleport.trust.v1.CreateTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2
23, // 2: teleport.trust.v1.UpdateTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2
24, // 3: teleport.trust.v1.GetCertAuthoritiesResponse.cert_authorities_v2:type_name -> types.CertAuthorityV2
24, // 4: teleport.trust.v1.UpsertCertAuthorityRequest.cert_authority:type_name -> types.CertAuthorityV2
25, // 5: teleport.trust.v1.RotateCertAuthorityRequest.grace_period:type_name -> google.protobuf.Duration
9, // 6: teleport.trust.v1.RotateCertAuthorityRequest.schedule:type_name -> teleport.trust.v1.RotationSchedule
23, // 7: teleport.trust.v1.RotationSchedule.update_clients:type_name -> google.protobuf.Timestamp
23, // 8: teleport.trust.v1.RotationSchedule.update_servers:type_name -> google.protobuf.Timestamp
23, // 9: teleport.trust.v1.RotationSchedule.standby:type_name -> google.protobuf.Timestamp
21, // 10: teleport.trust.v1.RotateExternalCertAuthorityRequest.cert_authority:type_name -> types.CertAuthorityV2
22, // 11: teleport.trust.v1.GenerateHostCertRequest.ttl:type_name -> google.protobuf.Duration
20, // 12: teleport.trust.v1.ListTrustedClustersResponse.trusted_clusters:type_name -> types.TrustedClusterV2
24, // 13: teleport.trust.v1.UpsertTunnelConnectionRequest.tunnel_connection:type_name -> types.TunnelConnectionV2
24, // 14: teleport.trust.v1.UpsertTunnelConnectionResponse.tunnel_connection:type_name -> types.TunnelConnectionV2
3, // 15: teleport.trust.v1.TrustService.GetCertAuthority:input_type -> teleport.trust.v1.GetCertAuthorityRequest
4, // 16: teleport.trust.v1.TrustService.GetCertAuthorities:input_type -> teleport.trust.v1.GetCertAuthoritiesRequest
6, // 17: teleport.trust.v1.TrustService.DeleteCertAuthority:input_type -> teleport.trust.v1.DeleteCertAuthorityRequest
7, // 18: teleport.trust.v1.TrustService.UpsertCertAuthority:input_type -> teleport.trust.v1.UpsertCertAuthorityRequest
8, // 19: teleport.trust.v1.TrustService.RotateCertAuthority:input_type -> teleport.trust.v1.RotateCertAuthorityRequest
11, // 20: teleport.trust.v1.TrustService.RotateExternalCertAuthority:input_type -> teleport.trust.v1.RotateExternalCertAuthorityRequest
13, // 21: teleport.trust.v1.TrustService.GenerateHostCert:input_type -> teleport.trust.v1.GenerateHostCertRequest
0, // 22: teleport.trust.v1.TrustService.UpsertTrustedCluster:input_type -> teleport.trust.v1.UpsertTrustedClusterRequest
1, // 23: teleport.trust.v1.TrustService.CreateTrustedCluster:input_type -> teleport.trust.v1.CreateTrustedClusterRequest
2, // 24: teleport.trust.v1.TrustService.UpdateTrustedCluster:input_type -> teleport.trust.v1.UpdateTrustedClusterRequest
15, // 25: teleport.trust.v1.TrustService.ListTrustedClusters:input_type -> teleport.trust.v1.ListTrustedClustersRequest
17, // 26: teleport.trust.v1.TrustService.UpsertTunnelConnection:input_type -> teleport.trust.v1.UpsertTunnelConnectionRequest
19, // 27: teleport.trust.v1.TrustService.DeleteTunnelConnection:input_type -> teleport.trust.v1.DeleteTunnelConnectionRequest
21, // 28: teleport.trust.v1.TrustService.GetCertAuthority:output_type -> types.CertAuthorityV2
5, // 29: teleport.trust.v1.TrustService.GetCertAuthorities:output_type -> teleport.trust.v1.GetCertAuthoritiesResponse
25, // 30: teleport.trust.v1.TrustService.DeleteCertAuthority:output_type -> google.protobuf.Empty
21, // 31: teleport.trust.v1.TrustService.UpsertCertAuthority:output_type -> types.CertAuthorityV2
10, // 32: teleport.trust.v1.TrustService.RotateCertAuthority:output_type -> teleport.trust.v1.RotateCertAuthorityResponse
12, // 33: teleport.trust.v1.TrustService.RotateExternalCertAuthority:output_type -> teleport.trust.v1.RotateExternalCertAuthorityResponse
14, // 34: teleport.trust.v1.TrustService.GenerateHostCert:output_type -> teleport.trust.v1.GenerateHostCertResponse
20, // 35: teleport.trust.v1.TrustService.UpsertTrustedCluster:output_type -> types.TrustedClusterV2
20, // 36: teleport.trust.v1.TrustService.CreateTrustedCluster:output_type -> types.TrustedClusterV2
20, // 37: teleport.trust.v1.TrustService.UpdateTrustedCluster:output_type -> types.TrustedClusterV2
16, // 38: teleport.trust.v1.TrustService.ListTrustedClusters:output_type -> teleport.trust.v1.ListTrustedClustersResponse
18, // 39: teleport.trust.v1.TrustService.UpsertTunnelConnection:output_type -> teleport.trust.v1.UpsertTunnelConnectionResponse
25, // 40: teleport.trust.v1.TrustService.DeleteTunnelConnection:output_type -> google.protobuf.Empty
28, // [28:41] is the sub-list for method output_type
15, // [15:28] is the sub-list for method input_type
15, // [15:15] is the sub-list for extension type_name
15, // [15:15] is the sub-list for extension extendee
0, // [0:15] is the sub-list for field type_name
26, // 7: teleport.trust.v1.RotationSchedule.update_clients:type_name -> google.protobuf.Timestamp
26, // 8: teleport.trust.v1.RotationSchedule.update_servers:type_name -> google.protobuf.Timestamp
26, // 9: teleport.trust.v1.RotationSchedule.standby:type_name -> google.protobuf.Timestamp
24, // 10: teleport.trust.v1.RotateExternalCertAuthorityRequest.cert_authority:type_name -> types.CertAuthorityV2
25, // 11: teleport.trust.v1.GenerateHostCertRequest.ttl:type_name -> google.protobuf.Duration
23, // 12: teleport.trust.v1.ListTrustedClustersResponse.trusted_clusters:type_name -> types.TrustedClusterV2
27, // 13: teleport.trust.v1.UpsertTunnelConnectionRequest.tunnel_connection:type_name -> types.TunnelConnectionV2
27, // 14: teleport.trust.v1.UpsertTunnelConnectionResponse.tunnel_connection:type_name -> types.TunnelConnectionV2
21, // 15: teleport.trust.v1.ListTunnelConnectionsRequest.filter:type_name -> teleport.trust.v1.ListTunnelConnectionsFilter
27, // 16: teleport.trust.v1.ListTunnelConnectionsResponse.tunnel_connections:type_name -> types.TunnelConnectionV2
3, // 17: teleport.trust.v1.TrustService.GetCertAuthority:input_type -> teleport.trust.v1.GetCertAuthorityRequest
4, // 18: teleport.trust.v1.TrustService.GetCertAuthorities:input_type -> teleport.trust.v1.GetCertAuthoritiesRequest
6, // 19: teleport.trust.v1.TrustService.DeleteCertAuthority:input_type -> teleport.trust.v1.DeleteCertAuthorityRequest
7, // 20: teleport.trust.v1.TrustService.UpsertCertAuthority:input_type -> teleport.trust.v1.UpsertCertAuthorityRequest
8, // 21: teleport.trust.v1.TrustService.RotateCertAuthority:input_type -> teleport.trust.v1.RotateCertAuthorityRequest
11, // 22: teleport.trust.v1.TrustService.RotateExternalCertAuthority:input_type -> teleport.trust.v1.RotateExternalCertAuthorityRequest
13, // 23: teleport.trust.v1.TrustService.GenerateHostCert:input_type -> teleport.trust.v1.GenerateHostCertRequest
0, // 24: teleport.trust.v1.TrustService.UpsertTrustedCluster:input_type -> teleport.trust.v1.UpsertTrustedClusterRequest
1, // 25: teleport.trust.v1.TrustService.CreateTrustedCluster:input_type -> teleport.trust.v1.CreateTrustedClusterRequest
2, // 26: teleport.trust.v1.TrustService.UpdateTrustedCluster:input_type -> teleport.trust.v1.UpdateTrustedClusterRequest
15, // 27: teleport.trust.v1.TrustService.ListTrustedClusters:input_type -> teleport.trust.v1.ListTrustedClustersRequest
17, // 28: teleport.trust.v1.TrustService.UpsertTunnelConnection:input_type -> teleport.trust.v1.UpsertTunnelConnectionRequest
19, // 29: teleport.trust.v1.TrustService.DeleteTunnelConnection:input_type -> teleport.trust.v1.DeleteTunnelConnectionRequest
20, // 30: teleport.trust.v1.TrustService.ListTunnelConnections:input_type -> teleport.trust.v1.ListTunnelConnectionsRequest
24, // 31: teleport.trust.v1.TrustService.GetCertAuthority:output_type -> types.CertAuthorityV2
5, // 32: teleport.trust.v1.TrustService.GetCertAuthorities:output_type -> teleport.trust.v1.GetCertAuthoritiesResponse
28, // 33: teleport.trust.v1.TrustService.DeleteCertAuthority:output_type -> google.protobuf.Empty
24, // 34: teleport.trust.v1.TrustService.UpsertCertAuthority:output_type -> types.CertAuthorityV2
10, // 35: teleport.trust.v1.TrustService.RotateCertAuthority:output_type -> teleport.trust.v1.RotateCertAuthorityResponse
12, // 36: teleport.trust.v1.TrustService.RotateExternalCertAuthority:output_type -> teleport.trust.v1.RotateExternalCertAuthorityResponse
14, // 37: teleport.trust.v1.TrustService.GenerateHostCert:output_type -> teleport.trust.v1.GenerateHostCertResponse
23, // 38: teleport.trust.v1.TrustService.UpsertTrustedCluster:output_type -> types.TrustedClusterV2
23, // 39: teleport.trust.v1.TrustService.CreateTrustedCluster:output_type -> types.TrustedClusterV2
23, // 40: teleport.trust.v1.TrustService.UpdateTrustedCluster:output_type -> types.TrustedClusterV2
16, // 41: teleport.trust.v1.TrustService.ListTrustedClusters:output_type -> teleport.trust.v1.ListTrustedClustersResponse
18, // 42: teleport.trust.v1.TrustService.UpsertTunnelConnection:output_type -> teleport.trust.v1.UpsertTunnelConnectionResponse
28, // 43: teleport.trust.v1.TrustService.DeleteTunnelConnection:output_type -> google.protobuf.Empty
22, // 44: teleport.trust.v1.TrustService.ListTunnelConnections:output_type -> teleport.trust.v1.ListTunnelConnectionsResponse
31, // [31:45] is the sub-list for method output_type
17, // [17:31] is the sub-list for method input_type
17, // [17:17] is the sub-list for extension type_name
17, // [17:17] is the sub-list for extension extendee
0, // [0:17] is the sub-list for field type_name
}
func init() { file_teleport_trust_v1_trust_service_proto_init() }
@@ -1812,7 +2068,7 @@ func file_teleport_trust_v1_trust_service_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_teleport_trust_v1_trust_service_proto_rawDesc), len(file_teleport_trust_v1_trust_service_proto_rawDesc)),
NumEnums: 0,
NumMessages: 20,
NumMessages: 23,
NumExtensions: 0,
NumServices: 1,
},
@@ -56,6 +56,9 @@ service TrustService {
// DeleteTunnelConnection removes a single tunnel connection record by
// cluster name and connection name.
rpc DeleteTunnelConnection(DeleteTunnelConnectionRequest) returns (google.protobuf.Empty);
// ListTunnelConnections returns a page of tunnel connection records,
// optionally filtered.
rpc ListTunnelConnections(ListTunnelConnectionsRequest) returns (ListTunnelConnectionsResponse);
}
// Request for UpsertTrustedCluster.
@@ -222,3 +225,30 @@ message DeleteTunnelConnectionRequest {
// ConnectionName is the name of the tunnel connection to delete.
string connection_name = 2;
}
// ListTunnelConnectionsRequest is the request for ListTunnelConnections.
message ListTunnelConnectionsRequest {
// The maximum number of items to return.
// The server may impose a different page size at its discretion.
int32 page_size = 1;
// The next_page_token value returned from a previous List request, if any.
string page_token = 2;
// Filter optionally narrows the returned tunnel connections.
ListTunnelConnectionsFilter filter = 3;
}
// ListTunnelConnectionsFilter narrows the results of ListTunnelConnections.
message ListTunnelConnectionsFilter {
// cluster_name, when set, limits results to tunnel connections for that
// cluster.
string cluster_name = 1;
}
// ListTunnelConnectionsResponse is the response for ListTunnelConnections.
message ListTunnelConnectionsResponse {
// TunnelConnections is a page of tunnel connection resources.
repeated types.TunnelConnectionV2 tunnel_connections = 1;
// Token to retrieve the next page of results, or empty if there are no
// more results in the list.
string next_page_token = 2;
}
+1 -1
View File
@@ -40,7 +40,7 @@ func WaitForTunnelConnections(t *testing.T, authServer *auth.Server, clusterName
var conns []types.TunnelConnection
for range 30 {
// to speed things up a bit, bypass the auth cache
conns, err := authServer.Services.GetTunnelConnections(clusterName)
conns, err := authServer.Services.GetTunnelConnections(t.Context(), clusterName)
require.NoError(t, err)
if len(conns) == expectedCount {
return
+1 -1
View File
@@ -315,7 +315,7 @@ func SetupTrustedCluster(ctx context.Context, t *testing.T, rootServer, leafServ
require.NoError(t, err)
require.EventuallyWithT(t, func(t *assert.CollectT) {
rt, err := rootServer.GetAuthServer().GetTunnelConnections(leafServer.Config.Auth.ClusterName.GetClusterName())
rt, err := rootServer.GetAuthServer().GetTunnelConnections(ctx, leafServer.Config.Auth.ClusterName.GetClusterName())
require.NoError(t, err)
require.Len(t, rt, 1)
}, time.Second*10, 200*time.Millisecond)
+10 -4
View File
@@ -142,7 +142,9 @@ func NewAPIServer(config *APIConfig) (http.Handler, error) {
srv.DELETE("/:version/proxies/:name", srv.WithAuth(srv.deleteProxy))
// TODO(strideynet): move to httpMigratedHandler in v20.0.0
srv.POST("/:version/tunnelconnections", srv.WithAuth(srv.upsertTunnelConnection))
// TODO(noah): move to httpMigratedHandler in v20.0.0
srv.GET("/:version/tunnelconnections/:cluster", srv.WithAuth(srv.getTunnelConnections))
// TODO(noah): move to httpMigratedHandler in v20.0.0
srv.GET("/:version/tunnelconnections", srv.WithAuth(srv.getAllTunnelConnections))
// TODO(strideynet): move to httpMigratedHandler in v20.0.0
srv.DELETE("/:version/tunnelconnections/:cluster/:conn", srv.WithAuth(srv.deleteTunnelConnection))
@@ -544,9 +546,11 @@ func (s *APIServer) upsertTunnelConnection(auth *ServerWithRoles, w http.Respons
return message("ok"), nil
}
// getTunnelConnections returns a list of tunnel connections from a cluster
// getTunnelConnections returns a list of tunnel connections from a cluster.
//
// TODO(noah): move to httpMigratedHandler in v20.0.0
func (s *APIServer) getTunnelConnections(auth *ServerWithRoles, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (any, error) {
conns, err := auth.GetTunnelConnections(p.ByName("cluster"))
conns, err := auth.GetTunnelConnections(r.Context(), p.ByName("cluster"))
if err != nil {
return nil, trace.Wrap(err)
}
@@ -561,9 +565,11 @@ func (s *APIServer) getTunnelConnections(auth *ServerWithRoles, w http.ResponseW
return items, nil
}
// getAllTunnelConnections returns a list of tunnel connections from a cluster
// getAllTunnelConnections returns a list of tunnel connections from a cluster.
//
// TODO(noah): move to httpMigratedHandler in v20.0.0
func (s *APIServer) getAllTunnelConnections(auth *ServerWithRoles, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (any, error) {
conns, err := auth.GetAllTunnelConnections()
conns, err := auth.GetAllTunnelConnections(r.Context())
if err != nil {
return nil, trace.Wrap(err)
}
+10 -4
View File
@@ -6004,18 +6004,24 @@ func (a *ServerWithRoles) UpsertTunnelConnection(ctx context.Context, conn types
return a.authServer.UpsertTunnelConnection(ctx, conn)
}
func (a *ServerWithRoles) GetTunnelConnections(clusterName string, opts ...services.MarshalOption) ([]types.TunnelConnection, error) {
// Deprecated: Prefer the [trustv1.Service.ListTunnelConnections] RPC.
//
// TODO(noah): DELETE IN v20.0.0
func (a *ServerWithRoles) GetTunnelConnections(ctx context.Context, clusterName string) ([]types.TunnelConnection, error) {
if err := a.authorizeAction(types.KindTunnelConnection, types.VerbList); err != nil {
return nil, trace.Wrap(err)
}
return a.authServer.GetTunnelConnections(clusterName, opts...)
return a.authServer.GetTunnelConnections(ctx, clusterName)
}
func (a *ServerWithRoles) GetAllTunnelConnections(opts ...services.MarshalOption) ([]types.TunnelConnection, error) {
// Deprecated: Prefer the [trustv1.Service.ListTunnelConnections] RPC.
//
// TODO(noah): DELETE IN v20.0.0
func (a *ServerWithRoles) GetAllTunnelConnections(ctx context.Context) ([]types.TunnelConnection, error) {
if err := a.authorizeAction(types.KindTunnelConnection, types.VerbList); err != nil {
return nil, trace.Wrap(err)
}
return a.authServer.GetAllTunnelConnections(opts...)
return a.authServer.GetAllTunnelConnections(ctx)
}
// Deprecated: Prefer the [trustv1.Service.DeleteTunnelConnection] RPC.
+10 -6
View File
@@ -41,6 +41,7 @@ import (
machineidv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1"
presencev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/presence/v1"
provisioningv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/provisioning/v1"
trustpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1"
userprovisioningpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2"
userspb "github.com/gravitational/teleport/api/gen/proto/go/teleport/users/v1"
usertasksv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/usertasks/v1"
@@ -253,10 +254,10 @@ type ReadProxyAccessPoint interface {
ListReverseTunnels(ctx context.Context, pageSize int, nextToken string) ([]types.ReverseTunnel, string, error)
// GetAllTunnelConnections returns all tunnel connections
GetAllTunnelConnections(opts ...services.MarshalOption) ([]types.TunnelConnection, error)
GetAllTunnelConnections(ctx context.Context) ([]types.TunnelConnection, error)
// GetTunnelConnections returns tunnel connections for a given cluster
GetTunnelConnections(clusterName string, opts ...services.MarshalOption) ([]types.TunnelConnection, error)
GetTunnelConnections(ctx context.Context, clusterName string) ([]types.TunnelConnection, error)
// GetApplicationServers returns all registered application servers.
GetApplicationServers(ctx context.Context, namespace string) ([]types.AppServer, error)
@@ -485,10 +486,10 @@ type ReadRemoteProxyAccessPoint interface {
ListAuthServers(ctx context.Context, pageSize int, nextToken string) ([]types.Server, string, error)
// GetAllTunnelConnections returns all tunnel connections
GetAllTunnelConnections(opts ...services.MarshalOption) ([]types.TunnelConnection, error)
GetAllTunnelConnections(ctx context.Context) ([]types.TunnelConnection, error)
// GetTunnelConnections returns tunnel connections for a given cluster
GetTunnelConnections(clusterName string, opts ...services.MarshalOption) ([]types.TunnelConnection, error)
GetTunnelConnections(ctx context.Context, clusterName string) ([]types.TunnelConnection, error)
// GetApplicationServers returns all registered application servers.
GetApplicationServers(ctx context.Context, namespace string) ([]types.AppServer, error)
@@ -1247,10 +1248,13 @@ type Cache interface {
ListRoles(ctx context.Context, req *proto.ListRolesRequest) (*proto.ListRolesResponse, error)
// GetAllTunnelConnections returns all tunnel connections
GetAllTunnelConnections(opts ...services.MarshalOption) ([]types.TunnelConnection, error)
GetAllTunnelConnections(ctx context.Context) ([]types.TunnelConnection, error)
// GetTunnelConnections returns tunnel connections for a given cluster
GetTunnelConnections(clusterName string, opts ...services.MarshalOption) ([]types.TunnelConnection, error)
GetTunnelConnections(ctx context.Context, clusterName string) ([]types.TunnelConnection, error)
// ListTunnelConnections returns a page of tunnel connections matching the given filter.
ListTunnelConnections(ctx context.Context, pageSize int, pageToken string, filter *trustpb.ListTunnelConnectionsFilter) ([]types.TunnelConnection, string, error)
// GetApps returns all application resources.
GetApps(ctx context.Context) ([]types.Application, error)
-45
View File
@@ -315,51 +315,6 @@ func (c *HTTPClient) Delete(ctx context.Context, u string) (*roundtrip.Response,
return httplib.ConvertResponse(c.Client.Delete(ctx, u))
}
// GetTunnelConnections returns tunnel connections for a given cluster
func (c *HTTPClient) GetTunnelConnections(clusterName string, opts ...services.MarshalOption) ([]types.TunnelConnection, error) {
if clusterName == "" {
return nil, trace.BadParameter("missing cluster name parameter")
}
out, err := c.Get(context.TODO(), c.Endpoint("tunnelconnections", clusterName), url.Values{})
if err != nil {
return nil, trace.Wrap(err)
}
var items []json.RawMessage
if err := json.Unmarshal(out.Bytes(), &items); err != nil {
return nil, trace.Wrap(err)
}
conns := make([]types.TunnelConnection, len(items))
for i, raw := range items {
conn, err := services.UnmarshalTunnelConnection(raw)
if err != nil {
return nil, trace.Wrap(err)
}
conns[i] = conn
}
return conns, nil
}
// GetAllTunnelConnections returns all tunnel connections
func (c *HTTPClient) GetAllTunnelConnections(opts ...services.MarshalOption) ([]types.TunnelConnection, error) {
out, err := c.Get(context.TODO(), c.Endpoint("tunnelconnections"), url.Values{})
if err != nil {
return nil, trace.Wrap(err)
}
var items []json.RawMessage
if err := json.Unmarshal(out.Bytes(), &items); err != nil {
return nil, trace.Wrap(err)
}
conns := make([]types.TunnelConnection, len(items))
for i, raw := range items {
conn, err := services.UnmarshalTunnelConnection(raw)
if err != nil {
return nil, trace.Wrap(err)
}
conns[i] = conn
}
return conns, nil
}
type upsertServerRawReq struct {
Server json.RawMessage `json:"server"`
TTL time.Duration `json:"ttl"`
+95
View File
@@ -28,6 +28,7 @@ import (
presencev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/presence/v1"
trustpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/utils/clientutils"
"github.com/gravitational/teleport/lib/services"
)
@@ -141,6 +142,100 @@ func (c *HTTPClient) deleteTunnelConnection(ctx context.Context, clusterName, co
return trace.Wrap(err)
}
// GetTunnelConnections returns all tunnel connections for a given cluster.
//
// TODO(noah): DELETE IN 20.0.0 — inline the gRPC page-loop directly once the
// HTTP fallback is removed; keep the method signature.
func (c *Client) GetTunnelConnections(ctx context.Context, clusterName string) ([]types.TunnelConnection, error) {
if clusterName == "" {
return nil, trace.BadParameter("missing cluster name parameter")
}
return c.listAllTunnelConnections(ctx, clusterName)
}
// GetAllTunnelConnections returns all tunnel connections across all clusters.
//
// TODO(noah): DELETE IN 20.0.0
func (c *Client) GetAllTunnelConnections(ctx context.Context) ([]types.TunnelConnection, error) {
return c.listAllTunnelConnections(ctx, "")
}
// TODO(noah): DELETE IN 20.0.0
func (c *Client) listAllTunnelConnections(ctx context.Context, clusterName string) ([]types.TunnelConnection, error) {
var filter *trustpb.ListTunnelConnectionsFilter
if clusterName != "" {
filter = &trustpb.ListTunnelConnectionsFilter{ClusterName: clusterName}
}
items, err := clientutils.CollectWithFallback(
ctx,
func(
ctx context.Context, pageSize int, pageToken string,
) ([]types.TunnelConnection, string, error) {
return c.APIClient.ListTunnelConnections(ctx, pageSize, pageToken, filter)
},
func(ctx context.Context) ([]types.TunnelConnection, error) {
if clusterName != "" {
return c.HTTPClient.getTunnelConnectionsLegacy(ctx, clusterName)
}
return c.HTTPClient.getAllTunnelConnectionsLegacy(ctx)
},
)
if err != nil {
return nil, trace.Wrap(err)
}
return items, nil
}
// getTunnelConnectionsLegacy returns tunnel connections for a given cluster.
//
// TODO(noah): DELETE IN 20.0.0
func (c *HTTPClient) getTunnelConnectionsLegacy(ctx context.Context, clusterName string) ([]types.TunnelConnection, error) {
if clusterName == "" {
return nil, trace.BadParameter("missing cluster name parameter")
}
out, err := c.Get(ctx, c.Endpoint("tunnelconnections", clusterName), url.Values{})
if err != nil {
return nil, trace.Wrap(err)
}
var items []json.RawMessage
if err := json.Unmarshal(out.Bytes(), &items); err != nil {
return nil, trace.Wrap(err)
}
conns := make([]types.TunnelConnection, len(items))
for i, raw := range items {
conn, err := services.UnmarshalTunnelConnection(raw)
if err != nil {
return nil, trace.Wrap(err)
}
conns[i] = conn
}
return conns, nil
}
// getAllTunnelConnectionsLegacy returns all tunnel connections.
//
// TODO(noah): DELETE IN 20.0.0
func (c *HTTPClient) getAllTunnelConnectionsLegacy(ctx context.Context) ([]types.TunnelConnection, error) {
out, err := c.Get(ctx, c.Endpoint("tunnelconnections"), url.Values{})
if err != nil {
return nil, trace.Wrap(err)
}
var items []json.RawMessage
if err := json.Unmarshal(out.Bytes(), &items); err != nil {
return nil, trace.Wrap(err)
}
conns := make([]types.TunnelConnection, len(items))
for i, raw := range items {
conn, err := services.UnmarshalTunnelConnection(raw)
if err != nil {
return nil, trace.Wrap(err)
}
conns[i] = conn
}
return conns, nil
}
// GetAuthServers returns the list of auth servers registered in the cluster.
//
// Deprecated: Prefer paginated variant [APIClient.ListAuthServers].
+54 -10
View File
@@ -1619,7 +1619,7 @@ func TestTunnelConnectionsCRUD(t *testing.T) {
require.NoError(t, err)
clusterName := "example.com"
out, err := clt.GetTunnelConnections(clusterName)
out, err := clt.GetTunnelConnections(ctx, clusterName)
require.NoError(t, err)
require.Empty(t, out)
@@ -1634,12 +1634,12 @@ func TestTunnelConnectionsCRUD(t *testing.T) {
err = clt.UpsertTunnelConnection(ctx, conn)
require.NoError(t, err)
out, err = clt.GetTunnelConnections(clusterName)
out, err = clt.GetTunnelConnections(ctx, clusterName)
require.NoError(t, err)
require.Len(t, out, 1)
require.Empty(t, cmp.Diff(out[0], conn, cmpopts.IgnoreFields(types.Metadata{}, "Revision")))
out, err = clt.GetAllTunnelConnections()
out, err = clt.GetAllTunnelConnections(ctx)
require.NoError(t, err)
require.Len(t, out, 1)
require.Empty(t, cmp.Diff(out[0], conn, cmpopts.IgnoreFields(types.Metadata{}, "Revision")))
@@ -1650,13 +1650,13 @@ func TestTunnelConnectionsCRUD(t *testing.T) {
err = clt.UpsertTunnelConnection(ctx, conn)
require.NoError(t, err)
out, err = clt.GetTunnelConnections(clusterName)
out, err = clt.GetTunnelConnections(ctx, clusterName)
require.NoError(t, err)
require.Len(t, out, 1)
require.Empty(t, cmp.Diff(out[0], conn, cmpopts.IgnoreFields(types.Metadata{}, "Revision")))
// Delete all to reset test environment
out, err = clt.GetAllTunnelConnections()
out, err = clt.GetAllTunnelConnections(ctx)
require.NoError(t, err)
for _, tc := range out {
err := testSrv.Auth().DeleteTunnelConnection(ctx, tc.GetClusterName(), tc.GetName())
@@ -1667,7 +1667,7 @@ func TestTunnelConnectionsCRUD(t *testing.T) {
err = clt.UpsertTunnelConnection(ctx, conn)
require.NoError(t, err)
out, err = clt.GetTunnelConnections(clusterName)
out, err = clt.GetTunnelConnections(ctx, clusterName)
require.NoError(t, err)
require.Len(t, out, 1)
require.Empty(t, cmp.Diff(out[0], conn, cmpopts.IgnoreFields(types.Metadata{}, "Revision")))
@@ -1675,9 +1675,32 @@ func TestTunnelConnectionsCRUD(t *testing.T) {
err = clt.DeleteTunnelConnection(ctx, clusterName, conn.GetName())
require.NoError(t, err)
out, err = clt.GetTunnelConnections(clusterName)
out, err = clt.GetTunnelConnections(ctx, clusterName)
require.NoError(t, err)
require.Empty(t, out)
// Exercise the direct gRPC ListTunnelConnections RPC, including the filter.
for i := 0; i < 3; i++ {
c, err := types.NewTunnelConnection(fmt.Sprintf("grpc-conn-%d", i), types.TunnelConnectionSpecV2{
ClusterName: clusterName,
ProxyName: fmt.Sprintf("p%d", i),
LastHeartbeat: dt,
})
require.NoError(t, err)
require.NoError(t, clt.UpsertTunnelConnection(ctx, c))
}
resp, err := clt.TrustClient().ListTunnelConnections(ctx, &trustpb.ListTunnelConnectionsRequest{
Filter: &trustpb.ListTunnelConnectionsFilter{ClusterName: clusterName},
})
require.NoError(t, err)
require.Len(t, resp.GetTunnelConnections(), 3)
resp, err = clt.TrustClient().ListTunnelConnections(ctx, &trustpb.ListTunnelConnectionsRequest{
Filter: &trustpb.ListTunnelConnectionsFilter{ClusterName: "other.example.com"},
})
require.NoError(t, err)
require.Empty(t, resp.GetTunnelConnections())
}
// TestTunnelConnectionsLegacyHTTP exercises the legacy HTTP handlers for
@@ -1708,15 +1731,36 @@ func TestTunnelConnectionsLegacyHTTP(t *testing.T) {
}{TunnelConnection: data})
require.NoError(t, err)
stored, err := clt.GetTunnelConnections(clusterName)
stored, err := clt.GetTunnelConnections(ctx, clusterName)
require.NoError(t, err)
require.Len(t, stored, 1)
require.Equal(t, conn.GetName(), stored[0].GetName())
// Exercise the legacy HTTP GET endpoints directly, so they stay covered
// during the v19→v20 fallback window.
readFromHTTP := func(path ...string) []types.TunnelConnection {
out, err := clt.HTTPClient.Get(ctx, clt.HTTPClient.Endpoint(path...), url.Values{})
require.NoError(t, err)
var items []json.RawMessage
require.NoError(t, json.Unmarshal(out.Bytes(), &items))
result := make([]types.TunnelConnection, len(items))
for i, raw := range items {
c, err := services.UnmarshalTunnelConnection(raw)
require.NoError(t, err)
result[i] = c
}
return result
}
byCluster := readFromHTTP("tunnelconnections", clusterName)
require.Len(t, byCluster, 1)
require.Equal(t, conn.GetName(), byCluster[0].GetName())
all := readFromHTTP("tunnelconnections")
require.Len(t, all, 1)
_, err = clt.HTTPClient.Delete(ctx, clt.HTTPClient.Endpoint("tunnelconnections", clusterName, conn.GetName()))
require.NoError(t, err)
stored, err = clt.GetTunnelConnections(clusterName)
stored, err = clt.GetTunnelConnections(ctx, clusterName)
require.NoError(t, err)
require.Empty(t, stored)
}
@@ -5042,7 +5086,7 @@ func TestEvents(t *testing.T) {
err = testSrv.Auth().UpsertTunnelConnection(ctx, conn)
require.NoError(t, err)
out, err := testSrv.Auth().GetTunnelConnections("example.com")
out, err := testSrv.Auth().GetTunnelConnections(ctx, "example.com")
require.NoError(t, err)
err = testSrv.Auth().DeleteTunnelConnection(ctx, conn.GetClusterName(), conn.GetName())
+10 -2
View File
@@ -64,12 +64,20 @@ type authServer interface {
ListTrustedClusters(ctx context.Context, limit int, startKey string) ([]types.TrustedCluster, string, error)
}
// cacheReader is the subset of cache reads used by the trust gRPC service.
type cacheReader interface {
services.AuthorityGetter
// ListTunnelConnections returns a page of tunnel connections matching the
// given filter.
ListTunnelConnections(ctx context.Context, pageSize int, pageToken string, filter *trustpb.ListTunnelConnectionsFilter) ([]types.TunnelConnection, string, error)
}
// ServiceConfig holds configuration options for
// the trust gRPC service.
type ServiceConfig struct {
Authorizer authz.Authorizer
ScopedAuthorizer authz.ScopedAuthorizer
Cache services.AuthorityGetter
Cache cacheReader
Backend services.TrustInternal
AuthServer authServer
Modules modules.Modules
@@ -80,7 +88,7 @@ type Service struct {
trustpb.UnimplementedTrustServiceServer
authorizer authz.Authorizer
scopedAuthorizer authz.ScopedAuthorizer
cache services.AuthorityGetter
cache cacheReader
backend services.TrustInternal
authServer authServer
modules modules.Modules
@@ -88,3 +88,33 @@ func (s *Service) DeleteTunnelConnection(ctx context.Context, req *trustpb.Delet
return &emptypb.Empty{}, nil
}
// ListTunnelConnections returns a page of tunnel connection resources,
// optionally filtered by cluster name.
func (s *Service) ListTunnelConnections(ctx context.Context, req *trustpb.ListTunnelConnectionsRequest) (*trustpb.ListTunnelConnectionsResponse, error) {
authCtx, err := s.authorizer.Authorize(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
if err := authCtx.CheckAccessToKind(types.KindTunnelConnection, types.VerbList, types.VerbRead); err != nil {
return nil, trace.Wrap(err)
}
conns, next, err := s.cache.ListTunnelConnections(ctx, int(req.GetPageSize()), req.GetPageToken(), req.GetFilter())
if err != nil {
return nil, trace.Wrap(err)
}
tcs := make([]*types.TunnelConnectionV2, 0, len(conns))
for _, c := range conns {
v2, ok := c.(*types.TunnelConnectionV2)
if !ok {
return nil, trace.Errorf("unexpected TunnelConnection type: %T", c)
}
tcs = append(tcs, v2)
}
return trustpb.ListTunnelConnectionsResponse_builder{
TunnelConnections: tcs,
NextPageToken: next,
}.Build(), nil
}
+165 -2
View File
@@ -19,6 +19,7 @@
package trustv1
import (
"fmt"
"testing"
"time"
@@ -116,7 +117,7 @@ func TestUpsertTunnelConnection(t *testing.T) {
require.NotEmpty(t, resp.GetTunnelConnection().GetRevision(), "response should carry the backend-assigned revision")
require.Equal(t, req.GetTunnelConnection(), resp.GetTunnelConnection())
stored, err := trust.GetTunnelConnections(req.GetTunnelConnection().GetClusterName())
stored, err := trust.GetTunnelConnections(ctx, req.GetTunnelConnection().GetClusterName())
require.NoError(t, err)
require.Len(t, stored, 1)
require.Equal(t, req.GetTunnelConnection().GetName(), stored[0].GetName())
@@ -203,7 +204,7 @@ func TestDeleteTunnelConnection(t *testing.T) {
_, err = service.DeleteTunnelConnection(ctx, test.req)
test.assertErr(t, err)
remaining, listErr := trust.GetTunnelConnections(clusterName)
remaining, listErr := trust.GetTunnelConnections(ctx, clusterName)
require.NoError(t, listErr)
if test.wantGone {
require.Empty(t, remaining)
@@ -213,3 +214,165 @@ func TestDeleteTunnelConnection(t *testing.T) {
})
}
}
func TestListTunnelConnections(t *testing.T) {
t.Parallel()
ctx := t.Context()
const leaf1 = "leaf-1.example.com"
const leaf2 = "leaf-2.example.com"
seed := func(t *testing.T, trust *local.CA) {
t.Helper()
fixtures := []struct {
cluster, name, proxy string
}{
{leaf1, "conn-a", "proxy-1"},
{leaf1, "conn-b", "proxy-2"},
{leaf2, "conn-a", "proxy-3"},
}
for _, f := range fixtures {
conn, err := types.NewTunnelConnection(f.name, types.TunnelConnectionSpecV2{
ClusterName: f.cluster,
ProxyName: f.proxy,
LastHeartbeat: time.Now().UTC(),
Type: types.ProxyTunnel,
})
require.NoError(t, err)
require.NoError(t, trust.UpsertTunnelConnection(ctx, conn))
}
}
type want struct {
clusters []string
names []string
}
tests := []struct {
name string
req *trustpb.ListTunnelConnectionsRequest
allow map[check]bool
assertErr require.ErrorAssertionFunc
want want
}{
{
name: "success no filter",
req: &trustpb.ListTunnelConnectionsRequest{},
allow: map[check]bool{{types.KindTunnelConnection, types.VerbList}: true, {types.KindTunnelConnection, types.VerbRead}: true},
assertErr: require.NoError,
want: want{
clusters: []string{leaf1, leaf1, leaf2},
names: []string{"conn-a", "conn-b", "conn-a"},
},
},
{
name: "success filter by cluster",
req: &trustpb.ListTunnelConnectionsRequest{
Filter: &trustpb.ListTunnelConnectionsFilter{ClusterName: leaf1},
},
allow: map[check]bool{{types.KindTunnelConnection, types.VerbList}: true, {types.KindTunnelConnection, types.VerbRead}: true},
assertErr: require.NoError,
want: want{
clusters: []string{leaf1, leaf1},
names: []string{"conn-a", "conn-b"},
},
},
{
name: "success filter unknown cluster returns empty",
req: &trustpb.ListTunnelConnectionsRequest{
Filter: &trustpb.ListTunnelConnectionsFilter{ClusterName: "nonexistent"},
},
allow: map[check]bool{{types.KindTunnelConnection, types.VerbList}: true, {types.KindTunnelConnection, types.VerbRead}: true},
assertErr: require.NoError,
},
{
name: "access denied",
req: &trustpb.ListTunnelConnectionsRequest{},
allow: map[check]bool{{types.KindTunnelConnection, types.VerbList}: false},
assertErr: func(t require.TestingT, err error, _ ...any) { require.True(t, trace.IsAccessDenied(err)) },
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
p := newTestPack(t)
trust := local.NewCAService(p.mem)
seed(t, trust)
authorizer := &fakeAuthorizer{checker: &fakeChecker{allow: test.allow}}
service, err := NewService(&ServiceConfig{
Cache: trust,
Backend: trust,
Authorizer: authorizer,
ScopedAuthorizer: authorizer,
AuthServer: &fakeAuthServer{},
Modules: modulestest.OSSModules(),
})
require.NoError(t, err)
resp, err := service.ListTunnelConnections(ctx, test.req)
test.assertErr(t, err)
if err != nil {
return
}
var gotClusters, gotNames []string
for _, c := range resp.GetTunnelConnections() {
gotClusters = append(gotClusters, c.GetClusterName())
gotNames = append(gotNames, c.GetName())
}
require.Equal(t, test.want.clusters, gotClusters)
require.Equal(t, test.want.names, gotNames)
})
}
}
func TestListTunnelConnections_Pagination(t *testing.T) {
t.Parallel()
ctx := t.Context()
const cluster = "leaf.example.com"
p := newTestPack(t)
trust := local.NewCAService(p.mem)
for i := 0; i < 5; i++ {
conn, err := types.NewTunnelConnection(fmt.Sprintf("conn-%d", i), types.TunnelConnectionSpecV2{
ClusterName: cluster,
ProxyName: fmt.Sprintf("proxy-%d", i),
LastHeartbeat: time.Now().UTC(),
Type: types.ProxyTunnel,
})
require.NoError(t, err)
require.NoError(t, trust.UpsertTunnelConnection(ctx, conn))
}
authorizer := &fakeAuthorizer{checker: &fakeChecker{allow: map[check]bool{
{types.KindTunnelConnection, types.VerbList}: true,
{types.KindTunnelConnection, types.VerbRead}: true,
}}}
service, err := NewService(&ServiceConfig{
Cache: trust,
Backend: trust,
Authorizer: authorizer,
ScopedAuthorizer: authorizer,
AuthServer: &fakeAuthServer{},
Modules: modulestest.OSSModules(),
})
require.NoError(t, err)
var gotNames []string
var pageToken string
for {
resp, err := service.ListTunnelConnections(ctx, &trustpb.ListTunnelConnectionsRequest{
PageSize: 2,
PageToken: pageToken,
})
require.NoError(t, err)
for _, c := range resp.GetTunnelConnections() {
gotNames = append(gotNames, c.GetName())
}
if resp.GetNextPageToken() == "" {
break
}
pageToken = resp.GetNextPageToken()
}
require.Equal(t, []string{"conn-0", "conn-1", "conn-2", "conn-3", "conn-4"}, gotNames)
}
+1 -1
View File
@@ -468,7 +468,7 @@ func (a *Server) updateRemoteClusterStatus(ctx context.Context, netConfig types.
keepAliveInterval := netConfig.GetKeepAliveInterval()
// fetch tunnel connections for the cluster to update runtime status
connections, err := a.GetTunnelConnections(remoteCluster.GetName())
connections, err := a.GetTunnelConnections(ctx, remoteCluster.GetName())
if err != nil {
return false, trace.Wrap(err)
}
+40 -7
View File
@@ -21,6 +21,7 @@ import (
"github.com/gravitational/trace"
trustpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/utils/clientutils"
"github.com/gravitational/teleport/lib/itertools/stream"
@@ -48,7 +49,7 @@ func newTunnelConnectionCollection(upstream services.Trust, w types.WatchKind) (
},
}),
fetcher: func(ctx context.Context, loadSecrets bool) ([]types.TunnelConnection, error) {
out, err := upstream.GetAllTunnelConnections()
out, err := upstream.GetAllTunnelConnections(ctx)
return out, trace.Wrap(err)
},
headerTransform: func(hdr *types.ResourceHeader) types.TunnelConnection {
@@ -68,8 +69,8 @@ func newTunnelConnectionCollection(upstream services.Trust, w types.WatchKind) (
}
// GetTunnelConnections is a part of auth.Cache implementation
func (c *Cache) GetTunnelConnections(clusterName string, opts ...services.MarshalOption) ([]types.TunnelConnection, error) {
_, span := c.Tracer.Start(context.TODO(), "cache/GetTunnelConnections")
func (c *Cache) GetTunnelConnections(ctx context.Context, clusterName string) ([]types.TunnelConnection, error) {
ctx, span := c.Tracer.Start(ctx, "cache/GetTunnelConnections")
defer span.End()
rg, err := acquireReadGuard(c, c.collections.tunnelConnections)
@@ -79,7 +80,7 @@ func (c *Cache) GetTunnelConnections(clusterName string, opts ...services.Marsha
defer rg.Release()
if !rg.ReadCache() {
tunnels, err := c.Config.Trust.GetTunnelConnections(clusterName, opts...)
tunnels, err := c.Config.Trust.GetTunnelConnections(ctx, clusterName)
return tunnels, trace.Wrap(err)
}
@@ -94,8 +95,8 @@ func (c *Cache) GetTunnelConnections(clusterName string, opts ...services.Marsha
}
// GetAllTunnelConnections is a part of auth.Cache implementation
func (c *Cache) GetAllTunnelConnections(opts ...services.MarshalOption) (conns []types.TunnelConnection, err error) {
_, span := c.Tracer.Start(context.TODO(), "cache/GetAllTunnelConnections")
func (c *Cache) GetAllTunnelConnections(ctx context.Context) (conns []types.TunnelConnection, err error) {
ctx, span := c.Tracer.Start(ctx, "cache/GetAllTunnelConnections")
defer span.End()
rg, err := acquireReadGuard(c, c.collections.tunnelConnections)
@@ -105,7 +106,7 @@ func (c *Cache) GetAllTunnelConnections(opts ...services.MarshalOption) (conns [
defer rg.Release()
if !rg.ReadCache() {
tunnels, err := c.Config.Trust.GetAllTunnelConnections(opts...)
tunnels, err := c.Config.Trust.GetAllTunnelConnections(ctx)
return tunnels, trace.Wrap(err)
}
@@ -117,6 +118,38 @@ func (c *Cache) GetAllTunnelConnections(opts ...services.MarshalOption) (conns [
return tunnels, nil
}
// ListTunnelConnections returns a page of tunnel connections matching the
// given filter.
func (c *Cache) ListTunnelConnections(ctx context.Context, pageSize int, pageToken string, filter *trustpb.ListTunnelConnectionsFilter) ([]types.TunnelConnection, string, error) {
ctx, span := c.Tracer.Start(ctx, "cache/ListTunnelConnections")
defer span.End()
lister := genericLister[types.TunnelConnection, tunnelConnectionIndex]{
cache: c,
collection: c.collections.tunnelConnections,
index: tunnelConnectionNameIndex,
upstreamList: func(ctx context.Context, pageSize int, pageToken string) ([]types.TunnelConnection, string, error) {
return c.Config.Trust.ListTunnelConnections(ctx, pageSize, pageToken, filter)
},
nextToken: func(tc types.TunnelConnection) string {
return tc.GetClusterName() + "/" + tc.GetName()
},
}
if clusterName := filter.GetClusterName(); clusterName != "" {
startToken := clusterName + "/"
if pageToken != "" {
startToken = pageToken
}
endToken := sortcache.NextKey(clusterName + "/")
out, next, err := lister.listRange(ctx, pageSize, startToken, endToken)
return out, next, trace.Wrap(err)
}
out, next, err := lister.list(ctx, pageSize, pageToken)
return out, next, trace.Wrap(err)
}
type remoteClusterIndex string
const remoteClusterNameIndex remoteClusterIndex = "name"
+82 -6
View File
@@ -25,6 +25,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
trustpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1"
"github.com/gravitational/teleport/api/types"
)
@@ -100,11 +101,11 @@ func TestTunnelConnections(t *testing.T) {
})
},
create: p.trustS.UpsertTunnelConnection,
list: getAllAdapter(func(ctx context.Context) ([]types.TunnelConnection, error) { return p.trustS.GetAllTunnelConnections() }),
cacheList: getAllAdapter(func(ctx context.Context) ([]types.TunnelConnection, error) { return p.cache.GetAllTunnelConnections() }),
list: getAllAdapter(p.trustS.GetAllTunnelConnections),
cacheList: getAllAdapter(p.cache.GetAllTunnelConnections),
update: p.trustS.UpsertTunnelConnection,
deleteAll: func(ctx context.Context) error {
all, err := p.trustS.GetAllTunnelConnections()
all, err := p.trustS.GetAllTunnelConnections(ctx)
if err != nil {
return err
}
@@ -140,17 +141,92 @@ func TestTunnelConnections(t *testing.T) {
}
require.EventuallyWithT(t, func(tt *assert.CollectT) {
tunnels, err := p.cache.GetAllTunnelConnections()
tunnels, err := p.cache.GetAllTunnelConnections(t.Context())
assert.NoError(tt, err)
assert.Len(tt, tunnels, 20)
}, 15*time.Second, 100*time.Millisecond)
tunnels, err := p.cache.GetTunnelConnections(clusterName)
tunnels, err := p.cache.GetTunnelConnections(t.Context(), clusterName)
require.NoError(t, err)
require.Len(t, tunnels, 17)
tunnels, err = p.cache.GetTunnelConnections("other-cluster")
tunnels, err = p.cache.GetTunnelConnections(t.Context(), "other-cluster")
require.NoError(t, err)
require.Len(t, tunnels, 3)
// TODO(noah): In v20, we'll be able to strip out the GetTunnelConnections/
// GetAllTunnelConnections implementation, and we can roll testing of
// ListTunnelConnections into testResources instead. For now, this is here
// so that we're still covering Get/GetAll but also covering
// ListTunnelConnections.
t.Run("ListTunnelConnections", func(t *testing.T) {
ctx := t.Context()
// Unfiltered list should page through all 20 tunnel connections.
var all []types.TunnelConnection
var pageToken string
for {
page, next, err := p.cache.ListTunnelConnections(ctx, 0, pageToken, nil)
require.NoError(t, err)
all = append(all, page...)
if next == "" {
break
}
pageToken = next
}
require.Len(t, all, 20)
// Filter by cluster name should only return matching tunnel connections.
filtered, next, err := p.cache.ListTunnelConnections(ctx, 0, "", &trustpb.ListTunnelConnectionsFilter{
ClusterName: clusterName,
})
require.NoError(t, err)
require.Empty(t, next)
require.Len(t, filtered, 17)
for _, tc := range filtered {
require.Equal(t, clusterName, tc.GetClusterName())
}
filtered, next, err = p.cache.ListTunnelConnections(ctx, 0, "", &trustpb.ListTunnelConnectionsFilter{
ClusterName: "other-cluster",
})
require.NoError(t, err)
require.Empty(t, next)
require.Len(t, filtered, 3)
for _, tc := range filtered {
require.Equal(t, "other-cluster", tc.GetClusterName())
}
// Filter for a cluster with no tunnel connections.
filtered, next, err = p.cache.ListTunnelConnections(ctx, 0, "", &trustpb.ListTunnelConnectionsFilter{
ClusterName: "does-not-exist",
})
require.NoError(t, err)
require.Empty(t, next)
require.Empty(t, filtered)
// Paginate with a small page size and a cluster filter.
var paginated []types.TunnelConnection
pageToken = ""
pages := 0
for {
page, next, err := p.cache.ListTunnelConnections(ctx, 5, pageToken, &trustpb.ListTunnelConnectionsFilter{
ClusterName: clusterName,
})
require.NoError(t, err)
require.LessOrEqual(t, len(page), 5)
pages++
paginated = append(paginated, page...)
if next == "" {
break
}
pageToken = next
}
require.Len(t, paginated, 17)
require.Greater(t, pages, 1, "expected multiple pages with page size 5 and 17 items")
for _, tc := range paginated {
require.Equal(t, clusterName, tc.GetClusterName())
}
})
}
+4 -4
View File
@@ -456,7 +456,7 @@ func (s *server) periodicFunctions() {
ticker := time.NewTicker(defaults.ResyncInterval)
defer ticker.Stop()
if err := s.fetchExpectedLeafClusters(); err != nil {
if err := s.fetchExpectedLeafClusters(s.ctx); err != nil {
s.logger.WarnContext(s.Context, "Failed to fetch expected leaf cluster", "error", err)
}
for {
@@ -465,7 +465,7 @@ func (s *server) periodicFunctions() {
s.logger.DebugContext(s.ctx, "Closing")
return
case <-ticker.C:
if err := s.fetchExpectedLeafClusters(); err != nil {
if err := s.fetchExpectedLeafClusters(s.ctx); err != nil {
s.logger.WarnContext(s.ctx, "Failed to fetch expected leaf clusters", "error", err)
}
@@ -494,8 +494,8 @@ func (s *server) periodicFunctions() {
// what was found in the previous iteration and updates the in-memory cluster
// placeholders. This map is used later by Cluster(s) to return either local or
// leaf cluster, or if no match, a placeholder.
func (s *server) fetchExpectedLeafClusters() error {
conns, err := s.LocalAccessPoint.GetAllTunnelConnections()
func (s *server) fetchExpectedLeafClusters(ctx context.Context) error {
conns, err := s.LocalAccessPoint.GetAllTunnelConnections(ctx)
if err != nil {
return trace.Wrap(err)
}
+8 -8
View File
@@ -1223,7 +1223,7 @@ func (s *ServicesTestSuite) OIDCPagination(t *testing.T) {
func (s *ServicesTestSuite) TunnelConnectionsCRUD(t *testing.T) {
ctx := t.Context()
clusterName := "example.com"
out, err := s.TrustS.GetTunnelConnections(clusterName)
out, err := s.TrustS.GetTunnelConnections(ctx, clusterName)
require.NoError(t, err)
require.Empty(t, out)
@@ -1238,12 +1238,12 @@ func (s *ServicesTestSuite) TunnelConnectionsCRUD(t *testing.T) {
err = s.TrustS.UpsertTunnelConnection(ctx, conn)
require.NoError(t, err)
out, err = s.TrustS.GetTunnelConnections(clusterName)
out, err = s.TrustS.GetTunnelConnections(ctx, clusterName)
require.NoError(t, err)
require.Len(t, out, 1)
require.Empty(t, cmp.Diff(out[0], conn, cmpopts.IgnoreFields(types.Metadata{}, "Revision")))
out, err = s.TrustS.GetAllTunnelConnections()
out, err = s.TrustS.GetAllTunnelConnections(ctx)
require.NoError(t, err)
require.Len(t, out, 1)
require.Empty(t, cmp.Diff(out[0], conn, cmpopts.IgnoreFields(types.Metadata{}, "Revision")))
@@ -1254,12 +1254,12 @@ func (s *ServicesTestSuite) TunnelConnectionsCRUD(t *testing.T) {
err = s.TrustS.UpsertTunnelConnection(ctx, conn)
require.NoError(t, err)
out, err = s.TrustS.GetTunnelConnections(clusterName)
out, err = s.TrustS.GetTunnelConnections(ctx, clusterName)
require.NoError(t, err)
require.Len(t, out, 1)
require.Empty(t, cmp.Diff(out[0], conn, cmpopts.IgnoreFields(types.Metadata{}, "Revision")))
out, err = s.TrustS.GetAllTunnelConnections()
out, err = s.TrustS.GetAllTunnelConnections(ctx)
require.NoError(t, err)
for _, tc := range out {
err = s.TrustS.DeleteTunnelConnection(ctx, tc.GetClusterName(), tc.GetName())
@@ -1270,7 +1270,7 @@ func (s *ServicesTestSuite) TunnelConnectionsCRUD(t *testing.T) {
err = s.TrustS.UpsertTunnelConnection(ctx, conn)
require.NoError(t, err)
out, err = s.TrustS.GetTunnelConnections(clusterName)
out, err = s.TrustS.GetTunnelConnections(ctx, clusterName)
require.NoError(t, err)
require.Len(t, out, 1)
require.Empty(t, cmp.Diff(out[0], conn, cmpopts.IgnoreFields(types.Metadata{}, "Revision")))
@@ -1278,7 +1278,7 @@ func (s *ServicesTestSuite) TunnelConnectionsCRUD(t *testing.T) {
err = s.TrustS.DeleteTunnelConnection(ctx, clusterName, conn.GetName())
require.NoError(t, err)
out, err = s.TrustS.GetTunnelConnections(clusterName)
out, err = s.TrustS.GetTunnelConnections(ctx, clusterName)
require.NoError(t, err)
require.Empty(t, out)
}
@@ -2252,7 +2252,7 @@ func (s *ServicesTestSuite) Events(t *testing.T) {
err = s.TrustS.UpsertTunnelConnection(ctx, conn)
require.NoError(t, err)
out, err := s.TrustS.GetTunnelConnections("example.com")
out, err := s.TrustS.GetTunnelConnections(ctx, "example.com")
require.NoError(t, err)
err = s.TrustS.DeleteTunnelConnection(ctx, conn.GetClusterName(), conn.GetName())
+50 -32
View File
@@ -30,6 +30,7 @@ import (
"github.com/gravitational/trace"
"github.com/gravitational/teleport"
trustpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/backend"
"github.com/gravitational/teleport/lib/itertools/stream"
@@ -866,49 +867,66 @@ func (s *CA) GetTunnelConnection(clusterName, connectionName string, opts ...ser
}
// GetTunnelConnections returns connections for a trusted cluster
func (s *CA) GetTunnelConnections(clusterName string, opts ...services.MarshalOption) ([]types.TunnelConnection, error) {
func (s *CA) GetTunnelConnections(ctx context.Context, clusterName string) ([]types.TunnelConnection, error) {
if clusterName == "" {
return nil, trace.BadParameter("missing cluster name")
}
startKey := backend.ExactKey(tunnelConnectionsPrefix, clusterName)
result, err := s.GetRange(context.TODO(), startKey, backend.RangeEnd(startKey), backend.NoLimit)
if err != nil {
return nil, trace.Wrap(err)
}
conns := make([]types.TunnelConnection, len(result.Items))
for i, item := range result.Items {
conns, err := stream.Collect(s.rangeTunnelConnections(ctx, clusterName, ""))
return conns, trace.Wrap(err)
}
// ListTunnelConnections returns a page of tunnel connections, optionally
// filtered to a single cluster.
func (s *CA) ListTunnelConnections(ctx context.Context, pageSize int, pageToken string, filter *trustpb.ListTunnelConnectionsFilter) ([]types.TunnelConnection, string, error) {
return generic.CollectPageAndCursor(
s.rangeTunnelConnections(ctx, filter.GetClusterName(), pageToken),
pageSize,
func(tc types.TunnelConnection) string {
return tc.GetClusterName() + backend.SeparatorString + tc.GetName()
},
)
}
// rangeTunnelConnections returns tunnel connection resources starting from the
// given page token, optionally restricted to a single cluster.
func (s *CA) rangeTunnelConnections(ctx context.Context, clusterName, pageToken string) iter.Seq2[types.TunnelConnection, error] {
mapFn := func(item backend.Item) (types.TunnelConnection, bool) {
conn, err := services.UnmarshalTunnelConnection(item.Value,
services.AddOptions(opts, services.WithExpires(item.Expires), services.WithRevision(item.Revision))...)
services.WithExpires(item.Expires),
services.WithRevision(item.Revision))
if err != nil {
return nil, trace.Wrap(err)
s.logger.WarnContext(ctx, "Failed to unmarshal tunnel connection from backend item",
"key", item.Key,
"error", err,
)
return nil, false
}
conns[i] = conn
return conn, true
}
return conns, nil
prefix := backend.ExactKey(tunnelConnectionsPrefix)
if clusterName != "" {
prefix = backend.ExactKey(tunnelConnectionsPrefix, clusterName)
}
startKey := prefix
if pageToken != "" {
startKey = backend.NewKey(tunnelConnectionsPrefix).AppendKey(backend.KeyFromString(pageToken))
}
endKey := backend.RangeEnd(prefix)
return stream.FilterMap(
s.Backend.Items(ctx, backend.ItemsParams{
StartKey: startKey,
EndKey: endKey,
}),
mapFn,
)
}
// GetAllTunnelConnections returns all tunnel connections
func (s *CA) GetAllTunnelConnections(opts ...services.MarshalOption) ([]types.TunnelConnection, error) {
startKey := backend.ExactKey(tunnelConnectionsPrefix)
result, err := s.GetRange(context.TODO(), startKey, backend.RangeEnd(startKey), backend.NoLimit)
if err != nil {
return nil, trace.Wrap(err)
}
conns := make([]types.TunnelConnection, len(result.Items))
for i, item := range result.Items {
conn, err := services.UnmarshalTunnelConnection(item.Value,
services.AddOptions(opts,
services.WithExpires(item.Expires),
services.WithRevision(item.Revision))...)
if err != nil {
return nil, trace.Wrap(err)
}
conns[i] = conn
}
return conns, nil
func (s *CA) GetAllTunnelConnections(ctx context.Context) ([]types.TunnelConnection, error) {
conns, err := stream.Collect(s.rangeTunnelConnections(ctx, "", ""))
return conns, trace.Wrap(err)
}
// DeleteTunnelConnection deletes tunnel connection by name
+91
View File
@@ -33,6 +33,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/gravitational/teleport"
trustpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/auth/testauthority"
"github.com/gravitational/teleport/lib/backend"
@@ -484,6 +485,96 @@ func TestPresenceService_ListRemoteClusters(t *testing.T) {
require.Len(t, rcs, 10)
}
// TestCA_TunnelConnections_CorruptItem ensures that a single malformed tunnel
// connection in the backend is skipped rather than failing or truncating the
// read. For List* this means pagination is not cut short; for Get*/GetAll* this
// means the bad item is skipped instead of erroring the whole call.
func TestCA_TunnelConnections_CorruptItem(t *testing.T) {
t.Parallel()
ctx := t.Context()
bk, err := memory.New(memory.Config{})
require.NoError(t, err)
t.Cleanup(func() { require.NoError(t, bk.Close()) })
trustService := NewCAService(bk)
const cluster = "leaf.example.com"
want := []string{"conn-0", "conn-1", "conn-2", "conn-3", "conn-4"}
for _, name := range want {
conn, err := types.NewTunnelConnection(name, types.TunnelConnectionSpecV2{
ClusterName: cluster,
ProxyName: "proxy",
LastHeartbeat: time.Now().UTC(),
Type: types.ProxyTunnel,
})
require.NoError(t, err)
require.NoError(t, trustService.UpsertTunnelConnection(ctx, conn))
}
// Write an unparseable item whose key sorts in the middle of the set
// (between conn-2 and conn-3).
_, err = bk.Put(ctx, backend.Item{
Key: backend.NewKey(tunnelConnectionsPrefix, cluster, "conn-2x"),
Value: []byte("}not a valid tunnel connection{"),
})
require.NoError(t, err)
// Page through with a small page size so the corrupt item lands inside a
// page window. Before the fix this dropped every connection after the
// corrupt one.
var got []string
var pageToken string
for {
page, next, err := trustService.ListTunnelConnections(ctx, 2, pageToken, nil)
require.NoError(t, err)
for _, c := range page {
got = append(got, c.GetName())
}
if next == "" {
break
}
pageToken = next
}
require.Equal(t, want, got)
// The cluster filter path must behave identically.
got = nil
pageToken = ""
for {
page, next, err := trustService.ListTunnelConnections(ctx, 2, pageToken, &trustpb.ListTunnelConnectionsFilter{
ClusterName: cluster,
})
require.NoError(t, err)
for _, c := range page {
got = append(got, c.GetName())
}
if next == "" {
break
}
pageToken = next
}
require.Equal(t, want, got)
// GetTunnelConnections and GetAllTunnelConnections skip the corrupt item
// rather than returning an error.
conns, err := trustService.GetTunnelConnections(ctx, cluster)
require.NoError(t, err)
gotNames := make([]string, 0, len(conns))
for _, c := range conns {
gotNames = append(gotNames, c.GetName())
}
require.ElementsMatch(t, want, gotNames)
allConns, err := trustService.GetAllTunnelConnections(ctx)
require.NoError(t, err)
gotNames = gotNames[:0]
for _, c := range allConns {
gotNames = append(gotNames, c.GetName())
}
require.ElementsMatch(t, want, gotNames)
}
func TestTrustedClusterCRUD(t *testing.T) {
t.Parallel()
ctx := context.Background()
+7 -2
View File
@@ -22,6 +22,7 @@ import (
"context"
"iter"
trustpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1"
"github.com/gravitational/teleport/api/types"
)
@@ -149,10 +150,14 @@ type Clusters interface {
UpsertTunnelConnection(ctx context.Context, conn types.TunnelConnection) error
// GetTunnelConnections returns tunnel connections for a given cluster
GetTunnelConnections(clusterName string, opts ...MarshalOption) ([]types.TunnelConnection, error)
GetTunnelConnections(ctx context.Context, clusterName string) ([]types.TunnelConnection, error)
// GetAllTunnelConnections returns all tunnel connections
GetAllTunnelConnections(opts ...MarshalOption) ([]types.TunnelConnection, error)
GetAllTunnelConnections(ctx context.Context) ([]types.TunnelConnection, error)
// ListTunnelConnections returns a page of tunnel connections matching the
// given filter.
ListTunnelConnections(ctx context.Context, pageSize int, pageToken string, filter *trustpb.ListTunnelConnectionsFilter) ([]types.TunnelConnection, string, error)
// DeleteTunnelConnection deletes tunnel connection by name
DeleteTunnelConnection(ctx context.Context, clusterName string, connName string) error
+1 -1
View File
@@ -576,7 +576,7 @@ func SetupTrustedCluster(ctx context.Context, t *testing.T, rootServer, leafServ
require.NoError(t, err)
require.EventuallyWithT(t, func(t *assert.CollectT) {
rt, err := rootServer.GetAuthServer().GetTunnelConnections(leafServer.Config.Auth.ClusterName.GetClusterName())
rt, err := rootServer.GetAuthServer().GetTunnelConnections(ctx, leafServer.Config.Auth.ClusterName.GetClusterName())
assert.NoError(t, err)
assert.Len(t, rt, 1)
}, time.Second*10, time.Second)
+1 -1
View File
@@ -306,7 +306,7 @@ func newTestSuite(t *testing.T, opts ...testSuiteOptionFunc) *suite {
if options.leafCluster || options.leafConfigFunc != nil {
s.setupLeafCluster(t, options)
require.Eventually(t, func() bool {
rt, err := s.root.GetAuthServer().GetTunnelConnections(s.leaf.Config.Auth.ClusterName.GetClusterName())
rt, err := s.root.GetAuthServer().GetTunnelConnections(t.Context(), s.leaf.Config.Auth.ClusterName.GetClusterName())
require.NoError(t, err)
return len(rt) == 1
}, 10*time.Second, 100*time.Millisecond)
+1 -1
View File
@@ -1565,7 +1565,7 @@ func TestSSHOnMultipleNodes(t *testing.T) {
require.NoError(t, err)
require.Eventually(t, func() bool {
conns, err := rootAuth.GetAuthServer().GetTunnelConnections("leafcluster")
conns, err := rootAuth.GetAuthServer().GetTunnelConnections(t.Context(), "leafcluster")
return err == nil && len(conns) == 1
}, 10*time.Second, 100*time.Millisecond, "leaf cluster never heart beated")