mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-29 17:58:15 +08:00
[vnet] feat: show SSH status in VNet slider (#55755)
* [vnet] feat: show SSH status in VNet slider * rename rpc * simplify when app and ssh zones match * Avoid making DNS zones bold * Fix the check for equal sets * Add presets to VnetSliderStep story * Fix case and punctuation * Fix positioning of inline warning icon * fix test --------- Co-authored-by: Rafał Cieślak <rafal.cieslak@goteleport.com>
This commit is contained in:
co-authored by
Rafał Cieślak
parent
5029a83e6b
commit
ff49ab0efd
@@ -248,27 +248,27 @@ func (*StopResponse) Descriptor() ([]byte, []int) {
|
||||
return file_teleport_lib_teleterm_vnet_v1_vnet_service_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
// Request for ListDNSZones.
|
||||
type ListDNSZonesRequest struct {
|
||||
// Request for GetServiceInfo.
|
||||
type GetServiceInfoRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ListDNSZonesRequest) Reset() {
|
||||
*x = ListDNSZonesRequest{}
|
||||
func (x *GetServiceInfoRequest) Reset() {
|
||||
*x = GetServiceInfoRequest{}
|
||||
mi := &file_teleport_lib_teleterm_vnet_v1_vnet_service_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListDNSZonesRequest) String() string {
|
||||
func (x *GetServiceInfoRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListDNSZonesRequest) ProtoMessage() {}
|
||||
func (*GetServiceInfoRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ListDNSZonesRequest) ProtoReflect() protoreflect.Message {
|
||||
func (x *GetServiceInfoRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_teleport_lib_teleterm_vnet_v1_vnet_service_proto_msgTypes[4]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
@@ -280,34 +280,40 @@ func (x *ListDNSZonesRequest) ProtoReflect() protoreflect.Message {
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListDNSZonesRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ListDNSZonesRequest) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use GetServiceInfoRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetServiceInfoRequest) Descriptor() ([]byte, []int) {
|
||||
return file_teleport_lib_teleterm_vnet_v1_vnet_service_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
// Response for ListDNSZones.
|
||||
type ListDNSZonesResponse struct {
|
||||
// GetServiceInfoResponse contains the status of the running VNet service.
|
||||
type GetServiceInfoResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// dns_zones is a deduplicated list of DNS zones.
|
||||
DnsZones []string `protobuf:"bytes,1,rep,name=dns_zones,json=dnsZones,proto3" json:"dns_zones,omitempty"`
|
||||
// app_dns_zones is a deduplicated list of all DNS zones valid as DNS
|
||||
// suffixes for connections to TCP apps.
|
||||
AppDnsZones []string `protobuf:"bytes,1,rep,name=app_dns_zones,json=appDnsZones,proto3" json:"app_dns_zones,omitempty"`
|
||||
// clusters is a list of cluster names valid as DNS suffixes for SSH hosts.
|
||||
Clusters []string `protobuf:"bytes,2,rep,name=clusters,proto3" json:"clusters,omitempty"`
|
||||
// ssh_configured is true if the user's SSH config file includes VNet's
|
||||
// generated SSH config necessary for SSH access.
|
||||
SshConfigured bool `protobuf:"varint,3,opt,name=ssh_configured,json=sshConfigured,proto3" json:"ssh_configured,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ListDNSZonesResponse) Reset() {
|
||||
*x = ListDNSZonesResponse{}
|
||||
func (x *GetServiceInfoResponse) Reset() {
|
||||
*x = GetServiceInfoResponse{}
|
||||
mi := &file_teleport_lib_teleterm_vnet_v1_vnet_service_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListDNSZonesResponse) String() string {
|
||||
func (x *GetServiceInfoResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListDNSZonesResponse) ProtoMessage() {}
|
||||
func (*GetServiceInfoResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ListDNSZonesResponse) ProtoReflect() protoreflect.Message {
|
||||
func (x *GetServiceInfoResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_teleport_lib_teleterm_vnet_v1_vnet_service_proto_msgTypes[5]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
@@ -319,18 +325,32 @@ func (x *ListDNSZonesResponse) ProtoReflect() protoreflect.Message {
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListDNSZonesResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ListDNSZonesResponse) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use GetServiceInfoResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetServiceInfoResponse) Descriptor() ([]byte, []int) {
|
||||
return file_teleport_lib_teleterm_vnet_v1_vnet_service_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *ListDNSZonesResponse) GetDnsZones() []string {
|
||||
func (x *GetServiceInfoResponse) GetAppDnsZones() []string {
|
||||
if x != nil {
|
||||
return x.DnsZones
|
||||
return x.AppDnsZones
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *GetServiceInfoResponse) GetClusters() []string {
|
||||
if x != nil {
|
||||
return x.Clusters
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *GetServiceInfoResponse) GetSshConfigured() bool {
|
||||
if x != nil {
|
||||
return x.SshConfigured
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Request for GetBackgroundItemStatus.
|
||||
type GetBackgroundItemStatusRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
@@ -503,10 +523,12 @@ const file_teleport_lib_teleterm_vnet_v1_vnet_service_proto_rawDesc = "" +
|
||||
"\fStartRequest\"\x0f\n" +
|
||||
"\rStartResponse\"\r\n" +
|
||||
"\vStopRequest\"\x0e\n" +
|
||||
"\fStopResponse\"\x15\n" +
|
||||
"\x13ListDNSZonesRequest\"3\n" +
|
||||
"\x14ListDNSZonesResponse\x12\x1b\n" +
|
||||
"\tdns_zones\x18\x01 \x03(\tR\bdnsZones\" \n" +
|
||||
"\fStopResponse\"\x17\n" +
|
||||
"\x15GetServiceInfoRequest\"\x7f\n" +
|
||||
"\x16GetServiceInfoResponse\x12\"\n" +
|
||||
"\rapp_dns_zones\x18\x01 \x03(\tR\vappDnsZones\x12\x1a\n" +
|
||||
"\bclusters\x18\x02 \x03(\tR\bclusters\x12%\n" +
|
||||
"\x0essh_configured\x18\x03 \x01(\bR\rsshConfigured\" \n" +
|
||||
"\x1eGetBackgroundItemStatusRequest\"n\n" +
|
||||
"\x1fGetBackgroundItemStatusResponse\x12K\n" +
|
||||
"\x06status\x18\x01 \x01(\x0e23.teleport.lib.teleterm.vnet.v1.BackgroundItemStatusR\x06status\"\x17\n" +
|
||||
@@ -519,11 +541,11 @@ const file_teleport_lib_teleterm_vnet_v1_vnet_service_proto_rawDesc = "" +
|
||||
"\x1eBACKGROUND_ITEM_STATUS_ENABLED\x10\x02\x12,\n" +
|
||||
"(BACKGROUND_ITEM_STATUS_REQUIRES_APPROVAL\x10\x03\x12$\n" +
|
||||
" BACKGROUND_ITEM_STATUS_NOT_FOUND\x10\x04\x12(\n" +
|
||||
"$BACKGROUND_ITEM_STATUS_NOT_SUPPORTED\x10\x052\xe5\x04\n" +
|
||||
"$BACKGROUND_ITEM_STATUS_NOT_SUPPORTED\x10\x052\xeb\x04\n" +
|
||||
"\vVnetService\x12b\n" +
|
||||
"\x05Start\x12+.teleport.lib.teleterm.vnet.v1.StartRequest\x1a,.teleport.lib.teleterm.vnet.v1.StartResponse\x12_\n" +
|
||||
"\x04Stop\x12*.teleport.lib.teleterm.vnet.v1.StopRequest\x1a+.teleport.lib.teleterm.vnet.v1.StopResponse\x12w\n" +
|
||||
"\fListDNSZones\x122.teleport.lib.teleterm.vnet.v1.ListDNSZonesRequest\x1a3.teleport.lib.teleterm.vnet.v1.ListDNSZonesResponse\x12\x98\x01\n" +
|
||||
"\x04Stop\x12*.teleport.lib.teleterm.vnet.v1.StopRequest\x1a+.teleport.lib.teleterm.vnet.v1.StopResponse\x12}\n" +
|
||||
"\x0eGetServiceInfo\x124.teleport.lib.teleterm.vnet.v1.GetServiceInfoRequest\x1a5.teleport.lib.teleterm.vnet.v1.GetServiceInfoResponse\x12\x98\x01\n" +
|
||||
"\x17GetBackgroundItemStatus\x12=.teleport.lib.teleterm.vnet.v1.GetBackgroundItemStatusRequest\x1a>.teleport.lib.teleterm.vnet.v1.GetBackgroundItemStatusResponse\x12}\n" +
|
||||
"\x0eRunDiagnostics\x124.teleport.lib.teleterm.vnet.v1.RunDiagnosticsRequest\x1a5.teleport.lib.teleterm.vnet.v1.RunDiagnosticsResponseBUZSgithub.com/gravitational/teleport/gen/proto/go/teleport/lib/teleterm/vnet/v1;vnetv1b\x06proto3"
|
||||
|
||||
@@ -547,8 +569,8 @@ var file_teleport_lib_teleterm_vnet_v1_vnet_service_proto_goTypes = []any{
|
||||
(*StartResponse)(nil), // 2: teleport.lib.teleterm.vnet.v1.StartResponse
|
||||
(*StopRequest)(nil), // 3: teleport.lib.teleterm.vnet.v1.StopRequest
|
||||
(*StopResponse)(nil), // 4: teleport.lib.teleterm.vnet.v1.StopResponse
|
||||
(*ListDNSZonesRequest)(nil), // 5: teleport.lib.teleterm.vnet.v1.ListDNSZonesRequest
|
||||
(*ListDNSZonesResponse)(nil), // 6: teleport.lib.teleterm.vnet.v1.ListDNSZonesResponse
|
||||
(*GetServiceInfoRequest)(nil), // 5: teleport.lib.teleterm.vnet.v1.GetServiceInfoRequest
|
||||
(*GetServiceInfoResponse)(nil), // 6: teleport.lib.teleterm.vnet.v1.GetServiceInfoResponse
|
||||
(*GetBackgroundItemStatusRequest)(nil), // 7: teleport.lib.teleterm.vnet.v1.GetBackgroundItemStatusRequest
|
||||
(*GetBackgroundItemStatusResponse)(nil), // 8: teleport.lib.teleterm.vnet.v1.GetBackgroundItemStatusResponse
|
||||
(*RunDiagnosticsRequest)(nil), // 9: teleport.lib.teleterm.vnet.v1.RunDiagnosticsRequest
|
||||
@@ -560,12 +582,12 @@ var file_teleport_lib_teleterm_vnet_v1_vnet_service_proto_depIdxs = []int32{
|
||||
11, // 1: teleport.lib.teleterm.vnet.v1.RunDiagnosticsResponse.report:type_name -> teleport.lib.vnet.diag.v1.Report
|
||||
1, // 2: teleport.lib.teleterm.vnet.v1.VnetService.Start:input_type -> teleport.lib.teleterm.vnet.v1.StartRequest
|
||||
3, // 3: teleport.lib.teleterm.vnet.v1.VnetService.Stop:input_type -> teleport.lib.teleterm.vnet.v1.StopRequest
|
||||
5, // 4: teleport.lib.teleterm.vnet.v1.VnetService.ListDNSZones:input_type -> teleport.lib.teleterm.vnet.v1.ListDNSZonesRequest
|
||||
5, // 4: teleport.lib.teleterm.vnet.v1.VnetService.GetServiceInfo:input_type -> teleport.lib.teleterm.vnet.v1.GetServiceInfoRequest
|
||||
7, // 5: teleport.lib.teleterm.vnet.v1.VnetService.GetBackgroundItemStatus:input_type -> teleport.lib.teleterm.vnet.v1.GetBackgroundItemStatusRequest
|
||||
9, // 6: teleport.lib.teleterm.vnet.v1.VnetService.RunDiagnostics:input_type -> teleport.lib.teleterm.vnet.v1.RunDiagnosticsRequest
|
||||
2, // 7: teleport.lib.teleterm.vnet.v1.VnetService.Start:output_type -> teleport.lib.teleterm.vnet.v1.StartResponse
|
||||
4, // 8: teleport.lib.teleterm.vnet.v1.VnetService.Stop:output_type -> teleport.lib.teleterm.vnet.v1.StopResponse
|
||||
6, // 9: teleport.lib.teleterm.vnet.v1.VnetService.ListDNSZones:output_type -> teleport.lib.teleterm.vnet.v1.ListDNSZonesResponse
|
||||
6, // 9: teleport.lib.teleterm.vnet.v1.VnetService.GetServiceInfo:output_type -> teleport.lib.teleterm.vnet.v1.GetServiceInfoResponse
|
||||
8, // 10: teleport.lib.teleterm.vnet.v1.VnetService.GetBackgroundItemStatus:output_type -> teleport.lib.teleterm.vnet.v1.GetBackgroundItemStatusResponse
|
||||
10, // 11: teleport.lib.teleterm.vnet.v1.VnetService.RunDiagnostics:output_type -> teleport.lib.teleterm.vnet.v1.RunDiagnosticsResponse
|
||||
7, // [7:12] is the sub-list for method output_type
|
||||
|
||||
@@ -37,7 +37,7 @@ const _ = grpc.SupportPackageIsVersion9
|
||||
const (
|
||||
VnetService_Start_FullMethodName = "/teleport.lib.teleterm.vnet.v1.VnetService/Start"
|
||||
VnetService_Stop_FullMethodName = "/teleport.lib.teleterm.vnet.v1.VnetService/Stop"
|
||||
VnetService_ListDNSZones_FullMethodName = "/teleport.lib.teleterm.vnet.v1.VnetService/ListDNSZones"
|
||||
VnetService_GetServiceInfo_FullMethodName = "/teleport.lib.teleterm.vnet.v1.VnetService/GetServiceInfo"
|
||||
VnetService_GetBackgroundItemStatus_FullMethodName = "/teleport.lib.teleterm.vnet.v1.VnetService/GetBackgroundItemStatus"
|
||||
VnetService_RunDiagnostics_FullMethodName = "/teleport.lib.teleterm.vnet.v1.VnetService/RunDiagnostics"
|
||||
)
|
||||
@@ -52,16 +52,8 @@ type VnetServiceClient interface {
|
||||
Start(ctx context.Context, in *StartRequest, opts ...grpc.CallOption) (*StartResponse, error)
|
||||
// Stop stops VNet.
|
||||
Stop(ctx context.Context, in *StopRequest, opts ...grpc.CallOption) (*StopResponse, error)
|
||||
// ListDNSZones returns DNS zones of all root and leaf clusters with non-expired user certs. This
|
||||
// includes the proxy service hostnames and custom DNS zones configured in vnet_config.
|
||||
//
|
||||
// This is fetched independently of what the Electron app thinks the current state of the cluster
|
||||
// looks like, since the VNet admin process also fetches this data independently of the Electron
|
||||
// app.
|
||||
//
|
||||
// Just like the admin process, it skips root and leaf clusters for which the vnet_config couldn't
|
||||
// be fetched (due to e.g., a network error or an expired cert).
|
||||
ListDNSZones(ctx context.Context, in *ListDNSZonesRequest, opts ...grpc.CallOption) (*ListDNSZonesResponse, error)
|
||||
// GetServiceInfo returns info about the running VNet service.
|
||||
GetServiceInfo(ctx context.Context, in *GetServiceInfoRequest, opts ...grpc.CallOption) (*GetServiceInfoResponse, error)
|
||||
// GetBackgroundItemStatus returns the status of the background item responsible for launching
|
||||
// VNet daemon. macOS only. tsh must be compiled with the vnetdaemon build tag.
|
||||
GetBackgroundItemStatus(ctx context.Context, in *GetBackgroundItemStatusRequest, opts ...grpc.CallOption) (*GetBackgroundItemStatusResponse, error)
|
||||
@@ -98,10 +90,10 @@ func (c *vnetServiceClient) Stop(ctx context.Context, in *StopRequest, opts ...g
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *vnetServiceClient) ListDNSZones(ctx context.Context, in *ListDNSZonesRequest, opts ...grpc.CallOption) (*ListDNSZonesResponse, error) {
|
||||
func (c *vnetServiceClient) GetServiceInfo(ctx context.Context, in *GetServiceInfoRequest, opts ...grpc.CallOption) (*GetServiceInfoResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListDNSZonesResponse)
|
||||
err := c.cc.Invoke(ctx, VnetService_ListDNSZones_FullMethodName, in, out, cOpts...)
|
||||
out := new(GetServiceInfoResponse)
|
||||
err := c.cc.Invoke(ctx, VnetService_GetServiceInfo_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -138,16 +130,8 @@ type VnetServiceServer interface {
|
||||
Start(context.Context, *StartRequest) (*StartResponse, error)
|
||||
// Stop stops VNet.
|
||||
Stop(context.Context, *StopRequest) (*StopResponse, error)
|
||||
// ListDNSZones returns DNS zones of all root and leaf clusters with non-expired user certs. This
|
||||
// includes the proxy service hostnames and custom DNS zones configured in vnet_config.
|
||||
//
|
||||
// This is fetched independently of what the Electron app thinks the current state of the cluster
|
||||
// looks like, since the VNet admin process also fetches this data independently of the Electron
|
||||
// app.
|
||||
//
|
||||
// Just like the admin process, it skips root and leaf clusters for which the vnet_config couldn't
|
||||
// be fetched (due to e.g., a network error or an expired cert).
|
||||
ListDNSZones(context.Context, *ListDNSZonesRequest) (*ListDNSZonesResponse, error)
|
||||
// GetServiceInfo returns info about the running VNet service.
|
||||
GetServiceInfo(context.Context, *GetServiceInfoRequest) (*GetServiceInfoResponse, error)
|
||||
// GetBackgroundItemStatus returns the status of the background item responsible for launching
|
||||
// VNet daemon. macOS only. tsh must be compiled with the vnetdaemon build tag.
|
||||
GetBackgroundItemStatus(context.Context, *GetBackgroundItemStatusRequest) (*GetBackgroundItemStatusResponse, error)
|
||||
@@ -170,8 +154,8 @@ func (UnimplementedVnetServiceServer) Start(context.Context, *StartRequest) (*St
|
||||
func (UnimplementedVnetServiceServer) Stop(context.Context, *StopRequest) (*StopResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Stop not implemented")
|
||||
}
|
||||
func (UnimplementedVnetServiceServer) ListDNSZones(context.Context, *ListDNSZonesRequest) (*ListDNSZonesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListDNSZones not implemented")
|
||||
func (UnimplementedVnetServiceServer) GetServiceInfo(context.Context, *GetServiceInfoRequest) (*GetServiceInfoResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetServiceInfo not implemented")
|
||||
}
|
||||
func (UnimplementedVnetServiceServer) GetBackgroundItemStatus(context.Context, *GetBackgroundItemStatusRequest) (*GetBackgroundItemStatusResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetBackgroundItemStatus not implemented")
|
||||
@@ -236,20 +220,20 @@ func _VnetService_Stop_Handler(srv interface{}, ctx context.Context, dec func(in
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _VnetService_ListDNSZones_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListDNSZonesRequest)
|
||||
func _VnetService_GetServiceInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetServiceInfoRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(VnetServiceServer).ListDNSZones(ctx, in)
|
||||
return srv.(VnetServiceServer).GetServiceInfo(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: VnetService_ListDNSZones_FullMethodName,
|
||||
FullMethod: VnetService_GetServiceInfo_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(VnetServiceServer).ListDNSZones(ctx, req.(*ListDNSZonesRequest))
|
||||
return srv.(VnetServiceServer).GetServiceInfo(ctx, req.(*GetServiceInfoRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
@@ -306,8 +290,8 @@ var VnetService_ServiceDesc = grpc.ServiceDesc{
|
||||
Handler: _VnetService_Stop_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListDNSZones",
|
||||
Handler: _VnetService_ListDNSZones_Handler,
|
||||
MethodName: "GetServiceInfo",
|
||||
Handler: _VnetService_GetServiceInfo_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetBackgroundItemStatus",
|
||||
|
||||
@@ -27,8 +27,8 @@ import type { RunDiagnosticsResponse } from "./vnet_service_pb";
|
||||
import type { RunDiagnosticsRequest } from "./vnet_service_pb";
|
||||
import type { GetBackgroundItemStatusResponse } from "./vnet_service_pb";
|
||||
import type { GetBackgroundItemStatusRequest } from "./vnet_service_pb";
|
||||
import type { ListDNSZonesResponse } from "./vnet_service_pb";
|
||||
import type { ListDNSZonesRequest } from "./vnet_service_pb";
|
||||
import type { GetServiceInfoResponse } from "./vnet_service_pb";
|
||||
import type { GetServiceInfoRequest } from "./vnet_service_pb";
|
||||
import type { StopResponse } from "./vnet_service_pb";
|
||||
import type { StopRequest } from "./vnet_service_pb";
|
||||
import { stackIntercept } from "@protobuf-ts/runtime-rpc";
|
||||
@@ -55,19 +55,11 @@ export interface IVnetServiceClient {
|
||||
*/
|
||||
stop(input: StopRequest, options?: RpcOptions): UnaryCall<StopRequest, StopResponse>;
|
||||
/**
|
||||
* ListDNSZones returns DNS zones of all root and leaf clusters with non-expired user certs. This
|
||||
* includes the proxy service hostnames and custom DNS zones configured in vnet_config.
|
||||
* GetServiceInfo returns info about the running VNet service.
|
||||
*
|
||||
* This is fetched independently of what the Electron app thinks the current state of the cluster
|
||||
* looks like, since the VNet admin process also fetches this data independently of the Electron
|
||||
* app.
|
||||
*
|
||||
* Just like the admin process, it skips root and leaf clusters for which the vnet_config couldn't
|
||||
* be fetched (due to e.g., a network error or an expired cert).
|
||||
*
|
||||
* @generated from protobuf rpc: ListDNSZones(teleport.lib.teleterm.vnet.v1.ListDNSZonesRequest) returns (teleport.lib.teleterm.vnet.v1.ListDNSZonesResponse);
|
||||
* @generated from protobuf rpc: GetServiceInfo(teleport.lib.teleterm.vnet.v1.GetServiceInfoRequest) returns (teleport.lib.teleterm.vnet.v1.GetServiceInfoResponse);
|
||||
*/
|
||||
listDNSZones(input: ListDNSZonesRequest, options?: RpcOptions): UnaryCall<ListDNSZonesRequest, ListDNSZonesResponse>;
|
||||
getServiceInfo(input: GetServiceInfoRequest, options?: RpcOptions): UnaryCall<GetServiceInfoRequest, GetServiceInfoResponse>;
|
||||
/**
|
||||
* GetBackgroundItemStatus returns the status of the background item responsible for launching
|
||||
* VNet daemon. macOS only. tsh must be compiled with the vnetdaemon build tag.
|
||||
@@ -113,21 +105,13 @@ export class VnetServiceClient implements IVnetServiceClient, ServiceInfo {
|
||||
return stackIntercept<StopRequest, StopResponse>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* ListDNSZones returns DNS zones of all root and leaf clusters with non-expired user certs. This
|
||||
* includes the proxy service hostnames and custom DNS zones configured in vnet_config.
|
||||
* GetServiceInfo returns info about the running VNet service.
|
||||
*
|
||||
* This is fetched independently of what the Electron app thinks the current state of the cluster
|
||||
* looks like, since the VNet admin process also fetches this data independently of the Electron
|
||||
* app.
|
||||
*
|
||||
* Just like the admin process, it skips root and leaf clusters for which the vnet_config couldn't
|
||||
* be fetched (due to e.g., a network error or an expired cert).
|
||||
*
|
||||
* @generated from protobuf rpc: ListDNSZones(teleport.lib.teleterm.vnet.v1.ListDNSZonesRequest) returns (teleport.lib.teleterm.vnet.v1.ListDNSZonesResponse);
|
||||
* @generated from protobuf rpc: GetServiceInfo(teleport.lib.teleterm.vnet.v1.GetServiceInfoRequest) returns (teleport.lib.teleterm.vnet.v1.GetServiceInfoResponse);
|
||||
*/
|
||||
listDNSZones(input: ListDNSZonesRequest, options?: RpcOptions): UnaryCall<ListDNSZonesRequest, ListDNSZonesResponse> {
|
||||
getServiceInfo(input: GetServiceInfoRequest, options?: RpcOptions): UnaryCall<GetServiceInfoRequest, GetServiceInfoResponse> {
|
||||
const method = this.methods[2], opt = this._transport.mergeOptions(options);
|
||||
return stackIntercept<ListDNSZonesRequest, ListDNSZonesResponse>("unary", this._transport, method, opt, input);
|
||||
return stackIntercept<GetServiceInfoRequest, GetServiceInfoResponse>("unary", this._transport, method, opt, input);
|
||||
}
|
||||
/**
|
||||
* GetBackgroundItemStatus returns the status of the background item responsible for launching
|
||||
|
||||
+12
-20
@@ -24,8 +24,8 @@ import { RunDiagnosticsResponse } from "./vnet_service_pb";
|
||||
import { RunDiagnosticsRequest } from "./vnet_service_pb";
|
||||
import { GetBackgroundItemStatusResponse } from "./vnet_service_pb";
|
||||
import { GetBackgroundItemStatusRequest } from "./vnet_service_pb";
|
||||
import { ListDNSZonesResponse } from "./vnet_service_pb";
|
||||
import { ListDNSZonesRequest } from "./vnet_service_pb";
|
||||
import { GetServiceInfoResponse } from "./vnet_service_pb";
|
||||
import { GetServiceInfoRequest } from "./vnet_service_pb";
|
||||
import { StopResponse } from "./vnet_service_pb";
|
||||
import { StopRequest } from "./vnet_service_pb";
|
||||
import { StartResponse } from "./vnet_service_pb";
|
||||
@@ -50,19 +50,11 @@ export interface IVnetService extends grpc.UntypedServiceImplementation {
|
||||
*/
|
||||
stop: grpc.handleUnaryCall<StopRequest, StopResponse>;
|
||||
/**
|
||||
* ListDNSZones returns DNS zones of all root and leaf clusters with non-expired user certs. This
|
||||
* includes the proxy service hostnames and custom DNS zones configured in vnet_config.
|
||||
* GetServiceInfo returns info about the running VNet service.
|
||||
*
|
||||
* This is fetched independently of what the Electron app thinks the current state of the cluster
|
||||
* looks like, since the VNet admin process also fetches this data independently of the Electron
|
||||
* app.
|
||||
*
|
||||
* Just like the admin process, it skips root and leaf clusters for which the vnet_config couldn't
|
||||
* be fetched (due to e.g., a network error or an expired cert).
|
||||
*
|
||||
* @generated from protobuf rpc: ListDNSZones(teleport.lib.teleterm.vnet.v1.ListDNSZonesRequest) returns (teleport.lib.teleterm.vnet.v1.ListDNSZonesResponse);
|
||||
* @generated from protobuf rpc: GetServiceInfo(teleport.lib.teleterm.vnet.v1.GetServiceInfoRequest) returns (teleport.lib.teleterm.vnet.v1.GetServiceInfoResponse);
|
||||
*/
|
||||
listDNSZones: grpc.handleUnaryCall<ListDNSZonesRequest, ListDNSZonesResponse>;
|
||||
getServiceInfo: grpc.handleUnaryCall<GetServiceInfoRequest, GetServiceInfoResponse>;
|
||||
/**
|
||||
* GetBackgroundItemStatus returns the status of the background item responsible for launching
|
||||
* VNet daemon. macOS only. tsh must be compiled with the vnetdaemon build tag.
|
||||
@@ -110,15 +102,15 @@ export const vnetServiceDefinition: grpc.ServiceDefinition<IVnetService> = {
|
||||
responseSerialize: value => Buffer.from(StopResponse.toBinary(value)),
|
||||
requestSerialize: value => Buffer.from(StopRequest.toBinary(value))
|
||||
},
|
||||
listDNSZones: {
|
||||
path: "/teleport.lib.teleterm.vnet.v1.VnetService/ListDNSZones",
|
||||
originalName: "ListDNSZones",
|
||||
getServiceInfo: {
|
||||
path: "/teleport.lib.teleterm.vnet.v1.VnetService/GetServiceInfo",
|
||||
originalName: "GetServiceInfo",
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
responseDeserialize: bytes => ListDNSZonesResponse.fromBinary(bytes),
|
||||
requestDeserialize: bytes => ListDNSZonesRequest.fromBinary(bytes),
|
||||
responseSerialize: value => Buffer.from(ListDNSZonesResponse.toBinary(value)),
|
||||
requestSerialize: value => Buffer.from(ListDNSZonesRequest.toBinary(value))
|
||||
responseDeserialize: bytes => GetServiceInfoResponse.fromBinary(bytes),
|
||||
requestDeserialize: bytes => GetServiceInfoRequest.fromBinary(bytes),
|
||||
responseSerialize: value => Buffer.from(GetServiceInfoResponse.toBinary(value)),
|
||||
requestSerialize: value => Buffer.from(GetServiceInfoRequest.toBinary(value))
|
||||
},
|
||||
getBackgroundItemStatus: {
|
||||
path: "/teleport.lib.teleterm.vnet.v1.VnetService/GetBackgroundItemStatus",
|
||||
|
||||
+63
-33
@@ -60,24 +60,38 @@ export interface StopRequest {
|
||||
export interface StopResponse {
|
||||
}
|
||||
/**
|
||||
* Request for ListDNSZones.
|
||||
* Request for GetServiceInfo.
|
||||
*
|
||||
* @generated from protobuf message teleport.lib.teleterm.vnet.v1.ListDNSZonesRequest
|
||||
* @generated from protobuf message teleport.lib.teleterm.vnet.v1.GetServiceInfoRequest
|
||||
*/
|
||||
export interface ListDNSZonesRequest {
|
||||
export interface GetServiceInfoRequest {
|
||||
}
|
||||
/**
|
||||
* Response for ListDNSZones.
|
||||
* GetServiceInfoResponse contains the status of the running VNet service.
|
||||
*
|
||||
* @generated from protobuf message teleport.lib.teleterm.vnet.v1.ListDNSZonesResponse
|
||||
* @generated from protobuf message teleport.lib.teleterm.vnet.v1.GetServiceInfoResponse
|
||||
*/
|
||||
export interface ListDNSZonesResponse {
|
||||
export interface GetServiceInfoResponse {
|
||||
/**
|
||||
* dns_zones is a deduplicated list of DNS zones.
|
||||
* app_dns_zones is a deduplicated list of all DNS zones valid as DNS
|
||||
* suffixes for connections to TCP apps.
|
||||
*
|
||||
* @generated from protobuf field: repeated string dns_zones = 1;
|
||||
* @generated from protobuf field: repeated string app_dns_zones = 1;
|
||||
*/
|
||||
dnsZones: string[];
|
||||
appDnsZones: string[];
|
||||
/**
|
||||
* clusters is a list of cluster names valid as DNS suffixes for SSH hosts.
|
||||
*
|
||||
* @generated from protobuf field: repeated string clusters = 2;
|
||||
*/
|
||||
clusters: string[];
|
||||
/**
|
||||
* ssh_configured is true if the user's SSH config file includes VNet's
|
||||
* generated SSH config necessary for SSH access.
|
||||
*
|
||||
* @generated from protobuf field: bool ssh_configured = 3;
|
||||
*/
|
||||
sshConfigured: boolean;
|
||||
}
|
||||
/**
|
||||
* Request for GetBackgroundItemStatus.
|
||||
@@ -251,20 +265,20 @@ class StopResponse$Type extends MessageType<StopResponse> {
|
||||
*/
|
||||
export const StopResponse = new StopResponse$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class ListDNSZonesRequest$Type extends MessageType<ListDNSZonesRequest> {
|
||||
class GetServiceInfoRequest$Type extends MessageType<GetServiceInfoRequest> {
|
||||
constructor() {
|
||||
super("teleport.lib.teleterm.vnet.v1.ListDNSZonesRequest", []);
|
||||
super("teleport.lib.teleterm.vnet.v1.GetServiceInfoRequest", []);
|
||||
}
|
||||
create(value?: PartialMessage<ListDNSZonesRequest>): ListDNSZonesRequest {
|
||||
create(value?: PartialMessage<GetServiceInfoRequest>): GetServiceInfoRequest {
|
||||
const message = globalThis.Object.create((this.messagePrototype!));
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<ListDNSZonesRequest>(this, message, value);
|
||||
reflectionMergePartial<GetServiceInfoRequest>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListDNSZonesRequest): ListDNSZonesRequest {
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetServiceInfoRequest): GetServiceInfoRequest {
|
||||
return target ?? this.create();
|
||||
}
|
||||
internalBinaryWrite(message: ListDNSZonesRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
internalBinaryWrite(message: GetServiceInfoRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
@@ -272,30 +286,40 @@ class ListDNSZonesRequest$Type extends MessageType<ListDNSZonesRequest> {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message teleport.lib.teleterm.vnet.v1.ListDNSZonesRequest
|
||||
* @generated MessageType for protobuf message teleport.lib.teleterm.vnet.v1.GetServiceInfoRequest
|
||||
*/
|
||||
export const ListDNSZonesRequest = new ListDNSZonesRequest$Type();
|
||||
export const GetServiceInfoRequest = new GetServiceInfoRequest$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class ListDNSZonesResponse$Type extends MessageType<ListDNSZonesResponse> {
|
||||
class GetServiceInfoResponse$Type extends MessageType<GetServiceInfoResponse> {
|
||||
constructor() {
|
||||
super("teleport.lib.teleterm.vnet.v1.ListDNSZonesResponse", [
|
||||
{ no: 1, name: "dns_zones", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }
|
||||
super("teleport.lib.teleterm.vnet.v1.GetServiceInfoResponse", [
|
||||
{ no: 1, name: "app_dns_zones", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 2, name: "clusters", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 3, name: "ssh_configured", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<ListDNSZonesResponse>): ListDNSZonesResponse {
|
||||
create(value?: PartialMessage<GetServiceInfoResponse>): GetServiceInfoResponse {
|
||||
const message = globalThis.Object.create((this.messagePrototype!));
|
||||
message.dnsZones = [];
|
||||
message.appDnsZones = [];
|
||||
message.clusters = [];
|
||||
message.sshConfigured = false;
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<ListDNSZonesResponse>(this, message, value);
|
||||
reflectionMergePartial<GetServiceInfoResponse>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListDNSZonesResponse): ListDNSZonesResponse {
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetServiceInfoResponse): GetServiceInfoResponse {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* repeated string dns_zones */ 1:
|
||||
message.dnsZones.push(reader.string());
|
||||
case /* repeated string app_dns_zones */ 1:
|
||||
message.appDnsZones.push(reader.string());
|
||||
break;
|
||||
case /* repeated string clusters */ 2:
|
||||
message.clusters.push(reader.string());
|
||||
break;
|
||||
case /* bool ssh_configured */ 3:
|
||||
message.sshConfigured = reader.bool();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
@@ -308,10 +332,16 @@ class ListDNSZonesResponse$Type extends MessageType<ListDNSZonesResponse> {
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: ListDNSZonesResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* repeated string dns_zones = 1; */
|
||||
for (let i = 0; i < message.dnsZones.length; i++)
|
||||
writer.tag(1, WireType.LengthDelimited).string(message.dnsZones[i]);
|
||||
internalBinaryWrite(message: GetServiceInfoResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* repeated string app_dns_zones = 1; */
|
||||
for (let i = 0; i < message.appDnsZones.length; i++)
|
||||
writer.tag(1, WireType.LengthDelimited).string(message.appDnsZones[i]);
|
||||
/* repeated string clusters = 2; */
|
||||
for (let i = 0; i < message.clusters.length; i++)
|
||||
writer.tag(2, WireType.LengthDelimited).string(message.clusters[i]);
|
||||
/* bool ssh_configured = 3; */
|
||||
if (message.sshConfigured !== false)
|
||||
writer.tag(3, WireType.Varint).bool(message.sshConfigured);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
@@ -319,9 +349,9 @@ class ListDNSZonesResponse$Type extends MessageType<ListDNSZonesResponse> {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message teleport.lib.teleterm.vnet.v1.ListDNSZonesResponse
|
||||
* @generated MessageType for protobuf message teleport.lib.teleterm.vnet.v1.GetServiceInfoResponse
|
||||
*/
|
||||
export const ListDNSZonesResponse = new ListDNSZonesResponse$Type();
|
||||
export const GetServiceInfoResponse = new GetServiceInfoResponse$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class GetBackgroundItemStatusRequest$Type extends MessageType<GetBackgroundItemStatusRequest> {
|
||||
constructor() {
|
||||
@@ -471,7 +501,7 @@ export const RunDiagnosticsResponse = new RunDiagnosticsResponse$Type();
|
||||
export const VnetService = new ServiceType("teleport.lib.teleterm.vnet.v1.VnetService", [
|
||||
{ name: "Start", options: {}, I: StartRequest, O: StartResponse },
|
||||
{ name: "Stop", options: {}, I: StopRequest, O: StopResponse },
|
||||
{ name: "ListDNSZones", options: {}, I: ListDNSZonesRequest, O: ListDNSZonesResponse },
|
||||
{ name: "GetServiceInfo", options: {}, I: GetServiceInfoRequest, O: GetServiceInfoResponse },
|
||||
{ name: "GetBackgroundItemStatus", options: {}, I: GetBackgroundItemStatusRequest, O: GetBackgroundItemStatusResponse },
|
||||
{ name: "RunDiagnostics", options: {}, I: RunDiagnosticsRequest, O: RunDiagnosticsResponse }
|
||||
]);
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
prehogv1alpha "github.com/gravitational/teleport/gen/proto/go/prehog/v1alpha"
|
||||
apiteleterm "github.com/gravitational/teleport/gen/proto/go/teleport/lib/teleterm/v1"
|
||||
api "github.com/gravitational/teleport/gen/proto/go/teleport/lib/teleterm/vnet/v1"
|
||||
diagv1 "github.com/gravitational/teleport/gen/proto/go/teleport/lib/vnet/diag/v1"
|
||||
vnetv1 "github.com/gravitational/teleport/gen/proto/go/teleport/lib/vnet/v1"
|
||||
"github.com/gravitational/teleport/lib/client"
|
||||
"github.com/gravitational/teleport/lib/teleterm/api/uri"
|
||||
@@ -43,6 +44,7 @@ import (
|
||||
"github.com/gravitational/teleport/lib/teleterm/daemon"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
"github.com/gravitational/teleport/lib/vnet"
|
||||
"github.com/gravitational/teleport/lib/vnet/diag"
|
||||
)
|
||||
|
||||
var log = logutils.NewPackageLogger(teleport.ComponentKey, "term:vnet")
|
||||
@@ -219,13 +221,8 @@ func (s *Service) Stop(ctx context.Context, req *api.StopRequest) (*api.StopResp
|
||||
return &api.StopResponse{}, nil
|
||||
}
|
||||
|
||||
// ListDNSZones returns DNS zones of all root and leaf clusters with non-expired user certs. This
|
||||
// includes the proxy service hostnames and custom DNS zones configured in vnet_config.
|
||||
//
|
||||
// This is fetched exactly the same way the VNet process fetches the DNS zones
|
||||
// but may be slightly out of sync with the OS configuration if the admin
|
||||
// process hasn't configured a recent change yet.
|
||||
func (s *Service) ListDNSZones(ctx context.Context, req *api.ListDNSZonesRequest) (*api.ListDNSZonesResponse, error) {
|
||||
// GetServiceInfo returns info about the running VNet service.
|
||||
func (s *Service) GetServiceInfo(ctx context.Context, _ *api.GetServiceInfoRequest) (*api.GetServiceInfoResponse, error) {
|
||||
// Acquire the lock just to check the status of the service. We don't want the actual process of
|
||||
// listing DNS zones to block the user from performing other operations.
|
||||
s.mu.Lock()
|
||||
@@ -240,8 +237,24 @@ func (s *Service) ListDNSZones(ctx context.Context, req *api.ListDNSZonesRequest
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return &api.ListDNSZonesResponse{
|
||||
DnsZones: unifiedClusterConfig.AppDNSZones(),
|
||||
|
||||
sshDiag, err := diag.NewSSHDiag(&diag.SSHConfig{
|
||||
ProfilePath: s.cfg.profilePath,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "building SSH diagnostic")
|
||||
}
|
||||
sshReport, err := sshDiag.Run(ctx)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "running SSH diagnostic")
|
||||
}
|
||||
sshConfigured := sshReport.Status == diagv1.CheckReportStatus_CHECK_REPORT_STATUS_OK &&
|
||||
sshReport.GetSshConfigurationReport().UserOpensshConfigIncludesVnetSshConfig
|
||||
|
||||
return &api.GetServiceInfoResponse{
|
||||
AppDnsZones: unifiedClusterConfig.AppDNSZones(),
|
||||
Clusters: unifiedClusterConfig.ClusterNames,
|
||||
SshConfigured: sshConfigured,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -30,16 +30,8 @@ service VnetService {
|
||||
// Stop stops VNet.
|
||||
rpc Stop(StopRequest) returns (StopResponse);
|
||||
|
||||
// ListDNSZones returns DNS zones of all root and leaf clusters with non-expired user certs. This
|
||||
// includes the proxy service hostnames and custom DNS zones configured in vnet_config.
|
||||
//
|
||||
// This is fetched independently of what the Electron app thinks the current state of the cluster
|
||||
// looks like, since the VNet admin process also fetches this data independently of the Electron
|
||||
// app.
|
||||
//
|
||||
// Just like the admin process, it skips root and leaf clusters for which the vnet_config couldn't
|
||||
// be fetched (due to e.g., a network error or an expired cert).
|
||||
rpc ListDNSZones(ListDNSZonesRequest) returns (ListDNSZonesResponse);
|
||||
// GetServiceInfo returns info about the running VNet service.
|
||||
rpc GetServiceInfo(GetServiceInfoRequest) returns (GetServiceInfoResponse);
|
||||
|
||||
// GetBackgroundItemStatus returns the status of the background item responsible for launching
|
||||
// VNet daemon. macOS only. tsh must be compiled with the vnetdaemon build tag.
|
||||
@@ -62,13 +54,19 @@ message StopRequest {}
|
||||
// Response for Stop.
|
||||
message StopResponse {}
|
||||
|
||||
// Request for ListDNSZones.
|
||||
message ListDNSZonesRequest {}
|
||||
// Request for GetServiceInfo.
|
||||
message GetServiceInfoRequest {}
|
||||
|
||||
// Response for ListDNSZones.
|
||||
message ListDNSZonesResponse {
|
||||
// dns_zones is a deduplicated list of DNS zones.
|
||||
repeated string dns_zones = 1;
|
||||
// GetServiceInfoResponse contains the status of the running VNet service.
|
||||
message GetServiceInfoResponse {
|
||||
// app_dns_zones is a deduplicated list of all DNS zones valid as DNS
|
||||
// suffixes for connections to TCP apps.
|
||||
repeated string app_dns_zones = 1;
|
||||
// clusters is a list of cluster names valid as DNS suffixes for SSH hosts.
|
||||
repeated string clusters = 2;
|
||||
// ssh_configured is true if the user's SSH config file includes VNet's
|
||||
// generated SSH config necessary for SSH access.
|
||||
bool ssh_configured = 3;
|
||||
}
|
||||
|
||||
// Request for GetBackgroundItemStatus.
|
||||
|
||||
@@ -118,7 +118,12 @@ export class MockTshClient implements TshdClient {
|
||||
export class MockVnetClient implements VnetClient {
|
||||
start = () => new MockedUnaryCall({});
|
||||
stop = () => new MockedUnaryCall({});
|
||||
listDNSZones = () => new MockedUnaryCall({ dnsZones: [] });
|
||||
getServiceInfo = () =>
|
||||
new MockedUnaryCall({
|
||||
appDnsZones: [],
|
||||
clusters: [],
|
||||
sshConfigured: false,
|
||||
});
|
||||
getBackgroundItemStatus = () => new MockedUnaryCall({ status: 0 });
|
||||
|
||||
runDiagnostics() {
|
||||
|
||||
+13
-11
@@ -21,6 +21,7 @@ import styled from 'styled-components';
|
||||
|
||||
import { ButtonIcon, Flex, Text } from 'design';
|
||||
import { Trash, Unlink } from 'design/Icon';
|
||||
import { typography, TypographyProps } from 'design/system';
|
||||
|
||||
import { useKeyboardArrowsNavigation } from 'teleterm/ui/components/KeyboardArrowsNavigation';
|
||||
import { ListItem } from 'teleterm/ui/components/ListItem';
|
||||
@@ -98,18 +99,9 @@ export function ConnectionItem(props: {
|
||||
line-height: 16px;
|
||||
`}
|
||||
>
|
||||
<span
|
||||
css={`
|
||||
font-size: 10px;
|
||||
background: ${props => props.theme.colors.spotBackground[2]};
|
||||
opacity: 0.85;
|
||||
padding: 1px 2px;
|
||||
margin-right: 4px;
|
||||
border-radius: 4px;
|
||||
`}
|
||||
>
|
||||
<ConnectionKindIndicator>
|
||||
{getKindName(props.item)}
|
||||
</span>
|
||||
</ConnectionKindIndicator>
|
||||
<span
|
||||
css={`
|
||||
vertical-align: middle;
|
||||
@@ -152,6 +144,16 @@ const ConnectionListItem = styled(ListItem)<{ $showClusterName?: boolean }>`
|
||||
height: unset;
|
||||
`;
|
||||
|
||||
export const ConnectionKindIndicator = styled.span<TypographyProps>`
|
||||
font-size: 10px;
|
||||
background: ${props => props.theme.colors.spotBackground[2]};
|
||||
opacity: 0.85;
|
||||
padding: 1px 2px;
|
||||
margin-right: 4px;
|
||||
border-radius: 4px;
|
||||
${typography}
|
||||
`;
|
||||
|
||||
function getKindName(connection: ExtendedTrackedConnection): string {
|
||||
switch (connection.kind) {
|
||||
case 'connection.gateway':
|
||||
|
||||
+9
@@ -109,6 +109,15 @@ const StyledStatus = styled(Box)<{
|
||||
&:after {
|
||||
content: '⚠';
|
||||
font-size: 12px;
|
||||
${props.$inline &&
|
||||
`
|
||||
// This cuts out a little portion of the icon on the left. This is most clearly visible
|
||||
// on Windows. But at least it better aligns with the other statuses.
|
||||
//
|
||||
// TODO(ravicious): Rewrite this to not use weird characters to represent different
|
||||
// statuses so that all statuses properly align together.
|
||||
margin: -1px;
|
||||
`}
|
||||
|
||||
${!props.$inline &&
|
||||
`
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { Meta } from '@storybook/react';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { Box } from 'design';
|
||||
@@ -38,8 +38,10 @@ import { VnetSliderStep as Component } from './VnetSliderStep';
|
||||
type StoryProps = {
|
||||
startVnet: 'success' | 'error' | 'processing';
|
||||
autoStart: boolean;
|
||||
dnsZones: string[];
|
||||
listDnsZones:
|
||||
appDnsZones: string[];
|
||||
clusters: string[];
|
||||
sshConfigured: boolean;
|
||||
fetchStatus:
|
||||
| 'success'
|
||||
| 'error'
|
||||
| 'processing'
|
||||
@@ -51,6 +53,20 @@ type StoryProps = {
|
||||
unexpectedShutdown: boolean;
|
||||
};
|
||||
|
||||
const defaultArgs: StoryProps = {
|
||||
startVnet: 'success',
|
||||
autoStart: true,
|
||||
appDnsZones: ['teleport.example.com', 'company.test'],
|
||||
clusters: ['teleport.example.com'],
|
||||
sshConfigured: false,
|
||||
fetchStatus: 'success',
|
||||
vnetDiag: true,
|
||||
runDiagnostics: 'success',
|
||||
diagReport: 'ok',
|
||||
isWorkspacePresent: true,
|
||||
unexpectedShutdown: false,
|
||||
};
|
||||
|
||||
const meta: Meta<StoryProps> = {
|
||||
title: 'Teleterm/Vnet/VnetSliderStep',
|
||||
component: VnetSliderStep,
|
||||
@@ -68,10 +84,13 @@ const meta: Meta<StoryProps> = {
|
||||
control: { type: 'inline-radio' },
|
||||
options: ['success', 'error', 'processing'],
|
||||
},
|
||||
dnsZones: {
|
||||
appDnsZones: {
|
||||
control: { type: 'object' },
|
||||
},
|
||||
listDnsZones: {
|
||||
clusters: {
|
||||
control: { type: 'object' },
|
||||
},
|
||||
fetchStatus: {
|
||||
control: { type: 'inline-radio' },
|
||||
options: [
|
||||
'success',
|
||||
@@ -93,21 +112,11 @@ const meta: Meta<StoryProps> = {
|
||||
"If there's no workspace, the button to open the diag report is disabled.",
|
||||
},
|
||||
},
|
||||
args: {
|
||||
startVnet: 'success',
|
||||
autoStart: true,
|
||||
dnsZones: ['teleport.example.com', 'company.test'],
|
||||
listDnsZones: 'success',
|
||||
vnetDiag: true,
|
||||
runDiagnostics: 'success',
|
||||
diagReport: 'ok',
|
||||
isWorkspacePresent: true,
|
||||
unexpectedShutdown: false,
|
||||
},
|
||||
render: props => <VnetSliderStep {...props} />,
|
||||
};
|
||||
export default meta;
|
||||
|
||||
export function VnetSliderStep(props: StoryProps) {
|
||||
function VnetSliderStep(props: StoryProps) {
|
||||
const appContext = new MockAppContext({
|
||||
platform: props.vnetDiag ? 'darwin' : 'win32',
|
||||
});
|
||||
@@ -148,22 +157,30 @@ export function VnetSliderStep(props: StoryProps) {
|
||||
};
|
||||
}
|
||||
|
||||
if (props.listDnsZones === 'processing') {
|
||||
appContext.vnet.listDNSZones = () => pendingPromise;
|
||||
if (props.fetchStatus === 'processing') {
|
||||
appContext.vnet.getServiceInfo = () => pendingPromise;
|
||||
} else {
|
||||
let firstCall = true;
|
||||
appContext.vnet.listDNSZones = () => {
|
||||
if (props.listDnsZones === 'processing-with-previous-results') {
|
||||
appContext.vnet.getServiceInfo = () => {
|
||||
if (props.fetchStatus === 'processing-with-previous-results') {
|
||||
if (firstCall) {
|
||||
firstCall = false;
|
||||
return new MockedUnaryCall({ dnsZones: props.dnsZones });
|
||||
return new MockedUnaryCall({
|
||||
appDnsZones: props.appDnsZones,
|
||||
clusters: props.clusters,
|
||||
sshConfigured: props.sshConfigured,
|
||||
});
|
||||
}
|
||||
return pendingPromise;
|
||||
}
|
||||
|
||||
return new MockedUnaryCall(
|
||||
{ dnsZones: props.dnsZones },
|
||||
props.listDnsZones === 'error'
|
||||
{
|
||||
appDnsZones: props.appDnsZones,
|
||||
clusters: props.clusters,
|
||||
sshConfigured: props.sshConfigured,
|
||||
},
|
||||
props.fetchStatus === 'error'
|
||||
? new Error('something went wrong')
|
||||
: undefined
|
||||
);
|
||||
@@ -204,8 +221,8 @@ export function VnetSliderStep(props: StoryProps) {
|
||||
>
|
||||
<ConnectionsContextProvider>
|
||||
<VnetContextProvider>
|
||||
{props.listDnsZones === 'processing-with-previous-results' && (
|
||||
<RerequestDNSZones />
|
||||
{props.fetchStatus === 'processing-with-previous-results' && (
|
||||
<RerequestServiceInfo />
|
||||
)}
|
||||
<Component
|
||||
refCallback={noop}
|
||||
@@ -221,16 +238,73 @@ export function VnetSliderStep(props: StoryProps) {
|
||||
);
|
||||
}
|
||||
|
||||
const RerequestDNSZones = () => {
|
||||
const { listDNSZones, listDNSZonesAttempt } = useVnetContext();
|
||||
const RerequestServiceInfo = () => {
|
||||
const { getServiceInfo, serviceInfoAttempt } = useVnetContext();
|
||||
|
||||
useEffect(() => {
|
||||
if (listDNSZonesAttempt.status === 'success') {
|
||||
listDNSZones();
|
||||
if (serviceInfoAttempt.status === 'success') {
|
||||
getServiceInfo();
|
||||
}
|
||||
}, [listDNSZonesAttempt, listDNSZones]);
|
||||
}, [serviceInfoAttempt, getServiceInfo]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
export const CloudCustomer: StoryObj<StoryProps> = {
|
||||
args: {
|
||||
...defaultArgs,
|
||||
appDnsZones: ['example.teleport.sh'],
|
||||
clusters: ['example.teleport.sh'],
|
||||
},
|
||||
};
|
||||
|
||||
export const SelfHostedWithDifferentClusterName: StoryObj<StoryProps> = {
|
||||
args: {
|
||||
...defaultArgs,
|
||||
appDnsZones: ['teleport.example.com'],
|
||||
clusters: ['teleport-example'],
|
||||
},
|
||||
};
|
||||
|
||||
export const SelfHostedWithEqualNameAndLeaf: StoryObj<StoryProps> = {
|
||||
args: {
|
||||
...defaultArgs,
|
||||
appDnsZones: ['teleport.example.com', 'leaf.example.com'],
|
||||
clusters: ['teleport.example.com', 'leaf.example.com'],
|
||||
},
|
||||
};
|
||||
|
||||
export const SelfHostedWithEqualNameAndDifferentLeaf: StoryObj<StoryProps> = {
|
||||
args: {
|
||||
...defaultArgs,
|
||||
appDnsZones: ['teleport.example.com', 'leaf.example.com'],
|
||||
clusters: ['teleport.example.com', 'teleport-leaf'],
|
||||
},
|
||||
};
|
||||
|
||||
export const SelfHostedWithEqualNameAndCustomDNSZones: StoryObj<StoryProps> = {
|
||||
args: {
|
||||
...defaultArgs,
|
||||
appDnsZones: ['teleport.example.com', 'company.com', 'apps.company'],
|
||||
clusters: ['teleport.example.com'],
|
||||
},
|
||||
};
|
||||
|
||||
export const SelfHostedWithManyLeavesAndZones: StoryObj<StoryProps> = {
|
||||
args: {
|
||||
...defaultArgs,
|
||||
appDnsZones: [
|
||||
'teleport.example.com',
|
||||
'leaf.example.com',
|
||||
'second-leaf.example.com',
|
||||
'company.com',
|
||||
],
|
||||
clusters: [
|
||||
'teleport.example.com',
|
||||
'teleport-leaf',
|
||||
'second-leaf.example.com',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -24,6 +24,7 @@ import { useRefAutoFocus } from 'shared/hooks';
|
||||
import { useDelayedRepeatedAttempt } from 'shared/hooks/useAsync';
|
||||
import { mergeRefs } from 'shared/libs/mergeRefs';
|
||||
|
||||
import { ConnectionKindIndicator } from 'teleterm/ui/TopBar/Connections/ConnectionsFilterableList/ConnectionItem';
|
||||
import { ConnectionStatusIndicator } from 'teleterm/ui/TopBar/Connections/ConnectionsFilterableList/ConnectionStatusIndicator';
|
||||
|
||||
import { DiagnosticsAlert } from './DiagnosticsAlert';
|
||||
@@ -104,18 +105,19 @@ export const VnetSliderStep = (props: StepComponentProps) => {
|
||||
) : (
|
||||
<Flex flexDirection="column" gap={1}>
|
||||
<Text>
|
||||
VNet enables any program to connect to TCP apps protected by
|
||||
Teleport.
|
||||
VNet enables any program to connect to TCP apps or SSH servers
|
||||
protected by Teleport.
|
||||
</Text>
|
||||
<Text>
|
||||
Start VNet and connect to any TCP app over its public address –
|
||||
VNet authenticates the connection for you under the hood.
|
||||
Start VNet and connect to any TCP app or SSH server at its own
|
||||
DNS address – VNet authenticates the connection for you under
|
||||
the hood.
|
||||
</Text>
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
|
||||
{status.value === 'running' && <DnsZones />}
|
||||
{status.value === 'running' && <VnetStatus />}
|
||||
|
||||
<DiagnosticsAlert
|
||||
runDiagnosticsFromVnetPanel={runDiagnosticsFromVnetPanel}
|
||||
@@ -132,41 +134,39 @@ const ErrorText = (props: PropsWithChildren) => (
|
||||
);
|
||||
|
||||
/**
|
||||
* DnsZones displays the list of currently proxied DNS zones, as understood by the VNet admin
|
||||
* process. The list is cached in the context and updated when the VNet panel gets opened.
|
||||
* VnetStatus displays the status of the running VNet service. The list is cached in the context and
|
||||
* updated when the VNet panel gets opened.
|
||||
*
|
||||
* As for 95% of users the list will never change during the lifespan of VNet, the VNet panel always
|
||||
* optimistically displays previously fetched results while fetching new list.
|
||||
*/
|
||||
const DnsZones = () => {
|
||||
const { listDNSZones, listDNSZonesAttempt: eagerListDNSZonesAttempt } =
|
||||
const VnetStatus = () => {
|
||||
const { getServiceInfo, serviceInfoAttempt: eagerServiceInfoAttempt } =
|
||||
useVnetContext();
|
||||
const listDNSZonesAttempt = useDelayedRepeatedAttempt(
|
||||
eagerListDNSZonesAttempt
|
||||
);
|
||||
const dnsZonesRefreshRequestedRef = useRef(false);
|
||||
const serviceInfoAttempt = useDelayedRepeatedAttempt(eagerServiceInfoAttempt);
|
||||
const serviceInfoRefreshRequestedRef = useRef(false);
|
||||
|
||||
useEffect(
|
||||
function refreshListOnOpen() {
|
||||
if (!dnsZonesRefreshRequestedRef.current) {
|
||||
dnsZonesRefreshRequestedRef.current = true;
|
||||
listDNSZones();
|
||||
if (!serviceInfoRefreshRequestedRef.current) {
|
||||
serviceInfoRefreshRequestedRef.current = true;
|
||||
getServiceInfo();
|
||||
}
|
||||
},
|
||||
[listDNSZones]
|
||||
[getServiceInfo]
|
||||
);
|
||||
|
||||
if (listDNSZonesAttempt.status === 'error') {
|
||||
if (serviceInfoAttempt.status === 'error') {
|
||||
return (
|
||||
<Text p={textSpacing}>
|
||||
<ConnectionStatusIndicator status="warning" inline mr={2} />
|
||||
VNet is working, but Teleport Connect could not fetch DNS zones:{' '}
|
||||
{listDNSZonesAttempt.statusText}
|
||||
VNet is running, but Teleport Connect could not fetch its status:{' '}
|
||||
{serviceInfoAttempt.statusText}
|
||||
<ButtonSecondary
|
||||
ml={2}
|
||||
size="small"
|
||||
type="button"
|
||||
onClick={listDNSZones}
|
||||
onClick={getServiceInfo}
|
||||
>
|
||||
Retry
|
||||
</ButtonSecondary>
|
||||
@@ -175,36 +175,100 @@ const DnsZones = () => {
|
||||
}
|
||||
|
||||
if (
|
||||
listDNSZonesAttempt.status === '' ||
|
||||
(listDNSZonesAttempt.status === 'processing' && !listDNSZonesAttempt.data)
|
||||
serviceInfoAttempt.status === '' ||
|
||||
(serviceInfoAttempt.status === 'processing' && !serviceInfoAttempt.data)
|
||||
) {
|
||||
return (
|
||||
<Text p={textSpacing}>
|
||||
<ConnectionStatusIndicator status="processing" inline mr={2} />
|
||||
Updating the list of DNS zones…
|
||||
Updating VNet status…
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
const dnsZones = listDNSZonesAttempt.data;
|
||||
const statusIndicator = (
|
||||
<ConnectionStatusIndicator
|
||||
status={serviceInfoAttempt.status === 'success' ? 'on' : 'processing'}
|
||||
title={
|
||||
serviceInfoAttempt.status === 'processing'
|
||||
? 'Updating VNet status…'
|
||||
: undefined
|
||||
}
|
||||
inline
|
||||
mr={2}
|
||||
mt={2}
|
||||
/>
|
||||
);
|
||||
|
||||
const serviceInfo = serviceInfoAttempt.data;
|
||||
|
||||
const sshConfiguredIndicator = serviceInfo.sshConfigured ? null : (
|
||||
<Flex>
|
||||
<ConnectionStatusIndicator status={'warning'} inline mr={2} />
|
||||
SSH clients are not configured to use VNet (see diag report).
|
||||
</Flex>
|
||||
);
|
||||
|
||||
if (serviceInfo.appDnsZones.length == 0 && serviceInfo.clusters.length == 0) {
|
||||
return (
|
||||
<Flex p={textSpacing}>
|
||||
{statusIndicator}
|
||||
No clusters connected yet, VNet is not proxying any connections.
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
const appDNSZones = new Set(serviceInfo.appDnsZones);
|
||||
const sshClusters = new Set(serviceInfo.clusters);
|
||||
const appAndSshAreEqual =
|
||||
appDNSZones.size == sshClusters.size && appDNSZones.isSubsetOf(sshClusters);
|
||||
|
||||
if (appAndSshAreEqual) {
|
||||
return (
|
||||
<Text p={textSpacing}>
|
||||
<Flex>
|
||||
{statusIndicator}
|
||||
Proxying TCP and SSH connections to {[...appDNSZones].join(', ')}
|
||||
</Flex>
|
||||
{sshConfiguredIndicator}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
const both = [...appDNSZones.intersection(sshClusters)].sort();
|
||||
const justTCP = [...appDNSZones.difference(sshClusters)].sort();
|
||||
const justSSH = [...sshClusters.difference(appDNSZones)].sort();
|
||||
|
||||
return (
|
||||
<Text p={textSpacing}>
|
||||
<ConnectionStatusIndicator
|
||||
status={listDNSZonesAttempt.status === 'success' ? 'on' : 'processing'}
|
||||
title={
|
||||
listDNSZonesAttempt.status === 'processing'
|
||||
? 'Updating the list of DNS zones…'
|
||||
: undefined
|
||||
}
|
||||
inline
|
||||
mr={2}
|
||||
/>
|
||||
{dnsZones.length === 0 ? (
|
||||
<>No clusters connected yet, VNet is not proxying any connections.</>
|
||||
) : (
|
||||
<>Proxying TCP connections to {dnsZones.join(', ')}</>
|
||||
)}
|
||||
</Text>
|
||||
<Box p={textSpacing}>
|
||||
<Flex>
|
||||
{statusIndicator}
|
||||
<Box>
|
||||
Proxying TCP and SSH connections to:
|
||||
<Text typography="body2">
|
||||
{both.length ? (
|
||||
<Box>
|
||||
<ConnectionKindIndicator bold>TCP</ConnectionKindIndicator>
|
||||
<ConnectionKindIndicator bold>SSH</ConnectionKindIndicator>
|
||||
{both.join(', ')}
|
||||
</Box>
|
||||
) : null}
|
||||
{justTCP.length ? (
|
||||
<Box>
|
||||
<ConnectionKindIndicator bold>TCP</ConnectionKindIndicator>
|
||||
{justTCP.join(', ')}
|
||||
</Box>
|
||||
) : null}
|
||||
{justSSH.length ? (
|
||||
<Box>
|
||||
<ConnectionKindIndicator bold>SSH</ConnectionKindIndicator>
|
||||
{justSSH.join(', ')}
|
||||
</Box>
|
||||
) : null}
|
||||
</Text>
|
||||
</Box>
|
||||
</Flex>
|
||||
{sshConfiguredIndicator}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -88,9 +88,11 @@ test.each(tests)(
|
||||
clusters: [rootCluster],
|
||||
})
|
||||
);
|
||||
jest.spyOn(ctx.vnet, 'listDNSZones').mockReturnValue(
|
||||
jest.spyOn(ctx.vnet, 'getServiceInfo').mockReturnValue(
|
||||
new MockedUnaryCall({
|
||||
dnsZones: [proxyHostname(rootCluster.proxyHost)],
|
||||
appDnsZones: [proxyHostname(rootCluster.proxyHost)],
|
||||
clusters: [rootCluster.name],
|
||||
sshConfigured: true,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -120,7 +122,7 @@ test.each(tests)(
|
||||
).toBeInTheDocument();
|
||||
await user.click(within(docVnetInfo).getByText('Start VNet'));
|
||||
expect(
|
||||
await screen.findByText(/Proxying TCP connections/)
|
||||
await screen.findByText(/Proxying TCP and SSH connections/)
|
||||
).toBeInTheDocument();
|
||||
|
||||
// Verify that a notification is shown and that the address is in the clipboard.
|
||||
@@ -141,7 +143,7 @@ test.each(tests)(
|
||||
await user.click(within(docVnetInfo).getByText('Stop VNet'));
|
||||
await user.click(await within(docVnetInfo).findByText('Start VNet'));
|
||||
expect(
|
||||
await screen.findByText(/Proxying TCP connections/)
|
||||
await screen.findByText(/Proxying TCP and SSH connections/)
|
||||
).toBeInTheDocument();
|
||||
|
||||
// Verify that the address was not copied to the clipboard after the second start from the "Start
|
||||
@@ -182,9 +184,11 @@ test.each(tests)(
|
||||
clusters: [rootCluster],
|
||||
})
|
||||
);
|
||||
jest.spyOn(ctx.vnet, 'listDNSZones').mockReturnValue(
|
||||
jest.spyOn(ctx.vnet, 'getServiceInfo').mockReturnValue(
|
||||
new MockedUnaryCall({
|
||||
dnsZones: [proxyHostname(rootCluster.proxyHost)],
|
||||
appDnsZones: [proxyHostname(rootCluster.proxyHost)],
|
||||
clusters: [rootCluster.name],
|
||||
sshConfigured: true,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -209,7 +213,7 @@ test.each(tests)(
|
||||
|
||||
// Verify that VNet is running and that the public address was copied to the clipboard.
|
||||
expect(
|
||||
await screen.findByText(/Proxying TCP connections/)
|
||||
await screen.findByText(/Proxying TCP and SSH connections/)
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
await screen.findByText(
|
||||
@@ -241,9 +245,11 @@ test('launching VNet for the first time from the connections panel does not open
|
||||
clusters: [rootCluster],
|
||||
})
|
||||
);
|
||||
jest.spyOn(ctx.vnet, 'listDNSZones').mockReturnValue(
|
||||
jest.spyOn(ctx.vnet, 'getServiceInfo').mockReturnValue(
|
||||
new MockedUnaryCall({
|
||||
dnsZones: [proxyHostname(rootCluster.proxyHost)],
|
||||
appDnsZones: [proxyHostname(rootCluster.proxyHost)],
|
||||
clusters: [rootCluster.name],
|
||||
sshConfigured: true,
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -28,7 +28,10 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { BackgroundItemStatus } from 'gen-proto-ts/teleport/lib/teleterm/vnet/v1/vnet_service_pb';
|
||||
import {
|
||||
BackgroundItemStatus,
|
||||
GetServiceInfoResponse,
|
||||
} from 'gen-proto-ts/teleport/lib/teleterm/vnet/v1/vnet_service_pb';
|
||||
import { Report } from 'gen-proto-ts/teleport/lib/vnet/diag/v1/diag_pb';
|
||||
import { useStateRef } from 'shared/hooks';
|
||||
import { Attempt, makeEmptyAttempt, useAsync } from 'shared/hooks/useAsync';
|
||||
@@ -60,8 +63,8 @@ export type VnetContext = {
|
||||
startAttempt: Attempt<void>;
|
||||
stop: () => Promise<[void, Error]>;
|
||||
stopAttempt: Attempt<void>;
|
||||
listDNSZones: () => Promise<[string[], Error]>;
|
||||
listDNSZonesAttempt: Attempt<string[]>;
|
||||
getServiceInfo: () => Promise<[GetServiceInfoResponse, Error]>;
|
||||
serviceInfoAttempt: Attempt<GetServiceInfoResponse>;
|
||||
runDiagnostics: () => Promise<[Report, Error]>;
|
||||
diagnosticsAttempt: Attempt<Report>;
|
||||
/**
|
||||
@@ -234,9 +237,9 @@ export const VnetContextProvider: FC<
|
||||
])
|
||||
);
|
||||
|
||||
const [listDNSZonesAttempt, listDNSZones] = useAsync(
|
||||
const [serviceInfoAttempt, getServiceInfo] = useAsync(
|
||||
useCallback(
|
||||
() => vnet.listDNSZones({}).then(({ response }) => response.dnsZones),
|
||||
() => vnet.getServiceInfo({}).then(({ response }) => response),
|
||||
[vnet]
|
||||
)
|
||||
);
|
||||
@@ -469,8 +472,8 @@ export const VnetContextProvider: FC<
|
||||
startAttempt,
|
||||
stop,
|
||||
stopAttempt,
|
||||
listDNSZones,
|
||||
listDNSZonesAttempt,
|
||||
getServiceInfo,
|
||||
serviceInfoAttempt,
|
||||
runDiagnostics,
|
||||
diagnosticsAttempt,
|
||||
getDisabledDiagnosticsReason,
|
||||
|
||||
Reference in New Issue
Block a user