From af498eff2041a8e69c956b0307b5bd032b5b7a65 Mon Sep 17 00:00:00 2001 From: Daniel De Vera Date: Mon, 6 Nov 2023 14:16:23 -0300 Subject: [PATCH 01/10] WIP: checkpoint --- internal/command/local/connect.go | 8 +- internal/command/local/printers.go | 75 +--- internal/command/local/status.go | 27 +- internal/command/sandbox/apply.go | 49 ++- .../locald/api/sandboxmanager/api_error.go | 9 - .../sandboxmanager/sandbox_manager_api.pb.go | 350 ++++-------------- .../sandboxmanager/sandbox_manager_api.proto | 25 -- .../sandbox_manager_api_grpc.pb.go | 47 +-- internal/locald/sandboxmanager/apply.go | 52 --- .../locald/sandboxmanager/sandbox_monitor.go | 3 +- .../locald/sandboxmanager/sandbox_server.go | 106 +++--- internal/locald/sandboxmanager/sdk.go | 119 ++++++ 12 files changed, 302 insertions(+), 568 deletions(-) delete mode 100644 internal/locald/api/sandboxmanager/api_error.go delete mode 100644 internal/locald/sandboxmanager/apply.go create mode 100644 internal/locald/sandboxmanager/sdk.go diff --git a/internal/command/local/connect.go b/internal/command/local/connect.go index 9ab6451..7706776 100644 --- a/internal/command/local/connect.go +++ b/internal/command/local/connect.go @@ -10,14 +10,16 @@ import ( "path/filepath" "time" + "log/slog" + "github.com/fatih/color" "github.com/signadot/cli/internal/config" sbmapi "github.com/signadot/cli/internal/locald/api/sandboxmanager" + sbmgr "github.com/signadot/cli/internal/locald/sandboxmanager" "github.com/signadot/cli/internal/utils/system" "github.com/signadot/libconnect/common/processes" "github.com/spf13/cobra" "github.com/spf13/viper" - "log/slog" "sigs.k8s.io/yaml" ) @@ -192,7 +194,7 @@ func waitConnect(localConfig *config.LocalConnect, out io.Writer) error { ) defer ticker.Stop() for { - status, err = getStatus() + status, err := sbmgr.GetStatus() if err != nil { fmt.Fprintf(out, "error getting status: %s", err.Error()) connectErrs = []error{err} @@ -204,7 +206,7 @@ func waitConnect(localConfig *config.LocalConnect, out io.Writer) error { goto tick } - connectErrs = checkLocalStatusConnectErrors(ciConfig, status) + connectErrs = sbmgr.CheckStatusConnectErrors(status, ciConfig) if len(connectErrs) == 0 { break } diff --git a/internal/command/local/printers.go b/internal/command/local/printers.go index 17ebdba..3b4d0c7 100644 --- a/internal/command/local/printers.go +++ b/internal/command/local/printers.go @@ -8,6 +8,7 @@ import ( "github.com/signadot/cli/internal/config" commonapi "github.com/signadot/cli/internal/locald/api" sbmapi "github.com/signadot/cli/internal/locald/api/sandboxmanager" + sbmgr "github.com/signadot/cli/internal/locald/sandboxmanager" connectcfg "github.com/signadot/libconnect/config" ) @@ -16,7 +17,7 @@ func printRawStatus(cfg *config.LocalStatus, out io.Writer, printer func(out io. // unmarshal the ci config ciConfig, err := sbmapi.ToCIConfig(status.CiConfig) if err != nil { - return fmt.Errorf("couldn't unmarshal ci-config from sandbox manager status, %v", err) + return fmt.Errorf("couldn't unmarshal ci-config from sandboxmanager status, %v", err) } // convert the status into a map (useful to convert snake-case fields to camel-case, @@ -237,37 +238,12 @@ func getRawPortforward(cfg *config.LocalStatus, ciConfig *config.ConnectInvocati return result } -func checkLocalStatusConnectErrors(ciConfig *config.ConnectInvocationConfig, status *sbmapi.StatusResponse) []error { - var errs []error - // check port forward status - if ciConfig.ConnectionConfig.Type == connectcfg.PortForwardLinkType { - err := checkPortforwardStatus(status.Portforward) - if err != nil { - errs = append(errs, err) - } - } - // check root manager (if running) - if ciConfig.WithRootManager { - // check localnet service - err := checkLocalNetStatus(status.Localnet) - if err != nil { - errs = append(errs, err) - } - // check hosts service - err = checkHostsStatus(status.Hosts) - if err != nil { - errs = append(errs, err) - } - } - return errs -} - func printLocalStatus(cfg *config.LocalStatus, out io.Writer, status *sbmapi.StatusResponse) error { ciConfig, err := sbmapi.ToCIConfig(status.CiConfig) if err != nil { return fmt.Errorf("couldn't unmarshal ci-config from sandbox manager status, %v", err) } - connectErrs := checkLocalStatusConnectErrors(ciConfig, status) + connectErrs := sbmgr.CheckStatusConnectErrors(status, ciConfig) // create a printer printer := statusPrinter{ @@ -290,51 +266,6 @@ func printLocalStatus(cfg *config.LocalStatus, out io.Writer, status *sbmapi.Sta return nil } -func checkPortforwardStatus(portforward *commonapi.PortForwardStatus) error { - errorMsg := "failed to establish port-forward" - if portforward != nil { - if portforward.Health != nil { - if portforward.Health.Healthy { - return nil - } - if portforward.Health.LastErrorReason != "" { - errorMsg += fmt.Sprintf(" (%q)", portforward.Health.LastErrorReason) - } - } - } - return fmt.Errorf(errorMsg) -} - -func checkLocalNetStatus(localnet *commonapi.LocalNetStatus) error { - errorMsg := "failed to setup localnet" - if localnet != nil { - if localnet.Health != nil { - if localnet.Health.Healthy { - return nil - } - if localnet.Health.LastErrorReason != "" { - errorMsg += fmt.Sprintf(" (%q)", localnet.Health.LastErrorReason) - } - } - } - return fmt.Errorf(errorMsg) -} - -func checkHostsStatus(hosts *commonapi.HostsStatus) error { - errorMsg := "failed to configure hosts in /etc/hosts" - if hosts != nil { - if hosts.Health != nil { - if hosts.Health.Healthy { - return nil - } - if hosts.Health.LastErrorReason != "" { - errorMsg += fmt.Sprintf(" (%q)", hosts.Health.LastErrorReason) - } - } - } - return fmt.Errorf(errorMsg) -} - type statusPrinter struct { cfg *config.LocalStatus status *sbmapi.StatusResponse diff --git a/internal/command/local/status.go b/internal/command/local/status.go index 6bdd983..f161f02 100644 --- a/internal/command/local/status.go +++ b/internal/command/local/status.go @@ -1,19 +1,16 @@ package local import ( - "context" "fmt" "io" "path/filepath" "github.com/signadot/cli/internal/config" - sbmapi "github.com/signadot/cli/internal/locald/api/sandboxmanager" + sbmgr "github.com/signadot/cli/internal/locald/sandboxmanager" "github.com/signadot/cli/internal/print" "github.com/signadot/cli/internal/utils/system" "github.com/signadot/libconnect/common/processes" "github.com/spf13/cobra" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" ) func newStatus(localConfig *config.Local) *cobra.Command { @@ -50,10 +47,11 @@ func runStatus(cfg *config.LocalStatus, out io.Writer, args []string) error { if !isRunning { return fmt.Errorf("signadot is not connected\n") } - status, err := getStatus() + // Get the status from sandbox manager + status, err := sbmgr.GetStatus() if err != nil { - return fmt.Errorf("couldn't get status from sandbox manager api: %w", err) + return err } switch cfg.OutputFormat { @@ -67,20 +65,3 @@ func runStatus(cfg *config.LocalStatus, out io.Writer, args []string) error { return fmt.Errorf("unsupported output format: %q", cfg.OutputFormat) } } - -func getStatus() (*sbmapi.StatusResponse, error) { - // Get a sandbox manager API client - grpcConn, err := grpc.Dial("127.0.0.1:6666", grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - return nil, fmt.Errorf("couldn't connect sandbox manager api: %w", err) - } - defer grpcConn.Close() - - // get the status - sbManagerClient := sbmapi.NewSandboxManagerAPIClient(grpcConn) - status, err := sbManagerClient.Status(context.Background(), &sbmapi.StatusRequest{}) - if err != nil { - return nil, fmt.Errorf("couldn't get status from sandbox manager api: %w", err) - } - return status, nil -} diff --git a/internal/command/sandbox/apply.go b/internal/command/sandbox/apply.go index 6d7e301..596f24f 100644 --- a/internal/command/sandbox/apply.go +++ b/internal/command/sandbox/apply.go @@ -1,13 +1,13 @@ package sandbox import ( - "context" "errors" "fmt" "io" - "time" + "github.com/denisbrodbeck/machineid" "github.com/signadot/cli/internal/config" + sbmapi "github.com/signadot/cli/internal/locald/api/sandboxmanager" sbmgr "github.com/signadot/cli/internal/locald/sandboxmanager" "github.com/signadot/cli/internal/poll" "github.com/signadot/cli/internal/print" @@ -39,30 +39,51 @@ func apply(cfg *config.SandboxApply, out, log io.Writer, args []string) error { if cfg.Filename == "" { return errors.New("must specify sandbox request file with '-f' flag") } + + // Load the sandbox spec req, err := loadSandbox(cfg.Filename, cfg.TemplateVals, false /*forDelete */) if err != nil { return err } + if req.Spec.Cluster == nil { + return fmt.Errorf("sandbox spec must specify cluster") + } - var resp *models.Sandbox if len(req.Spec.Local) > 0 { - // Send the request to the sandbox manager - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - resp, err = sbmgr.Apply(ctx, cfg.Org, req.Name, req.Spec) + // Confirm sandboxmanager is running and connected to the right cluster + status, err := sbmgr.GetStatus() if err != nil { return err } - } else { - // Send the request directly to the SaaS - params := sandboxes.NewApplySandboxParams(). - WithOrgName(cfg.Org).WithSandboxName(req.Name).WithData(req) - result, err := cfg.Client.Sandboxes.ApplySandbox(params, nil) + ciConfig, err := sbmapi.ToCIConfig(status.CiConfig) if err != nil { - return err + return fmt.Errorf("couldn't unmarshal ci-config from sandboxmanager status, %v", err) + } + connectErrs := sbmgr.CheckStatusConnectErrors(status, ciConfig) + if len(connectErrs) != 0 { + return fmt.Errorf("sandboxmanager is still starting") + } + if *req.Spec.Cluster != ciConfig.ConnectionConfig.Cluster { + return fmt.Errorf("sandbox spec cluster %q does not match connected cluster (%q)", + *req.Spec.Cluster, ciConfig.ConnectionConfig.Cluster) + } + + // Set the local machine ID + machineID, err := machineid.ProtectedID("signadotCLI") + if err != nil { + return fmt.Errorf("couldn't read machine-id, %v", err) } - resp = result.Payload + req.Spec.MachineID = machineID + } + + // Send the request to the SaaS + params := sandboxes.NewApplySandboxParams(). + WithOrgName(cfg.Org).WithSandboxName(req.Name).WithData(req) + result, err := cfg.Client.Sandboxes.ApplySandbox(params, nil) + if err != nil { + return err } + resp := result.Payload fmt.Fprintf(log, "Created sandbox %q (routing key: %s) in cluster %q.\n\n", req.Name, resp.RoutingKey, *req.Spec.Cluster) diff --git a/internal/locald/api/sandboxmanager/api_error.go b/internal/locald/api/sandboxmanager/api_error.go deleted file mode 100644 index dd6f9da..0000000 --- a/internal/locald/api/sandboxmanager/api_error.go +++ /dev/null @@ -1,9 +0,0 @@ -package sandboxmanager - -func APIErrorResponse(err error) *ApplySandboxResponse { - return &ApplySandboxResponse{ - It: &ApplySandboxResponse_ApiError{ - ApiError: err.Error(), - }, - } -} diff --git a/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go b/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go index 1e8c2c5..2febfb0 100644 --- a/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go +++ b/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go @@ -22,145 +22,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -type ApplySandboxRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // sandbox name - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // sandbox spec (instance of github.com/signadot/go-sdk/models.SandboxSpec) - SandboxSpec *_struct.Struct `protobuf:"bytes,2,opt,name=sandbox_spec,json=sandboxSpec,proto3" json:"sandbox_spec,omitempty"` -} - -func (x *ApplySandboxRequest) Reset() { - *x = ApplySandboxRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ApplySandboxRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ApplySandboxRequest) ProtoMessage() {} - -func (x *ApplySandboxRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ApplySandboxRequest.ProtoReflect.Descriptor instead. -func (*ApplySandboxRequest) Descriptor() ([]byte, []int) { - return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZIP(), []int{0} -} - -func (x *ApplySandboxRequest) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *ApplySandboxRequest) GetSandboxSpec() *_struct.Struct { - if x != nil { - return x.SandboxSpec - } - return nil -} - -type ApplySandboxResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to It: - // - // *ApplySandboxResponse_Sandbox - // *ApplySandboxResponse_ApiError - It isApplySandboxResponse_It `protobuf_oneof:"it"` -} - -func (x *ApplySandboxResponse) Reset() { - *x = ApplySandboxResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ApplySandboxResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ApplySandboxResponse) ProtoMessage() {} - -func (x *ApplySandboxResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ApplySandboxResponse.ProtoReflect.Descriptor instead. -func (*ApplySandboxResponse) Descriptor() ([]byte, []int) { - return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZIP(), []int{1} -} - -func (m *ApplySandboxResponse) GetIt() isApplySandboxResponse_It { - if m != nil { - return m.It - } - return nil -} - -func (x *ApplySandboxResponse) GetSandbox() *_struct.Struct { - if x, ok := x.GetIt().(*ApplySandboxResponse_Sandbox); ok { - return x.Sandbox - } - return nil -} - -func (x *ApplySandboxResponse) GetApiError() string { - if x, ok := x.GetIt().(*ApplySandboxResponse_ApiError); ok { - return x.ApiError - } - return "" -} - -type isApplySandboxResponse_It interface { - isApplySandboxResponse_It() -} - -type ApplySandboxResponse_Sandbox struct { - // sandbox (instance of github.com/signadot/go-sdk/models.Sandbox) - Sandbox *_struct.Struct `protobuf:"bytes,1,opt,name=sandbox,proto3,oneof"` -} - -type ApplySandboxResponse_ApiError struct { - ApiError string `protobuf:"bytes,2,opt,name=apiError,proto3,oneof"` -} - -func (*ApplySandboxResponse_Sandbox) isApplySandboxResponse_It() {} - -func (*ApplySandboxResponse_ApiError) isApplySandboxResponse_It() {} - type StatusRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -170,7 +31,7 @@ type StatusRequest struct { func (x *StatusRequest) Reset() { *x = StatusRequest{} if protoimpl.UnsafeEnabled { - mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[2] + mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -183,7 +44,7 @@ func (x *StatusRequest) String() string { func (*StatusRequest) ProtoMessage() {} func (x *StatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[2] + mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -196,7 +57,7 @@ func (x *StatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusRequest.ProtoReflect.Descriptor instead. func (*StatusRequest) Descriptor() ([]byte, []int) { - return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZIP(), []int{2} + return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZIP(), []int{0} } type StatusResponse struct { @@ -216,7 +77,7 @@ type StatusResponse struct { func (x *StatusResponse) Reset() { *x = StatusResponse{} if protoimpl.UnsafeEnabled { - mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[3] + mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -229,7 +90,7 @@ func (x *StatusResponse) String() string { func (*StatusResponse) ProtoMessage() {} func (x *StatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[3] + mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -242,7 +103,7 @@ func (x *StatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusResponse.ProtoReflect.Descriptor instead. func (*StatusResponse) Descriptor() ([]byte, []int) { - return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZIP(), []int{3} + return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZIP(), []int{1} } func (x *StatusResponse) GetCiConfig() *_struct.Struct { @@ -289,7 +150,7 @@ type ShutdownRequest struct { func (x *ShutdownRequest) Reset() { *x = ShutdownRequest{} if protoimpl.UnsafeEnabled { - mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[4] + mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -302,7 +163,7 @@ func (x *ShutdownRequest) String() string { func (*ShutdownRequest) ProtoMessage() {} func (x *ShutdownRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[4] + mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -315,7 +176,7 @@ func (x *ShutdownRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutdownRequest.ProtoReflect.Descriptor instead. func (*ShutdownRequest) Descriptor() ([]byte, []int) { - return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZIP(), []int{4} + return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZIP(), []int{2} } type ShutdownResponse struct { @@ -327,7 +188,7 @@ type ShutdownResponse struct { func (x *ShutdownResponse) Reset() { *x = ShutdownResponse{} if protoimpl.UnsafeEnabled { - mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[5] + mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -340,7 +201,7 @@ func (x *ShutdownResponse) String() string { func (*ShutdownResponse) ProtoMessage() {} func (x *ShutdownResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[5] + mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -353,7 +214,7 @@ func (x *ShutdownResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutdownResponse.ProtoReflect.Descriptor instead. func (*ShutdownResponse) Descriptor() ([]byte, []int) { - return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZIP(), []int{5} + return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZIP(), []int{3} } var File_internal_locald_api_sandboxmanager_sandbox_manager_api_proto protoreflect.FileDescriptor @@ -367,64 +228,45 @@ var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDesc = 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x65, - 0x0a, 0x13, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x0c, 0x73, 0x61, 0x6e, - 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x0b, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, - 0x78, 0x53, 0x70, 0x65, 0x63, 0x22, 0x6f, 0x0a, 0x14, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x61, - 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, - 0x07, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x48, 0x00, 0x52, 0x07, 0x73, 0x61, 0x6e, 0x64, 0x62, - 0x6f, 0x78, 0x12, 0x1c, 0x0a, 0x08, 0x61, 0x70, 0x69, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x61, 0x70, 0x69, 0x45, 0x72, 0x72, 0x6f, 0x72, - 0x42, 0x04, 0x0a, 0x02, 0x69, 0x74, 0x22, 0x0f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xa3, 0x02, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x09, 0x63, 0x69, - 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x08, 0x63, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x12, 0x35, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x6e, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, - 0x6f, 0x63, 0x61, 0x6c, 0x4e, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x08, 0x6c, - 0x6f, 0x63, 0x61, 0x6c, 0x6e, 0x65, 0x74, 0x12, 0x2c, 0x0a, 0x05, 0x68, 0x6f, 0x73, 0x74, 0x73, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x05, - 0x68, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x3e, 0x0a, 0x0b, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x72, - 0x77, 0x61, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x70, 0x69, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, - 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0b, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, - 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x36, 0x0a, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, - 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x22, 0x11, 0x0a, - 0x0f, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x22, 0x12, 0x0a, 0x10, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x8c, 0x02, 0x0a, 0x11, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, - 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x41, 0x50, 0x49, 0x12, 0x5b, 0x0a, 0x0c, 0x41, 0x70, - 0x70, 0x6c, 0x79, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x12, 0x23, 0x2e, 0x73, 0x61, 0x6e, - 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, 0x6c, - 0x79, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x24, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x1d, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1e, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x08, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1f, - 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, - 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x20, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x42, 0x3c, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x0f, + 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0xa3, 0x02, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x34, 0x0a, 0x09, 0x63, 0x69, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x08, + 0x63, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x6e, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x70, 0x69, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4e, 0x65, 0x74, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x6e, 0x65, 0x74, 0x12, + 0x2c, 0x0a, 0x05, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x05, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x3e, 0x0a, + 0x0b, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, + 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x0b, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x36, 0x0a, + 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x61, 0x6e, + 0x64, 0x62, 0x6f, 0x78, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x65, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x53, 0x68, 0x75, 0x74, + 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xaf, 0x01, 0x0a, + 0x11, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x41, + 0x50, 0x49, 0x12, 0x49, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x2e, 0x73, + 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x61, + 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4f, 0x0a, + 0x08, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1f, 0x2e, 0x73, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, + 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x61, 0x6e, + 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x68, 0x75, 0x74, + 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x3c, + 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x61, + 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -439,39 +281,33 @@ func file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZ return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescData } -var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_goTypes = []interface{}{ - (*ApplySandboxRequest)(nil), // 0: sandboxmanager.ApplySandboxRequest - (*ApplySandboxResponse)(nil), // 1: sandboxmanager.ApplySandboxResponse - (*StatusRequest)(nil), // 2: sandboxmanager.StatusRequest - (*StatusResponse)(nil), // 3: sandboxmanager.StatusResponse - (*ShutdownRequest)(nil), // 4: sandboxmanager.ShutdownRequest - (*ShutdownResponse)(nil), // 5: sandboxmanager.ShutdownResponse - (*_struct.Struct)(nil), // 6: google.protobuf.Struct - (*api.LocalNetStatus)(nil), // 7: apicommon.LocalNetStatus - (*api.HostsStatus)(nil), // 8: apicommon.HostsStatus - (*api.PortForwardStatus)(nil), // 9: apicommon.PortForwardStatus - (*api.SandboxStatus)(nil), // 10: apicommon.SandboxStatus + (*StatusRequest)(nil), // 0: sandboxmanager.StatusRequest + (*StatusResponse)(nil), // 1: sandboxmanager.StatusResponse + (*ShutdownRequest)(nil), // 2: sandboxmanager.ShutdownRequest + (*ShutdownResponse)(nil), // 3: sandboxmanager.ShutdownResponse + (*_struct.Struct)(nil), // 4: google.protobuf.Struct + (*api.LocalNetStatus)(nil), // 5: apicommon.LocalNetStatus + (*api.HostsStatus)(nil), // 6: apicommon.HostsStatus + (*api.PortForwardStatus)(nil), // 7: apicommon.PortForwardStatus + (*api.SandboxStatus)(nil), // 8: apicommon.SandboxStatus } var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_depIdxs = []int32{ - 6, // 0: sandboxmanager.ApplySandboxRequest.sandbox_spec:type_name -> google.protobuf.Struct - 6, // 1: sandboxmanager.ApplySandboxResponse.sandbox:type_name -> google.protobuf.Struct - 6, // 2: sandboxmanager.StatusResponse.ci_config:type_name -> google.protobuf.Struct - 7, // 3: sandboxmanager.StatusResponse.localnet:type_name -> apicommon.LocalNetStatus - 8, // 4: sandboxmanager.StatusResponse.hosts:type_name -> apicommon.HostsStatus - 9, // 5: sandboxmanager.StatusResponse.portforward:type_name -> apicommon.PortForwardStatus - 10, // 6: sandboxmanager.StatusResponse.sandboxes:type_name -> apicommon.SandboxStatus - 0, // 7: sandboxmanager.SandboxManagerAPI.ApplySandbox:input_type -> sandboxmanager.ApplySandboxRequest - 2, // 8: sandboxmanager.SandboxManagerAPI.Status:input_type -> sandboxmanager.StatusRequest - 4, // 9: sandboxmanager.SandboxManagerAPI.Shutdown:input_type -> sandboxmanager.ShutdownRequest - 1, // 10: sandboxmanager.SandboxManagerAPI.ApplySandbox:output_type -> sandboxmanager.ApplySandboxResponse - 3, // 11: sandboxmanager.SandboxManagerAPI.Status:output_type -> sandboxmanager.StatusResponse - 5, // 12: sandboxmanager.SandboxManagerAPI.Shutdown:output_type -> sandboxmanager.ShutdownResponse - 10, // [10:13] is the sub-list for method output_type - 7, // [7:10] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 4, // 0: sandboxmanager.StatusResponse.ci_config:type_name -> google.protobuf.Struct + 5, // 1: sandboxmanager.StatusResponse.localnet:type_name -> apicommon.LocalNetStatus + 6, // 2: sandboxmanager.StatusResponse.hosts:type_name -> apicommon.HostsStatus + 7, // 3: sandboxmanager.StatusResponse.portforward:type_name -> apicommon.PortForwardStatus + 8, // 4: sandboxmanager.StatusResponse.sandboxes:type_name -> apicommon.SandboxStatus + 0, // 5: sandboxmanager.SandboxManagerAPI.Status:input_type -> sandboxmanager.StatusRequest + 2, // 6: sandboxmanager.SandboxManagerAPI.Shutdown:input_type -> sandboxmanager.ShutdownRequest + 1, // 7: sandboxmanager.SandboxManagerAPI.Status:output_type -> sandboxmanager.StatusResponse + 3, // 8: sandboxmanager.SandboxManagerAPI.Shutdown:output_type -> sandboxmanager.ShutdownResponse + 7, // [7:9] is the sub-list for method output_type + 5, // [5:7] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name } func init() { file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_init() } @@ -481,30 +317,6 @@ func file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_init() { } if !protoimpl.UnsafeEnabled { file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplySandboxRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplySandboxResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StatusRequest); i { case 0: return &v.state @@ -516,7 +328,7 @@ func file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_init() { return nil } } - file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StatusResponse); i { case 0: return &v.state @@ -528,7 +340,7 @@ func file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_init() { return nil } } - file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ShutdownRequest); i { case 0: return &v.state @@ -540,7 +352,7 @@ func file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_init() { return nil } } - file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ShutdownResponse); i { case 0: return &v.state @@ -553,17 +365,13 @@ func file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_init() { } } } - file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[1].OneofWrappers = []interface{}{ - (*ApplySandboxResponse_Sandbox)(nil), - (*ApplySandboxResponse_ApiError)(nil), - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDesc, NumEnums: 0, - NumMessages: 6, + NumMessages: 4, NumExtensions: 0, NumServices: 1, }, diff --git a/internal/locald/api/sandboxmanager/sandbox_manager_api.proto b/internal/locald/api/sandboxmanager/sandbox_manager_api.proto index 309a52a..5164a18 100644 --- a/internal/locald/api/sandboxmanager/sandbox_manager_api.proto +++ b/internal/locald/api/sandboxmanager/sandbox_manager_api.proto @@ -9,12 +9,6 @@ package sandboxmanager; service SandboxManagerAPI { - // This method is used to create a sandbox with local references. - // The local controller (signadot local connect) should be running, - // otherwise it will return an error - rpc ApplySandbox(ApplySandboxRequest) returns (ApplySandboxResponse) {} - - // This method returns the status of the local controller rpc Status(StatusRequest) returns (StatusResponse) {} @@ -22,25 +16,6 @@ service SandboxManagerAPI { rpc Shutdown(ShutdownRequest) returns (ShutdownResponse) {} } -// ApplySandbox -// ---------------------------------------------------------------------------- - -message ApplySandboxRequest { - // sandbox name - string name = 1; - // sandbox spec (instance of github.com/signadot/go-sdk/models.SandboxSpec) - google.protobuf.Struct sandbox_spec = 2; -} - -message ApplySandboxResponse { - oneof it { - // sandbox (instance of github.com/signadot/go-sdk/models.Sandbox) - google.protobuf.Struct sandbox = 1; - - string apiError = 2; - } -} - // Status // ---------------------------------------------------------------------------- diff --git a/internal/locald/api/sandboxmanager/sandbox_manager_api_grpc.pb.go b/internal/locald/api/sandboxmanager/sandbox_manager_api_grpc.pb.go index 015500d..2345794 100644 --- a/internal/locald/api/sandboxmanager/sandbox_manager_api_grpc.pb.go +++ b/internal/locald/api/sandboxmanager/sandbox_manager_api_grpc.pb.go @@ -19,19 +19,14 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - SandboxManagerAPI_ApplySandbox_FullMethodName = "/sandboxmanager.SandboxManagerAPI/ApplySandbox" - SandboxManagerAPI_Status_FullMethodName = "/sandboxmanager.SandboxManagerAPI/Status" - SandboxManagerAPI_Shutdown_FullMethodName = "/sandboxmanager.SandboxManagerAPI/Shutdown" + SandboxManagerAPI_Status_FullMethodName = "/sandboxmanager.SandboxManagerAPI/Status" + SandboxManagerAPI_Shutdown_FullMethodName = "/sandboxmanager.SandboxManagerAPI/Shutdown" ) // SandboxManagerAPIClient is the client API for SandboxManagerAPI service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type SandboxManagerAPIClient interface { - // This method is used to create a sandbox with local references. - // The local controller (signadot local connect) should be running, - // otherwise it will return an error - ApplySandbox(ctx context.Context, in *ApplySandboxRequest, opts ...grpc.CallOption) (*ApplySandboxResponse, error) // This method returns the status of the local controller Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) // This method requests the root controller to shutdown @@ -46,15 +41,6 @@ func NewSandboxManagerAPIClient(cc grpc.ClientConnInterface) SandboxManagerAPICl return &sandboxManagerAPIClient{cc} } -func (c *sandboxManagerAPIClient) ApplySandbox(ctx context.Context, in *ApplySandboxRequest, opts ...grpc.CallOption) (*ApplySandboxResponse, error) { - out := new(ApplySandboxResponse) - err := c.cc.Invoke(ctx, SandboxManagerAPI_ApplySandbox_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *sandboxManagerAPIClient) Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) { out := new(StatusResponse) err := c.cc.Invoke(ctx, SandboxManagerAPI_Status_FullMethodName, in, out, opts...) @@ -77,10 +63,6 @@ func (c *sandboxManagerAPIClient) Shutdown(ctx context.Context, in *ShutdownRequ // All implementations must embed UnimplementedSandboxManagerAPIServer // for forward compatibility type SandboxManagerAPIServer interface { - // This method is used to create a sandbox with local references. - // The local controller (signadot local connect) should be running, - // otherwise it will return an error - ApplySandbox(context.Context, *ApplySandboxRequest) (*ApplySandboxResponse, error) // This method returns the status of the local controller Status(context.Context, *StatusRequest) (*StatusResponse, error) // This method requests the root controller to shutdown @@ -92,9 +74,6 @@ type SandboxManagerAPIServer interface { type UnimplementedSandboxManagerAPIServer struct { } -func (UnimplementedSandboxManagerAPIServer) ApplySandbox(context.Context, *ApplySandboxRequest) (*ApplySandboxResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method ApplySandbox not implemented") -} func (UnimplementedSandboxManagerAPIServer) Status(context.Context, *StatusRequest) (*StatusResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Status not implemented") } @@ -114,24 +93,6 @@ func RegisterSandboxManagerAPIServer(s grpc.ServiceRegistrar, srv SandboxManager s.RegisterService(&SandboxManagerAPI_ServiceDesc, srv) } -func _SandboxManagerAPI_ApplySandbox_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ApplySandboxRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(SandboxManagerAPIServer).ApplySandbox(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: SandboxManagerAPI_ApplySandbox_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(SandboxManagerAPIServer).ApplySandbox(ctx, req.(*ApplySandboxRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _SandboxManagerAPI_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(StatusRequest) if err := dec(in); err != nil { @@ -175,10 +136,6 @@ var SandboxManagerAPI_ServiceDesc = grpc.ServiceDesc{ ServiceName: "sandboxmanager.SandboxManagerAPI", HandlerType: (*SandboxManagerAPIServer)(nil), Methods: []grpc.MethodDesc{ - { - MethodName: "ApplySandbox", - Handler: _SandboxManagerAPI_ApplySandbox_Handler, - }, { MethodName: "Status", Handler: _SandboxManagerAPI_Status_Handler, diff --git a/internal/locald/sandboxmanager/apply.go b/internal/locald/sandboxmanager/apply.go deleted file mode 100644 index 30947ee..0000000 --- a/internal/locald/sandboxmanager/apply.go +++ /dev/null @@ -1,52 +0,0 @@ -package sandboxmanager - -import ( - "context" - "errors" - "fmt" - - sbmgrapi "github.com/signadot/cli/internal/locald/api/sandboxmanager" - "github.com/signadot/go-sdk/models" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/status" -) - -// Apply is for client parts of the cli (everything else in locald is -// server/daemon side) -func Apply(ctx context.Context, org, name string, spec *models.SandboxSpec) (*models.Sandbox, error) { - grpcSpec, err := sbmgrapi.ToGRPCSandboxSpec(spec) - if err != nil { - return nil, err - } - req := &sbmgrapi.ApplySandboxRequest{ - Name: name, - SandboxSpec: grpcSpec, - } - conn, err := grpc.Dial("localhost:6666", - grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - return nil, fmt.Errorf("unable to dial sandboxmanager: %w", err) - } - cli := sbmgrapi.NewSandboxManagerAPIClient(conn) - grpcResp, err := cli.ApplySandbox(ctx, req) - if err != nil { - grpcStatus, ok := status.FromError(err) - if ok { - switch grpcStatus.Code() { - case codes.Unavailable: - return nil, fmt.Errorf("sandboxmanager is not running, start it with \"signadot local connect\"") - } - } - return nil, fmt.Errorf("unable to apply sandbox in sandboxmanager: %w", err) - } - switch it := grpcResp.It.(type) { - case *sbmgrapi.ApplySandboxResponse_ApiError: - return nil, errors.New(it.ApiError) - case *sbmgrapi.ApplySandboxResponse_Sandbox: - return sbmgrapi.ToModelsSandbox(it.Sandbox) - default: - return nil, fmt.Errorf("internal error: unexpected type of `It`") - } -} diff --git a/internal/locald/sandboxmanager/sandbox_monitor.go b/internal/locald/sandboxmanager/sandbox_monitor.go index c35ba27..0b450bf 100644 --- a/internal/locald/sandboxmanager/sandbox_monitor.go +++ b/internal/locald/sandboxmanager/sandbox_monitor.go @@ -6,11 +6,12 @@ import ( "sync" "time" + "log/slog" + "github.com/signadot/go-sdk/models" clapi "github.com/signadot/libconnect/apiv1" clapiclient "github.com/signadot/libconnect/common/apiclient" "github.com/signadot/libconnect/revtun" - "log/slog" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) diff --git a/internal/locald/sandboxmanager/sandbox_server.go b/internal/locald/sandboxmanager/sandbox_server.go index ec67ddf..4b10c60 100644 --- a/internal/locald/sandboxmanager/sandbox_server.go +++ b/internal/locald/sandboxmanager/sandbox_server.go @@ -6,14 +6,14 @@ import ( "sync" "time" + "log/slog" + "github.com/signadot/cli/internal/config" commonapi "github.com/signadot/cli/internal/locald/api" rootapi "github.com/signadot/cli/internal/locald/api/rootmanager" sbapi "github.com/signadot/cli/internal/locald/api/sandboxmanager" - "github.com/signadot/go-sdk/client/sandboxes" "github.com/signadot/go-sdk/models" "github.com/signadot/libconnect/common/portforward" - "log/slog" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" @@ -60,60 +60,60 @@ func newSandboxManagerGRPCServer(ciConfig *config.ConnectInvocationConfig, portF return srv } -func (s *sbmServer) ApplySandbox(ctx context.Context, req *sbapi.ApplySandboxRequest) (*sbapi.ApplySandboxResponse, error) { - if !s.isSBManagerReadyFunc() { - return sbapi.APIErrorResponse( - fmt.Errorf("sandboxmanager is still starting")), nil - } - sbSpec, err := sbapi.ToModelsSandboxSpec(req.SandboxSpec) - if err != nil { - return sbapi.APIErrorResponse( - fmt.Errorf("unable to create go-sdk sandbox spec: %w", err)), nil - } - sb := &models.Sandbox{ - Spec: sbSpec, - } - if sbSpec.Cluster == nil { - return sbapi.APIErrorResponse( - fmt.Errorf("sandbox spec must specify cluster")), nil - } - if *sbSpec.Cluster != s.ciConfig.ConnectionConfig.Cluster { - return sbapi.APIErrorResponse( - fmt.Errorf("sandbox spec cluster %q does not match connected cluster (%q)", - *sbSpec.Cluster, s.ciConfig.ConnectionConfig.Cluster)), nil - } +// func (s *sbmServer) ApplySandbox(ctx context.Context, req *sbapi.ApplySandboxRequest) (*sbapi.ApplySandboxResponse, error) { +// if !s.isSBManagerReadyFunc() { +// return sbapi.APIErrorResponse( +// fmt.Errorf("sandboxmanager is still starting")), nil +// } +// sbSpec, err := sbapi.ToModelsSandboxSpec(req.SandboxSpec) +// if err != nil { +// return sbapi.APIErrorResponse( +// fmt.Errorf("unable to create go-sdk sandbox spec: %w", err)), nil +// } +// sb := &models.Sandbox{ +// Spec: sbSpec, +// } +// if sbSpec.Cluster == nil { +// return sbapi.APIErrorResponse( +// fmt.Errorf("sandbox spec must specify cluster")), nil +// } +// if *sbSpec.Cluster != s.ciConfig.ConnectionConfig.Cluster { +// return sbapi.APIErrorResponse( +// fmt.Errorf("sandbox spec cluster %q does not match connected cluster (%q)", +// *sbSpec.Cluster, s.ciConfig.ConnectionConfig.Cluster)), nil +// } - apiConfig := s.ciConfig.API - s.log.Debug("api", "config", apiConfig) - params := sandboxes.NewApplySandboxParams(). - WithOrgName(apiConfig.Org).WithSandboxName(req.Name).WithData(sb) - result, err := apiConfig.Client.Sandboxes.ApplySandbox(params, nil) - if err != nil { - return sbapi.APIErrorResponse(err), nil - } - code := result.Code() - switch { - default: - return sbapi.APIErrorResponse(result), nil - case code/100 == 2: - // success, continue below - } +// apiConfig := s.ciConfig.API +// s.log.Debug("api", "config", apiConfig) +// params := sandboxes.NewApplySandboxParams(). +// WithOrgName(apiConfig.Org).WithSandboxName(req.Name).WithData(sb) +// result, err := apiConfig.Client.Sandboxes.ApplySandbox(params, nil) +// if err != nil { +// return sbapi.APIErrorResponse(err), nil +// } +// code := result.Code() +// switch { +// default: +// return sbapi.APIErrorResponse(result), nil +// case code/100 == 2: +// // success, continue below +// } - // the api call was a success, register sandbox - s.registerSandbox(result.Payload) +// // the api call was a success, register sandbox +// s.registerSandbox(result.Payload) - // construct response - grpcSandbox, err := sbapi.ToGRPCSandbox(result.Payload) - if err != nil { - return nil, status.Errorf(codes.Internal, "unable to create grpc sandbox: %s", err.Error()) - } - resp := &sbapi.ApplySandboxResponse{ - It: &sbapi.ApplySandboxResponse_Sandbox{ - Sandbox: grpcSandbox, - }, - } - return resp, nil -} +// // construct response +// grpcSandbox, err := sbapi.ToGRPCSandbox(result.Payload) +// if err != nil { +// return nil, status.Errorf(codes.Internal, "unable to create grpc sandbox: %s", err.Error()) +// } +// resp := &sbapi.ApplySandboxResponse{ +// It: &sbapi.ApplySandboxResponse_Sandbox{ +// Sandbox: grpcSandbox, +// }, +// } +// return resp, nil +// } func (s *sbmServer) Status(ctx context.Context, req *sbapi.StatusRequest) (*sbapi.StatusResponse, error) { // make a local copy diff --git a/internal/locald/sandboxmanager/sdk.go b/internal/locald/sandboxmanager/sdk.go new file mode 100644 index 0000000..0cf7d51 --- /dev/null +++ b/internal/locald/sandboxmanager/sdk.go @@ -0,0 +1,119 @@ +package sandboxmanager + +import ( + "context" + "fmt" + + "github.com/signadot/cli/internal/config" + commonapi "github.com/signadot/cli/internal/locald/api" + sbmapi "github.com/signadot/cli/internal/locald/api/sandboxmanager" + connectcfg "github.com/signadot/libconnect/config" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/status" +) + +func GetStatus() (*sbmapi.StatusResponse, error) { + // Get a sandbox manager API client + grpcConn, err := grpc.Dial("127.0.0.1:6666", grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return nil, fmt.Errorf("couldn't connect sandboxmanager: %w", err) + } + defer grpcConn.Close() + + // get the status + sbManagerClient := sbmapi.NewSandboxManagerAPIClient(grpcConn) + sbStatus, err := sbManagerClient.Status(context.Background(), &sbmapi.StatusRequest{}) + if err != nil { + grpcStatus, ok := status.FromError(err) + if ok { + switch grpcStatus.Code() { + case codes.Unavailable: + return nil, fmt.Errorf("sandboxmanager is not running, start it with \"signadot local connect\"") + } + } + return nil, fmt.Errorf("unable to get status from sandboxmanager: %w", err) + } + return sbStatus, nil +} + +func CheckStatusConnectErrors(status *sbmapi.StatusResponse, ciConfig *config.ConnectInvocationConfig) []error { + var errs []error + + // decode config (if needed) + if ciConfig == nil { + var err error + ciConfig, err = sbmapi.ToCIConfig(status.CiConfig) + if err != nil { + return append(errs, fmt.Errorf("couldn't unmarshal ci-config from sandboxmanager status, %v", err)) + } + } + + // check port forward status + if ciConfig.ConnectionConfig.Type == connectcfg.PortForwardLinkType { + err := checkPortforwardStatus(status.Portforward) + if err != nil { + errs = append(errs, err) + } + } + // check root manager (if running) + if ciConfig.WithRootManager { + // check localnet service + err := checkLocalNetStatus(status.Localnet) + if err != nil { + errs = append(errs, err) + } + // check hosts service + err = checkHostsStatus(status.Hosts) + if err != nil { + errs = append(errs, err) + } + } + return errs +} + +func checkPortforwardStatus(portforward *commonapi.PortForwardStatus) error { + errorMsg := "failed to establish port-forward" + if portforward != nil { + if portforward.Health != nil { + if portforward.Health.Healthy { + return nil + } + if portforward.Health.LastErrorReason != "" { + errorMsg += fmt.Sprintf(" (%q)", portforward.Health.LastErrorReason) + } + } + } + return fmt.Errorf(errorMsg) +} + +func checkLocalNetStatus(localnet *commonapi.LocalNetStatus) error { + errorMsg := "failed to setup localnet" + if localnet != nil { + if localnet.Health != nil { + if localnet.Health.Healthy { + return nil + } + if localnet.Health.LastErrorReason != "" { + errorMsg += fmt.Sprintf(" (%q)", localnet.Health.LastErrorReason) + } + } + } + return fmt.Errorf(errorMsg) +} + +func checkHostsStatus(hosts *commonapi.HostsStatus) error { + errorMsg := "failed to configure hosts in /etc/hosts" + if hosts != nil { + if hosts.Health != nil { + if hosts.Health.Healthy { + return nil + } + if hosts.Health.LastErrorReason != "" { + errorMsg += fmt.Sprintf(" (%q)", hosts.Health.LastErrorReason) + } + } + } + return fmt.Errorf(errorMsg) +} From 58fd74b6c5e2f62a4bcaccd5b736e359785815a0 Mon Sep 17 00:00:00 2001 From: Daniel De Vera Date: Tue, 7 Nov 2023 17:14:07 -0300 Subject: [PATCH 02/10] Release candidate changes --- go.mod | 18 +- go.sum | 30 +- internal/command/sandbox/apply.go | 8 +- internal/locald/sandboxmanager/revtun.go | 42 +-- .../sandboxmanager/sandbox_controller.go | 224 ++++++++++++ .../locald/sandboxmanager/sandbox_manager.go | 54 ++- .../locald/sandboxmanager/sandbox_monitor.go | 325 ------------------ .../locald/sandboxmanager/sandbox_server.go | 140 +------- .../sandboxmanager/sandboxes_watcher.go | 173 ++++++++++ internal/utils/system/system.go | 10 + 10 files changed, 491 insertions(+), 533 deletions(-) create mode 100644 internal/locald/sandboxmanager/sandbox_controller.go delete mode 100644 internal/locald/sandboxmanager/sandbox_monitor.go create mode 100644 internal/locald/sandboxmanager/sandboxes_watcher.go diff --git a/go.mod b/go.mod index 0e55ba4..d7a1bc1 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/signadot/cli go 1.21 require ( + github.com/denisbrodbeck/machineid v1.0.1 github.com/docker/go-units v0.5.0 github.com/go-openapi/runtime v0.26.0 github.com/go-openapi/strfmt v0.21.7 @@ -10,12 +11,11 @@ require ( github.com/golang/protobuf v1.5.3 github.com/hashicorp/go-multierror v1.1.1 github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 - github.com/signadot/go-sdk v0.3.8-0.20230917202415-61cf5bfada91 - github.com/signadot/libconnect v0.1.1-0.20231027085512-a9f6abcdcf30 + github.com/signadot/go-sdk v0.3.8-0.20231107200143-6c7fe4258298 + github.com/signadot/libconnect v0.1.1-0.20231107195908-d23167fa13fe github.com/spf13/cobra v1.6.0 github.com/spf13/viper v1.11.0 github.com/theckman/yacspin v0.13.12 - golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 golang.org/x/net v0.10.0 golang.org/x/term v0.9.0 google.golang.org/grpc v1.56.0 @@ -43,7 +43,7 @@ require ( github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/fatih/color v1.15.0 github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/errors v0.20.4 // indirect @@ -85,9 +85,9 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.2 // indirect go.mongodb.org/mongo-driver v1.12.1 // indirect - go.opentelemetry.io/otel v1.18.0 // indirect - go.opentelemetry.io/otel/metric v1.18.0 // indirect - go.opentelemetry.io/otel/trace v1.18.0 // indirect + go.opentelemetry.io/otel v1.19.0 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/otel/trace v1.19.0 // indirect golang.org/x/crypto v0.10.0 // indirect golang.org/x/oauth2 v0.7.0 // indirect golang.org/x/sys v0.9.0 // indirect @@ -111,5 +111,5 @@ require ( ) // Used for local dev -//replace github.com/signadot/libconnect => ../libconnect/ -//replace github.com/signadot/go-sdk => ../go-sdk +// replace github.com/signadot/libconnect => ../libconnect/ +// replace github.com/signadot/go-sdk => ../go-sdk diff --git a/go.sum b/go.sum index 1940031..1205078 100644 --- a/go.sum +++ b/go.sum @@ -78,6 +78,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ= +github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= @@ -103,8 +105,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= @@ -360,12 +362,10 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/signadot/go-sdk v0.3.8-0.20230917202415-61cf5bfada91 h1:DVxA0GXvgVmrlpUo48xd0SDbcXHLO+KkUHkUFbWfSwg= -github.com/signadot/go-sdk v0.3.8-0.20230917202415-61cf5bfada91/go.mod h1:X86A7rI8J//a2T8aKVCCVXxOMBjh32c2GJ50WK7iYzs= -github.com/signadot/libconnect v0.1.1-0.20231011194636-a0941512a00a h1:o+GNGQP7MKm/wX6S/rXoCMVyjSHGVcCtROMpiQLJnJk= -github.com/signadot/libconnect v0.1.1-0.20231011194636-a0941512a00a/go.mod h1:LIU36XBqFs+GlaE05UIJxI7+O/MHISAAMGupQdTAEUE= -github.com/signadot/libconnect v0.1.1-0.20231027085512-a9f6abcdcf30 h1:tmnSWg79tDjV0sU+nU7Iiv91Rc66Dq4hsj/O4EKqFMo= -github.com/signadot/libconnect v0.1.1-0.20231027085512-a9f6abcdcf30/go.mod h1:ZX3YLJ5zYTxaVkeOAMsufYQZTOEwgFgAb2w1hZWIS3s= +github.com/signadot/go-sdk v0.3.8-0.20231107200143-6c7fe4258298 h1:zNEYJUQEbYMpEkFekq8wDjC6atbKRxPHIrC5UT6pE/A= +github.com/signadot/go-sdk v0.3.8-0.20231107200143-6c7fe4258298/go.mod h1:mLzoMuSE0GsFLONRjjYYHQBsU9twXML1BrExSvpMqeI= +github.com/signadot/libconnect v0.1.1-0.20231107195908-d23167fa13fe h1:QcR2WYy8Vg+N+yJI59w3ozpBYiTWGorMbQP95mlppEI= +github.com/signadot/libconnect v0.1.1-0.20231107195908-d23167fa13fe/go.mod h1:4OzWoyxyoh56h4jgCw/FBJVxyHB45qpwHDVWbsGfFTg= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -429,14 +429,14 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opentelemetry.io/otel v1.18.0 h1:TgVozPGZ01nHyDZxK5WGPFB9QexeTMXEH7+tIClWfzs= -go.opentelemetry.io/otel v1.18.0/go.mod h1:9lWqYO0Db579XzVuCKFNPDl4s73Voa+zEck3wHaAYQI= -go.opentelemetry.io/otel/metric v1.18.0 h1:JwVzw94UYmbx3ej++CwLUQZxEODDj/pOuTCvzhtRrSQ= -go.opentelemetry.io/otel/metric v1.18.0/go.mod h1:nNSpsVDjWGfb7chbRLUNW+PBNdcSTHD4Uu5pfFMOI0k= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= -go.opentelemetry.io/otel/trace v1.18.0 h1:NY+czwbHbmndxojTEKiSMHkG2ClNH2PwmcHrdo0JY10= -go.opentelemetry.io/otel/trace v1.18.0/go.mod h1:T2+SGJGuYZY3bjj5rgh/hN7KIrlpWC5nS8Mjvzckz+0= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= @@ -462,8 +462,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/internal/command/sandbox/apply.go b/internal/command/sandbox/apply.go index 596f24f..5910011 100644 --- a/internal/command/sandbox/apply.go +++ b/internal/command/sandbox/apply.go @@ -5,13 +5,13 @@ import ( "fmt" "io" - "github.com/denisbrodbeck/machineid" "github.com/signadot/cli/internal/config" sbmapi "github.com/signadot/cli/internal/locald/api/sandboxmanager" sbmgr "github.com/signadot/cli/internal/locald/sandboxmanager" "github.com/signadot/cli/internal/poll" "github.com/signadot/cli/internal/print" "github.com/signadot/cli/internal/spinner" + "github.com/signadot/cli/internal/utils/system" "github.com/signadot/go-sdk/client/sandboxes" "github.com/signadot/go-sdk/models" "github.com/spf13/cobra" @@ -69,11 +69,11 @@ func apply(cfg *config.SandboxApply, out, log io.Writer, args []string) error { } // Set the local machine ID - machineID, err := machineid.ProtectedID("signadotCLI") + machineID, err := system.GetMachineID() if err != nil { - return fmt.Errorf("couldn't read machine-id, %v", err) + return err } - req.Spec.MachineID = machineID + req.Spec.LocalMachineID = machineID } // Send the request to the SaaS diff --git a/internal/locald/sandboxmanager/revtun.go b/internal/locald/sandboxmanager/revtun.go index e7589e7..e555ec4 100644 --- a/internal/locald/sandboxmanager/revtun.go +++ b/internal/locald/sandboxmanager/revtun.go @@ -6,16 +6,17 @@ import ( "io" "time" - "github.com/signadot/go-sdk/models" + "log/slog" + + tunapiv1 "github.com/signadot/libconnect/apiv1" "github.com/signadot/libconnect/revtun" rtproto "github.com/signadot/libconnect/revtun/protocol" - "log/slog" ) type rt struct { - log *slog.Logger - localName string - // NB used exclusively by sanbox monitor => no races + log *slog.Logger + + // NB used exclusively by sanbox controller => no races clusterNotConnectedTime *time.Time rtClient revtun.Client rtConfig *rtproto.Config @@ -25,31 +26,33 @@ type rt struct { rtErr error } -func newRevtun(log *slog.Logger, rtc revtun.Client, name, rk string, local *models.Local) (*rt, error) { +func newRevtun(log *slog.Logger, rtc revtun.Client, rk string, + xw *tunapiv1.WatchLocalSandboxesResponse_ExternalWorkload) (*rt, error) { + // define the revtun config (that will be used to setup the reverse tunnel) rtConfig := &rtproto.Config{ SandboxRoutingKey: rk, - ExternalWorkload: name, + ExternalWorkload: xw.Name, Forwards: []rtproto.Forward{}, } - for _, pm := range local.Mappings { - kind, err := kindToRemoteURLTLD(local.From.Kind) + for _, pm := range xw.WorkloadPortMapping { + kind, err := kindToRemoteURLTLD(xw.Baseline.Kind) if err != nil { return nil, err } rtConfig.Forwards = append(rtConfig.Forwards, rtproto.Forward{ - LocalURL: fmt.Sprintf("tcp://%s", pm.ToLocal), + LocalURL: fmt.Sprintf("tcp://%s", pm.LocalAddress), RemoteURL: fmt.Sprintf("tcp://%s.%s.%s:%d", - *local.From.Name, - *local.From.Namespace, + xw.Baseline.Name, + xw.Baseline.Namespace, kind, - pm.Port), + pm.BaselinePort, + ), }, ) } res := &rt{ - log: log, - localName: name, + log: log.With("local", xw.Name), rtClient: rtc, rtConfig: rtConfig, rtToClose: make(chan struct{}), @@ -88,16 +91,13 @@ func (t *rt) monitor() { } } -func kindToRemoteURLTLD(kind *string) (string, error) { - if kind == nil { - return "svc", nil - } - switch *kind { +func kindToRemoteURLTLD(kind string) (string, error) { + switch kind { case "Deployment": return "deploy", nil case "Rollout": return "rollout", nil default: - return "", fmt.Errorf("invalid local.From kind: %q", *kind) + return "", fmt.Errorf("invalid baseline kind: %q", kind) } } diff --git a/internal/locald/sandboxmanager/sandbox_controller.go b/internal/locald/sandboxmanager/sandbox_controller.go new file mode 100644 index 0000000..2d56a24 --- /dev/null +++ b/internal/locald/sandboxmanager/sandbox_controller.go @@ -0,0 +1,224 @@ +package sandboxmanager + +import ( + "sync" + "time" + + "log/slog" + + "github.com/signadot/libconnect/apiv1" + tunapiv1 "github.com/signadot/libconnect/apiv1" + "github.com/signadot/libconnect/revtun" + "google.golang.org/protobuf/proto" +) + +const ( + reconcilePeriod = 10 * time.Second +) + +type sbController struct { + sync.Mutex + + log *slog.Logger + sandbox *tunapiv1.WatchLocalSandboxesResponse_Sandbox + revtunClient revtun.Client + revtuns map[string]*rt + delFn func() + + reconcileCh chan struct{} + doneCh chan struct{} +} + +func newSBController(log *slog.Logger, sandbox *tunapiv1.WatchLocalSandboxesResponse_Sandbox, + rtClient revtun.Client, delFn func()) *sbController { + // create the controller + ctrl := &sbController{ + log: log.With("sandbox", sandbox.SandboxName), + sandbox: sandbox, + revtunClient: rtClient, + revtuns: make(map[string]*rt), + delFn: delFn, + reconcileCh: make(chan struct{}, 1), + doneCh: make(chan struct{}), + } + // run the controller + go ctrl.run() + return ctrl +} + +func (ctrl *sbController) run() { + // run the reconcile loop + ticker := time.NewTicker(reconcilePeriod) + defer ticker.Stop() +reconcileLoop: + for { + select { + case <-ctrl.doneCh: + // we are done, cancel the context + break reconcileLoop + case <-ctrl.reconcileCh: + // The status has changed + ctrl.reconcile() + case <-ticker.C: + // Reconcile ticker + ctrl.reconcile() + } + } + + // we're done, clean up revtuns + ctrl.log.Debug("cleaning up reverse tunnels") + ctrl.updateSandbox(&tunapiv1.WatchLocalSandboxesResponse_Sandbox{}) + ctrl.reconcile() + ctrl.delFn() +} + +func (ctrl *sbController) stop() { + select { + case <-ctrl.doneCh: + default: + close(ctrl.doneCh) + } +} + +func (ctrl *sbController) getSandbox() *tunapiv1.WatchLocalSandboxesResponse_Sandbox { + ctrl.Lock() + defer ctrl.Unlock() + return ctrl.sandbox +} + +func (ctrl *sbController) updateSandbox(sandbox *tunapiv1.WatchLocalSandboxesResponse_Sandbox) { + ctrl.Lock() + defer ctrl.Unlock() + + // close rev tunnels if the spec has changed + for _, desXW := range sandbox.ExternalWorkloads { + for _, obsXW := range ctrl.sandbox.ExternalWorkloads { + if desXW.Name != obsXW.Name { + continue + } + if !ctrl.compareExternalWorkloadsSpec(desXW, obsXW) { + // the desired local spec is different from the observed one, + // close existing tunnel + ctrl.log.Debug("desired local spec is different from the observed one", "des", desXW, "obs", obsXW) + ctrl.closeRevTunnel(obsXW.Name) + } + break + } + } + + // update sandbox + ctrl.sandbox.ExternalWorkloads = sandbox.ExternalWorkloads + ctrl.sandbox.Resources = sandbox.Resources + ctrl.log.Debug("updating sandbox", "sandbox", ctrl.sandbox) + + // trigger a reconcile + ctrl.triggerReconcile() +} + +func (ctrl *sbController) triggerReconcile() { + select { + case ctrl.reconcileCh <- struct{}{}: + default: + } +} + +func (ctrl *sbController) reconcile() { + ctrl.Lock() + defer ctrl.Unlock() + if ctrl.sandbox == nil { + return + } + + // reconcile + ctrl.log.Debug("reconciling tunnels") + // put the xwls in a map + xwMap := make(map[string]*tunapiv1.WatchLocalSandboxesResponse_ExternalWorkload, len(ctrl.sandbox.ExternalWorkloads)) + for _, xw := range ctrl.sandbox.ExternalWorkloads { + xwMap[xw.Name] = xw + } + + for xwName, xw := range xwMap { + rt, has := ctrl.revtuns[xwName] + if has { + select { + case <-rt.rtToClose: + // delete the revtun if it has been closed + has = false + delete(ctrl.revtuns, xwName) + default: + } + } + + if has { + // check connection issues + if !xw.Connected { + now := time.Now() + if rt.clusterNotConnectedTime == nil { + rt.clusterNotConnectedTime = &now + } + if time.Since(*rt.clusterNotConnectedTime) > 10*time.Second { + // this revtun has been down for more than 10 secs + // close and delete the current revtune + has = false + ctrl.closeRevTunnel(xwName) + delete(ctrl.revtuns, xwName) + } + } else { + // reset this value + rt.clusterNotConnectedTime = nil + } + } + if has { + continue + } + + // create revtun + rt, err := newRevtun(ctrl.log, ctrl.revtunClient, ctrl.sandbox.RoutingKey, xw) + if err != nil { + ctrl.log.Error("error creating revtun", "error", err) + continue + } + ctrl.revtuns[xwName] = rt + } + + // delete unwanted tunnels + for xwName := range ctrl.revtuns { + _, desired := xwMap[xwName] + if desired { + continue + } + // close and delete the current revtune + ctrl.closeRevTunnel(xwName) + delete(ctrl.revtuns, xwName) + } +} + +func (ctrl *sbController) closeRevTunnel(xwName string) { + revtun := ctrl.revtuns[xwName] + if revtun == nil { + return + } + + select { + case <-revtun.rtToClose: + default: + ctrl.log.Debug("sandbox controller closing revtun", "local", xwName) + close(revtun.rtToClose) + } +} + +func (ctrl *sbController) compareExternalWorkloadsSpec(a, b *apiv1.WatchLocalSandboxesResponse_ExternalWorkload) bool { + // for comparison, ignore status info + specA := &apiv1.WatchLocalSandboxesResponse_ExternalWorkload{ + Name: a.Name, + Baseline: a.Baseline, + WorkloadPortMapping: a.WorkloadPortMapping, + } + specB := &apiv1.WatchLocalSandboxesResponse_ExternalWorkload{ + Name: b.Name, + Baseline: b.Baseline, + WorkloadPortMapping: b.WorkloadPortMapping, + } + // compare specs + return proto.Equal(specA, specB) +} diff --git a/internal/locald/sandboxmanager/sandbox_manager.go b/internal/locald/sandboxmanager/sandbox_manager.go index 2740aba..5a85a79 100644 --- a/internal/locald/sandboxmanager/sandbox_manager.go +++ b/internal/locald/sandboxmanager/sandbox_manager.go @@ -6,13 +6,14 @@ import ( "net" "os" "os/signal" - "sync" "syscall" + "log/slog" + "github.com/signadot/cli/internal/config" sbapi "github.com/signadot/cli/internal/locald/api/sandboxmanager" + "github.com/signadot/cli/internal/utils/system" tunapiclient "github.com/signadot/libconnect/common/apiclient" - "log/slog" "google.golang.org/grpc" "k8s.io/client-go/kubernetes" @@ -32,13 +33,14 @@ type sandboxManager struct { ciConfig *config.ConnectInvocationConfig connConfig *connectcfg.ConnectionConfig hostname string + machineID string grpcServer *grpc.Server sbmServer *sbmServer + sbmWatcher *sbmWatcher portForward *portforward.PortForward shutdownCh chan struct{} // tunnel API - tunMu sync.Mutex tunAPIClient tunapiclient.Client proxyAddress string } @@ -53,6 +55,12 @@ func NewSandboxManager(cfg *config.LocalDaemon, args []string, log *slog.Logger) return nil, err } + // Resolve the machine ID + machineID, err := system.GetMachineID() + if err != nil { + return nil, err + } + ciConfig := cfg.ConnectInvocationConfig return &sandboxManager{ @@ -60,6 +68,7 @@ func NewSandboxManager(cfg *config.LocalDaemon, args []string, log *slog.Logger) ciConfig: ciConfig, connConfig: ciConfig.ConnectionConfig, hostname: hostname, + machineID: machineID, grpcServer: grpcServer, shutdownCh: shutdownCh, }, nil @@ -102,9 +111,12 @@ func (m *sandboxManager) Run(ctx context.Context) error { } } + // Create the watcher + m.sbmWatcher = newSandboxManagerWatcher(m.log, m.machineID, m.revtunClient, m.shutdownCh) + // Register our service in gRPC server - m.sbmServer = newSandboxManagerGRPCServer(m.ciConfig, m.portForward, m.isSBManagerReady, - m.getSBMonitor, m.log, m.shutdownCh) + m.sbmServer = newSandboxManagerGRPCServer(m.log, m.ciConfig, m.portForward, + m.sbmWatcher, m.shutdownCh) sbapi.RegisterSandboxManagerAPIServer(m.grpcServer, m.sbmServer) // Run the gRPC server @@ -130,13 +142,16 @@ func (m *sandboxManager) Run(ctx context.Context) error { } } + // Run the sandboxes watcher + m.sbmWatcher.run(ctx, m.tunAPIClient) + // Wait until termination <-runCtx.Done() // Clean up m.log.Info("Shutting down") m.grpcServer.GracefulStop() - m.sbmServer.stop() + m.sbmWatcher.stop() if m.portForward != nil { m.portForward.Close() } @@ -152,39 +167,12 @@ func (m *sandboxManager) runAPIServer() error { return nil } -func (m *sandboxManager) isSBManagerReady() bool { - m.tunMu.Lock() - defer m.tunMu.Unlock() - return m.tunAPIClient != nil -} - -func (m *sandboxManager) getSBMonitor(routingKey string, delFn func()) *sbMonitor { - m.tunMu.Lock() - defer m.tunMu.Unlock() - if m.tunAPIClient == nil { - // this shouldn't happen because we check - // if sb manager is ready, which is - // monotonic - m.log.Error("invalid internal state: getSBMonitor while sb manager is not ready") - return nil - } - return newSBMonitor( - routingKey, - m.tunAPIClient, - m.revtunClient(), - delFn, - m.log.With("sandbox-routing-key", routingKey), - ) -} - func (m *sandboxManager) setTunnelAPIClient(proxyAddress string) error { tunAPIClient, err := tunapiclient.NewClient(proxyAddress, tunapiclient.DefaultClientKeepaliveParams()) if err != nil { return err } - m.tunMu.Lock() - defer m.tunMu.Unlock() m.tunAPIClient = tunAPIClient m.proxyAddress = proxyAddress return nil diff --git a/internal/locald/sandboxmanager/sandbox_monitor.go b/internal/locald/sandboxmanager/sandbox_monitor.go deleted file mode 100644 index 0b450bf..0000000 --- a/internal/locald/sandboxmanager/sandbox_monitor.go +++ /dev/null @@ -1,325 +0,0 @@ -package sandboxmanager - -import ( - "bytes" - "context" - "sync" - "time" - - "log/slog" - - "github.com/signadot/go-sdk/models" - clapi "github.com/signadot/libconnect/apiv1" - clapiclient "github.com/signadot/libconnect/common/apiclient" - "github.com/signadot/libconnect/revtun" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -const ( - reconcilePeriod = 10 * time.Second -) - -type sbMonitor struct { - sync.Mutex - routingKey string - clapiClient clapiclient.Client - revtunClient revtun.Client - // func called on delete - delFn func() - log *slog.Logger - doneCh chan struct{} - reconcileCh chan struct{} - status *clapi.WatchSandboxResponse - revtuns map[string]*rt - locals map[string]*models.Local -} - -func newSBMonitor(rk string, clapiClient clapiclient.Client, rtClient revtun.Client, delFn func(), log *slog.Logger) *sbMonitor { - res := &sbMonitor{ - routingKey: rk, - clapiClient: clapiClient, - revtunClient: rtClient, - delFn: delFn, - log: log, - doneCh: make(chan struct{}), - reconcileCh: make(chan struct{}, 1), - locals: make(map[string]*models.Local), - revtuns: make(map[string]*rt), - } - go res.monitor() - return res -} - -func (sbm *sbMonitor) getStatus() *clapi.WatchSandboxResponse { - sbm.Lock() - defer sbm.Unlock() - return sbm.status -} - -func (sbm *sbMonitor) stop() { - select { - case <-sbm.doneCh: - default: - close(sbm.doneCh) - } -} - -func (sbm *sbMonitor) monitor() { - // setup context for grp stream requests - ctx, cancel := context.WithCancel(context.Background()) - - // watch the given sandbox - go sbm.watchSandbox(ctx) - - // run the reconcile loop - ticker := time.NewTicker(reconcilePeriod) - defer ticker.Stop() -reconcileLoop: - for { - select { - case <-sbm.doneCh: - // we are done, cancel the context - cancel() - break reconcileLoop - case <-sbm.reconcileCh: - // The status has changed - sbm.reconcile() - case <-ticker.C: - // Reconcile ticker - sbm.reconcile() - } - } - - // we're done, clean up revtuns and parent delete func - sbm.log.Debug("cleaning up status and locals and parent") - sbm.updateSandboxStatus(&clapi.WatchSandboxResponse{}) - sbm.updateLocalsSpec(nil) - sbm.reconcile() - sbm.delFn() -} - -func (sbm *sbMonitor) watchSandbox(ctx context.Context) { - // watch loop - for { - sbwClient, err := sbm.clapiClient.WatchSandbox(ctx, &clapi.WatchSandboxRequest{ - RoutingKey: sbm.routingKey, - }) - if err != nil { - // don't retry if the context has been cancelled - select { - case <-ctx.Done(): - return - default: - } - - sbm.log.Error("error getting sb watch stream, retrying", "error", err) - <-time.After(3 * time.Second) - continue - } - sbm.log.Debug("successfully got sandbox watch client") - err = sbm.readStream(sbwClient) - if err == nil { - // NotFound - break - } - } - - // There is no sandbox, stop the monitor - sbm.stop() -} - -func (sbm *sbMonitor) readStream(sbwClient clapi.TunnelAPI_WatchSandboxClient) error { - var ( - ok bool - err error - sbStatus *clapi.WatchSandboxResponse - grpcStatus *status.Status - ) - for { - sbStatus, err = sbwClient.Recv() - if err == nil { - sbm.updateSandboxStatus(sbStatus) - continue - } - if grpcStatus, ok = status.FromError(err); !ok { - sbm.log.Error("sandbox monitor grpc stream error: no status", - "error", err) - break - } - switch grpcStatus.Code() { - case codes.OK: - sbm.log.Debug("sandbox watch stream error code is ok") - sbm.updateSandboxStatus(sbStatus) - continue - case codes.Internal: - sbm.log.Error("sandbox watch: internal grpc error", - "error", err) - <-time.After(3 * time.Second) - case codes.NotFound: - sbm.log.Info("sandbox watch: sandbox not found") - err = nil - default: - sbm.log.Error("sandbox watch error", "error", err) - } - break - } - return err -} - -func (sbm *sbMonitor) updateSandboxStatus(st *clapi.WatchSandboxResponse) { - sbm.Lock() - defer sbm.Unlock() - - // update status - sbm.status = st - sbm.log.Debug("sbm setting watch status", "status", sbm.status) - // trigger a reconcile - sbm.triggerReconcile() -} - -func (sbm *sbMonitor) updateLocalsSpec(locals []*models.Local) { - sbm.Lock() - defer sbm.Unlock() - - desLocals := make(map[string]*models.Local, len(locals)) - for _, localSpec := range locals { - desLocals[localSpec.Name] = localSpec - } - for localName := range sbm.locals { - _, desired := desLocals[localName] - if !desired { - delete(sbm.locals, localName) - continue - } - } - for localName, des := range desLocals { - obs, has := sbm.locals[localName] - if !has { - sbm.locals[localName] = des - continue - } - if !sbm.localsEqual(des, obs) { - sbm.log.Debug("not equal", "des", des, "obs", obs) - sbm.closeRevTunnel(localName) - } - sbm.locals[localName] = des - } - - // trigger a reconcile - sbm.triggerReconcile() -} - -func (sbm *sbMonitor) closeRevTunnel(xwName string) { - revtun := sbm.revtuns[xwName] - if revtun == nil { - return - } - - select { - case <-revtun.rtToClose: - default: - sbm.log.Debug("sandbox monitor closing revtun", "local", xwName) - close(revtun.rtToClose) - } -} - -func (sbm *sbMonitor) localsEqual(a, b *models.Local) bool { - da, err := a.MarshalBinary() - if err != nil { - sbm.log.Error("error marshalling local", "error", err) - return false - } - db, err := b.MarshalBinary() - if err != nil { - sbm.log.Error("error marshalling local", "error", err) - return false - } - return bytes.Equal(da, db) -} - -func (sbm *sbMonitor) triggerReconcile() { - select { - case sbm.reconcileCh <- struct{}{}: - default: - } -} - -func (sbm *sbMonitor) reconcile() { - sbm.Lock() - defer sbm.Unlock() - if sbm.status == nil { - return - } - - // reconcile - sbm.log.Debug("reconciling tunnels") - statusXWs := make(map[string]*clapi.WatchSandboxResponse_ExternalWorkload, len(sbm.status.ExternalWorkloads)) - // put the xwls in a map - for _, xw := range sbm.status.ExternalWorkloads { - statusXWs[xw.Name] = xw - } - - for xwName, sxw := range statusXWs { - rt, has := sbm.revtuns[xwName] - if has { - select { - case <-rt.rtToClose: - // delete the revtun if it has been closed - has = false - delete(sbm.revtuns, xwName) - default: - } - } - - if has { - // check connection issues - if !sxw.Connected { - now := time.Now() - if rt.clusterNotConnectedTime == nil { - rt.clusterNotConnectedTime = &now - } - if time.Since(*rt.clusterNotConnectedTime) > 10*time.Second { - // this revtun has been down for more than 10 secs - // close and delete the current revtune - has = false - sbm.closeRevTunnel(xwName) - delete(sbm.revtuns, xwName) - } - } else { - // reset this value - rt.clusterNotConnectedTime = nil - } - } - if has { - continue - } - - // get local spec - local := sbm.locals[xwName] - if local == nil { - sbm.log.Warn("no local found for cluster extworkload status", "local", xwName) - continue - } - - // create revtun - rt, err := newRevtun(sbm.log.With("local", sxw.Name), - sbm.revtunClient, sxw.Name, sbm.routingKey, local) - if err != nil { - sbm.log.Error("error creating revtun", "error", err) - continue - } - sbm.revtuns[xwName] = rt - } - - // delete unwanted tunnels - for xwName := range sbm.revtuns { - _, desired := statusXWs[xwName] - if desired { - continue - } - // close and delete the current revtune - sbm.closeRevTunnel(xwName) - delete(sbm.revtuns, xwName) - } -} diff --git a/internal/locald/sandboxmanager/sandbox_server.go b/internal/locald/sandboxmanager/sandbox_server.go index 4b10c60..73727d7 100644 --- a/internal/locald/sandboxmanager/sandbox_server.go +++ b/internal/locald/sandboxmanager/sandbox_server.go @@ -12,7 +12,6 @@ import ( commonapi "github.com/signadot/cli/internal/locald/api" rootapi "github.com/signadot/cli/internal/locald/api/rootmanager" sbapi "github.com/signadot/cli/internal/locald/api/sandboxmanager" - "github.com/signadot/go-sdk/models" "github.com/signadot/libconnect/common/portforward" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -32,10 +31,7 @@ type sbmServer struct { portForward *portforward.PortForward // sandboxes - isSBManagerReadyFunc func() bool - getSBMonitorFunc func(routingKey string, delFn func()) *sbMonitor - sbMu sync.Mutex - sbMonitors map[string]*sbMonitor + sbmWatcher *sbmWatcher // rootmanager statuses rootMu sync.Mutex @@ -45,76 +41,19 @@ type sbmServer struct { shutdownCh chan struct{} } -func newSandboxManagerGRPCServer(ciConfig *config.ConnectInvocationConfig, portForward *portforward.PortForward, - isSBManagerReadyFunc func() bool, getSBMonitorFunc func(string, func()) *sbMonitor, - log *slog.Logger, shutdownCh chan struct{}) *sbmServer { +func newSandboxManagerGRPCServer(log *slog.Logger, ciConfig *config.ConnectInvocationConfig, + portForward *portforward.PortForward, sbmWatcher *sbmWatcher, + shutdownCh chan struct{}) *sbmServer { srv := &sbmServer{ - log: log, - ciConfig: ciConfig, - portForward: portForward, - sbMonitors: make(map[string]*sbMonitor), - isSBManagerReadyFunc: isSBManagerReadyFunc, - getSBMonitorFunc: getSBMonitorFunc, - shutdownCh: shutdownCh, + log: log, + ciConfig: ciConfig, + portForward: portForward, + sbmWatcher: sbmWatcher, + shutdownCh: shutdownCh, } return srv } -// func (s *sbmServer) ApplySandbox(ctx context.Context, req *sbapi.ApplySandboxRequest) (*sbapi.ApplySandboxResponse, error) { -// if !s.isSBManagerReadyFunc() { -// return sbapi.APIErrorResponse( -// fmt.Errorf("sandboxmanager is still starting")), nil -// } -// sbSpec, err := sbapi.ToModelsSandboxSpec(req.SandboxSpec) -// if err != nil { -// return sbapi.APIErrorResponse( -// fmt.Errorf("unable to create go-sdk sandbox spec: %w", err)), nil -// } -// sb := &models.Sandbox{ -// Spec: sbSpec, -// } -// if sbSpec.Cluster == nil { -// return sbapi.APIErrorResponse( -// fmt.Errorf("sandbox spec must specify cluster")), nil -// } -// if *sbSpec.Cluster != s.ciConfig.ConnectionConfig.Cluster { -// return sbapi.APIErrorResponse( -// fmt.Errorf("sandbox spec cluster %q does not match connected cluster (%q)", -// *sbSpec.Cluster, s.ciConfig.ConnectionConfig.Cluster)), nil -// } - -// apiConfig := s.ciConfig.API -// s.log.Debug("api", "config", apiConfig) -// params := sandboxes.NewApplySandboxParams(). -// WithOrgName(apiConfig.Org).WithSandboxName(req.Name).WithData(sb) -// result, err := apiConfig.Client.Sandboxes.ApplySandbox(params, nil) -// if err != nil { -// return sbapi.APIErrorResponse(err), nil -// } -// code := result.Code() -// switch { -// default: -// return sbapi.APIErrorResponse(result), nil -// case code/100 == 2: -// // success, continue below -// } - -// // the api call was a success, register sandbox -// s.registerSandbox(result.Payload) - -// // construct response -// grpcSandbox, err := sbapi.ToGRPCSandbox(result.Payload) -// if err != nil { -// return nil, status.Errorf(codes.Internal, "unable to create grpc sandbox: %s", err.Error()) -// } -// resp := &sbapi.ApplySandboxResponse{ -// It: &sbapi.ApplySandboxResponse_Sandbox{ -// Sandbox: grpcSandbox, -// }, -// } -// return resp, nil -// } - func (s *sbmServer) Status(ctx context.Context, req *sbapi.StatusRequest) (*sbapi.StatusResponse, error) { // make a local copy sbConfig := *s.ciConfig @@ -143,34 +82,6 @@ func (s *sbmServer) Shutdown(ctx context.Context, req *sbapi.ShutdownRequest) (* return &sbapi.ShutdownResponse{}, nil } -func (s *sbmServer) registerSandbox(sb *models.Sandbox) { - s.sbMu.Lock() - defer s.sbMu.Unlock() - sbm, present := s.sbMonitors[sb.Name] - if present { - // update the local spec - sbm.updateLocalsSpec(sb.Spec.Local) - return - } - - // start watching the sandbox in the cluster - sbm = s.getSBMonitorFunc(sb.RoutingKey, func() { - s.sbMu.Lock() - defer s.sbMu.Unlock() - delete(s.sbMonitors, sb.Name) - }) - if sbm == nil { - // this shouldn't happen because we check - // if sb manager is ready, which is - // monotonic - s.log.Error("invalid internal state: getSBMonitor while sb manager is not ready") - return - } - // update the local spec and keep a reference to the sandbox monitor - sbm.updateLocalsSpec(sb.Spec.Local) - s.sbMonitors[sb.Name] = sbm -} - func (s *sbmServer) rootStatus() (*commonapi.HostsStatus, *commonapi.LocalNetStatus) { if !s.ciConfig.WithRootManager { // We are running without a root manager @@ -227,14 +138,13 @@ func (s *sbmServer) portForwardStatus() *commonapi.PortForwardStatus { } func (s *sbmServer) sbStatuses() []*commonapi.SandboxStatus { - s.sbMu.Lock() - defer s.sbMu.Unlock() - res := make([]*commonapi.SandboxStatus, 0, len(s.sbMonitors)) - for name, sbM := range s.sbMonitors { - sbmStatus := sbM.getStatus() + sandboxes := s.sbmWatcher.getSandboxes() + + res := make([]*commonapi.SandboxStatus, 0, len(sandboxes)) + for _, sbmStatus := range sandboxes { grpcStatus := &commonapi.SandboxStatus{ - Name: name, - RoutingKey: sbM.routingKey, + Name: sbmStatus.SandboxName, + RoutingKey: sbmStatus.RoutingKey, LocalWorkloads: make([]*commonapi.SandboxStatus_LocalWorkload, len(sbmStatus.ExternalWorkloads)), } for i, xw := range sbmStatus.ExternalWorkloads { @@ -266,23 +176,3 @@ func (s *sbmServer) sbStatuses() []*commonapi.SandboxStatus { } return res } - -func (s *sbmServer) stop() { - var wg sync.WaitGroup - - // stop all sbx monitors - s.sbMu.Lock() - for _, sbMon := range s.sbMonitors { - wg.Add(1) - // overwrite the delete function - sbMon.delFn = func() { - defer wg.Done() - } - // stop the sbx monitor - sbMon.stop() - } - s.sbMu.Unlock() - - // wait until all sbx monitor has stopped - wg.Wait() -} diff --git a/internal/locald/sandboxmanager/sandboxes_watcher.go b/internal/locald/sandboxmanager/sandboxes_watcher.go new file mode 100644 index 0000000..c65d2fd --- /dev/null +++ b/internal/locald/sandboxmanager/sandboxes_watcher.go @@ -0,0 +1,173 @@ +package sandboxmanager + +import ( + "context" + "log/slog" + "sync" + "time" + + tunapiv1 "github.com/signadot/libconnect/apiv1" + tunapiclient "github.com/signadot/libconnect/common/apiclient" + "github.com/signadot/libconnect/revtun" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type sbmWatcher struct { + log *slog.Logger + + machineID string + + // sandbox controllers + sbMu sync.Mutex + sbControllers map[string]*sbController + revtunClient func() revtun.Client + + // shutdown + shutdownCh chan struct{} +} + +func newSandboxManagerWatcher(log *slog.Logger, machineID string, revtunClient func() revtun.Client, + shutdownCh chan struct{}) *sbmWatcher { + srv := &sbmWatcher{ + log: log, + machineID: machineID, + sbControllers: make(map[string]*sbController), + revtunClient: revtunClient, + shutdownCh: shutdownCh, + } + return srv +} + +func (sbw *sbmWatcher) run(ctx context.Context, tunAPIClient tunapiclient.Client) { + go sbw.watchSandboxes(ctx, tunAPIClient) +} + +func (sbw *sbmWatcher) watchSandboxes(ctx context.Context, tunAPIClient tunapiclient.Client) { + // watch loop + for { + sbwClient, err := tunAPIClient.WatchLocalSandboxes(ctx, &tunapiv1.WatchLocalSandboxesRequest{ + MachineId: sbw.machineID, + }) + if err != nil { + // don't retry if the context has been cancelled + select { + case <-ctx.Done(): + return + default: + } + + sbw.log.Error("error getting local sandboxes watch stream, retrying", "error", err) + <-time.After(3 * time.Second) + continue + } + sbw.log.Debug("successfully got local sandboxes watch client") + err = sbw.readStream(sbwClient) + if err == nil { + // NotFound + break + } + } +} + +func (sbw *sbmWatcher) readStream(sbwClient tunapiv1.TunnelAPI_WatchLocalSandboxesClient) error { + var ( + ok bool + err error + event *tunapiv1.WatchLocalSandboxesResponse + grpcStatus *status.Status + ) + for { + event, err = sbwClient.Recv() + if err == nil { + sbw.processStreamEvent(event) + continue + } + if grpcStatus, ok = status.FromError(err); !ok { + sbw.log.Error("sandboxes watch grpc stream error: no status", + "error", err) + break + } + switch grpcStatus.Code() { + case codes.OK: + sbw.log.Debug("sandboxes watch error code is ok") + sbw.processStreamEvent(event) + continue + case codes.Internal: + sbw.log.Error("sandboxes watch internal grpc error", + "error", err) + <-time.After(3 * time.Second) + default: + sbw.log.Error("sandbox watch error", "error", err) + } + break + } + return err +} + +func (sbw *sbmWatcher) processStreamEvent(event *tunapiv1.WatchLocalSandboxesResponse) { + sbw.sbMu.Lock() + defer sbw.sbMu.Unlock() + + desiredSandboxes := map[string]bool{} + for i := range event.Sandboxes { + sds := event.Sandboxes[i] + desiredSandboxes[sds.SandboxName] = true + + if ctrl := sbw.sbControllers[sds.SandboxName]; ctrl != nil { + // update the sandbox in the controller + ctrl.updateSandbox(sds) + } else { + // create a new sandbox controller + sbw.log.Debug("creating sandbox", "sandbox", sds) + sbw.sbControllers[sds.SandboxName] = newSBController( + sbw.log, sds, sbw.revtunClient(), + func() { + sbw.sbMu.Lock() + defer sbw.sbMu.Unlock() + delete(sbw.sbControllers, sds.SandboxName) + }, + ) + } + } + + // remove unwanted sandboxes + for sdsName, ctrl := range sbw.sbControllers { + if _, ok := desiredSandboxes[sdsName]; ok { + continue + } + sbw.log.Debug("removing sandbox", "sandboxName", sdsName) + ctrl.stop() + } +} + +func (sbw *sbmWatcher) getSandboxes() []*tunapiv1.WatchLocalSandboxesResponse_Sandbox { + sbw.sbMu.Lock() + defer sbw.sbMu.Unlock() + + res := make([]*tunapiv1.WatchLocalSandboxesResponse_Sandbox, 0, len(sbw.sbControllers)) + for _, ctrl := range sbw.sbControllers { + res = append(res, ctrl.getSandbox()) + } + return res +} + +func (sbw *sbmWatcher) stop() { + var wg sync.WaitGroup + + // stop all sandbox controllers + sbw.sbMu.Lock() + for _, sbMon := range sbw.sbControllers { + wg.Add(1) + // overwrite the delete function + sbMon.delFn = func() { + defer wg.Done() + } + // stop the sandbox controller + sbMon.stop() + } + sbw.sbMu.Unlock() + + // wait until all sandbox controllers have stopped + wg.Wait() +} diff --git a/internal/utils/system/system.go b/internal/utils/system/system.go index 3bfb116..f616693 100644 --- a/internal/utils/system/system.go +++ b/internal/utils/system/system.go @@ -1,11 +1,13 @@ package system import ( + "fmt" "io" "os" "path" "path/filepath" + "github.com/denisbrodbeck/machineid" "gopkg.in/natefinch/lumberjack.v2" ) @@ -52,3 +54,11 @@ func GetRollingLogWriter(logDirPath, logName string, uid, gid int) (io.Writer, s MaxAge: 28, // days }, logPath, nil } + +func GetMachineID() (string, error) { + machineID, err := machineid.ProtectedID("signadotCLI") + if err != nil { + return "", fmt.Errorf("couldn't read machine-id, %v", err) + } + return machineID[:63], nil +} From 96c0d06c6d9d3835c4c3a2ad512bcabd0c704e47 Mon Sep 17 00:00:00 2001 From: Daniel De Vera Date: Tue, 7 Nov 2023 17:52:44 -0300 Subject: [PATCH 03/10] Bug fix --- internal/command/local/connect.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/command/local/connect.go b/internal/command/local/connect.go index 7706776..9c7aeb2 100644 --- a/internal/command/local/connect.go +++ b/internal/command/local/connect.go @@ -194,7 +194,7 @@ func waitConnect(localConfig *config.LocalConnect, out io.Writer) error { ) defer ticker.Stop() for { - status, err := sbmgr.GetStatus() + status, err = sbmgr.GetStatus() if err != nil { fmt.Fprintf(out, "error getting status: %s", err.Error()) connectErrs = []error{err} From 3bb0bc094ca287ace1584249fdeed849071b6ee9 Mon Sep 17 00:00:00 2001 From: Daniel De Vera Date: Wed, 8 Nov 2023 09:54:10 -0300 Subject: [PATCH 04/10] Another fix --- internal/locald/sandboxmanager/sandbox_controller.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/locald/sandboxmanager/sandbox_controller.go b/internal/locald/sandboxmanager/sandbox_controller.go index 2d56a24..cb7f2b5 100644 --- a/internal/locald/sandboxmanager/sandbox_controller.go +++ b/internal/locald/sandboxmanager/sandbox_controller.go @@ -43,6 +43,8 @@ func newSBController(log *slog.Logger, sandbox *tunapiv1.WatchLocalSandboxesResp } // run the controller go ctrl.run() + // trigger a reconcile + ctrl.triggerReconcile() return ctrl } From 29778f879a022236d9bcfd2f1985fa81ef392283 Mon Sep 17 00:00:00 2001 From: Daniel De Vera Date: Thu, 9 Nov 2023 11:13:33 -0300 Subject: [PATCH 05/10] Reflect changes in tunnel API spec --- go.mod | 2 +- go.sum | 4 ++-- internal/locald/sandboxmanager/revtun.go | 2 +- .../sandboxmanager/sandbox_controller.go | 18 +++++++++--------- .../locald/sandboxmanager/sandboxes_watcher.go | 4 ++-- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index d7a1bc1..167faf6 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 github.com/signadot/go-sdk v0.3.8-0.20231107200143-6c7fe4258298 - github.com/signadot/libconnect v0.1.1-0.20231107195908-d23167fa13fe + github.com/signadot/libconnect v0.1.1-0.20231109133751-e261a2f69044 github.com/spf13/cobra v1.6.0 github.com/spf13/viper v1.11.0 github.com/theckman/yacspin v0.13.12 diff --git a/go.sum b/go.sum index 1205078..aa18ce3 100644 --- a/go.sum +++ b/go.sum @@ -364,8 +364,8 @@ github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUz github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/signadot/go-sdk v0.3.8-0.20231107200143-6c7fe4258298 h1:zNEYJUQEbYMpEkFekq8wDjC6atbKRxPHIrC5UT6pE/A= github.com/signadot/go-sdk v0.3.8-0.20231107200143-6c7fe4258298/go.mod h1:mLzoMuSE0GsFLONRjjYYHQBsU9twXML1BrExSvpMqeI= -github.com/signadot/libconnect v0.1.1-0.20231107195908-d23167fa13fe h1:QcR2WYy8Vg+N+yJI59w3ozpBYiTWGorMbQP95mlppEI= -github.com/signadot/libconnect v0.1.1-0.20231107195908-d23167fa13fe/go.mod h1:4OzWoyxyoh56h4jgCw/FBJVxyHB45qpwHDVWbsGfFTg= +github.com/signadot/libconnect v0.1.1-0.20231109133751-e261a2f69044 h1:sl4y7UE8aar1gud3yCZUfMyUHeLkstNXJ2MRnoX7jBI= +github.com/signadot/libconnect v0.1.1-0.20231109133751-e261a2f69044/go.mod h1:4OzWoyxyoh56h4jgCw/FBJVxyHB45qpwHDVWbsGfFTg= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= diff --git a/internal/locald/sandboxmanager/revtun.go b/internal/locald/sandboxmanager/revtun.go index e555ec4..f425abd 100644 --- a/internal/locald/sandboxmanager/revtun.go +++ b/internal/locald/sandboxmanager/revtun.go @@ -27,7 +27,7 @@ type rt struct { } func newRevtun(log *slog.Logger, rtc revtun.Client, rk string, - xw *tunapiv1.WatchLocalSandboxesResponse_ExternalWorkload) (*rt, error) { + xw *tunapiv1.ExternalWorkload) (*rt, error) { // define the revtun config (that will be used to setup the reverse tunnel) rtConfig := &rtproto.Config{ SandboxRoutingKey: rk, diff --git a/internal/locald/sandboxmanager/sandbox_controller.go b/internal/locald/sandboxmanager/sandbox_controller.go index cb7f2b5..e6f5b19 100644 --- a/internal/locald/sandboxmanager/sandbox_controller.go +++ b/internal/locald/sandboxmanager/sandbox_controller.go @@ -20,7 +20,7 @@ type sbController struct { sync.Mutex log *slog.Logger - sandbox *tunapiv1.WatchLocalSandboxesResponse_Sandbox + sandbox *tunapiv1.Sandbox revtunClient revtun.Client revtuns map[string]*rt delFn func() @@ -29,7 +29,7 @@ type sbController struct { doneCh chan struct{} } -func newSBController(log *slog.Logger, sandbox *tunapiv1.WatchLocalSandboxesResponse_Sandbox, +func newSBController(log *slog.Logger, sandbox *tunapiv1.Sandbox, rtClient revtun.Client, delFn func()) *sbController { // create the controller ctrl := &sbController{ @@ -69,7 +69,7 @@ reconcileLoop: // we're done, clean up revtuns ctrl.log.Debug("cleaning up reverse tunnels") - ctrl.updateSandbox(&tunapiv1.WatchLocalSandboxesResponse_Sandbox{}) + ctrl.updateSandbox(&tunapiv1.Sandbox{}) ctrl.reconcile() ctrl.delFn() } @@ -82,13 +82,13 @@ func (ctrl *sbController) stop() { } } -func (ctrl *sbController) getSandbox() *tunapiv1.WatchLocalSandboxesResponse_Sandbox { +func (ctrl *sbController) getSandbox() *tunapiv1.Sandbox { ctrl.Lock() defer ctrl.Unlock() return ctrl.sandbox } -func (ctrl *sbController) updateSandbox(sandbox *tunapiv1.WatchLocalSandboxesResponse_Sandbox) { +func (ctrl *sbController) updateSandbox(sandbox *tunapiv1.Sandbox) { ctrl.Lock() defer ctrl.Unlock() @@ -134,7 +134,7 @@ func (ctrl *sbController) reconcile() { // reconcile ctrl.log.Debug("reconciling tunnels") // put the xwls in a map - xwMap := make(map[string]*tunapiv1.WatchLocalSandboxesResponse_ExternalWorkload, len(ctrl.sandbox.ExternalWorkloads)) + xwMap := make(map[string]*tunapiv1.ExternalWorkload, len(ctrl.sandbox.ExternalWorkloads)) for _, xw := range ctrl.sandbox.ExternalWorkloads { xwMap[xw.Name] = xw } @@ -209,14 +209,14 @@ func (ctrl *sbController) closeRevTunnel(xwName string) { } } -func (ctrl *sbController) compareExternalWorkloadsSpec(a, b *apiv1.WatchLocalSandboxesResponse_ExternalWorkload) bool { +func (ctrl *sbController) compareExternalWorkloadsSpec(a, b *apiv1.ExternalWorkload) bool { // for comparison, ignore status info - specA := &apiv1.WatchLocalSandboxesResponse_ExternalWorkload{ + specA := &apiv1.ExternalWorkload{ Name: a.Name, Baseline: a.Baseline, WorkloadPortMapping: a.WorkloadPortMapping, } - specB := &apiv1.WatchLocalSandboxesResponse_ExternalWorkload{ + specB := &apiv1.ExternalWorkload{ Name: b.Name, Baseline: b.Baseline, WorkloadPortMapping: b.WorkloadPortMapping, diff --git a/internal/locald/sandboxmanager/sandboxes_watcher.go b/internal/locald/sandboxmanager/sandboxes_watcher.go index c65d2fd..553401e 100644 --- a/internal/locald/sandboxmanager/sandboxes_watcher.go +++ b/internal/locald/sandboxmanager/sandboxes_watcher.go @@ -141,11 +141,11 @@ func (sbw *sbmWatcher) processStreamEvent(event *tunapiv1.WatchLocalSandboxesRes } } -func (sbw *sbmWatcher) getSandboxes() []*tunapiv1.WatchLocalSandboxesResponse_Sandbox { +func (sbw *sbmWatcher) getSandboxes() []*tunapiv1.Sandbox { sbw.sbMu.Lock() defer sbw.sbMu.Unlock() - res := make([]*tunapiv1.WatchLocalSandboxesResponse_Sandbox, 0, len(sbw.sbControllers)) + res := make([]*tunapiv1.Sandbox, 0, len(sbw.sbControllers)) for _, ctrl := range sbw.sbControllers { res = append(res, ctrl.getSandbox()) } From bd37be9783edf0ea82c7508f579902504f4b28ee Mon Sep 17 00:00:00 2001 From: Daniel De Vera Date: Thu, 9 Nov 2023 14:44:15 -0300 Subject: [PATCH 06/10] Remove unneeded code. --- internal/locald/api/sandboxmanager/convert.go | 44 ------------------- 1 file changed, 44 deletions(-) diff --git a/internal/locald/api/sandboxmanager/convert.go b/internal/locald/api/sandboxmanager/convert.go index 5be3e88..6dc25ec 100644 --- a/internal/locald/api/sandboxmanager/convert.go +++ b/internal/locald/api/sandboxmanager/convert.go @@ -6,54 +6,10 @@ import ( "fmt" "github.com/signadot/cli/internal/config" - "github.com/signadot/go-sdk/models" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/types/known/structpb" ) -func ToModelsSandboxSpec(grpcSpec *structpb.Struct) (*models.SandboxSpec, error) { - d, e := grpcSpec.MarshalJSON() - if e != nil { - return nil, e - } - sbs := &models.SandboxSpec{} - if err := json.Unmarshal(d, sbs); err != nil { - return nil, err - } - return sbs, nil -} - -func ToGRPCSandbox(sb *models.Sandbox) (*structpb.Struct, error) { - d, _ := json.Marshal(sb) - un := map[string]any{} - if err := json.Unmarshal(d, &un); err != nil { - return nil, err - } - return structpb.NewStruct(un) -} - -func ToGRPCSandboxSpec(sbs *models.SandboxSpec) (*structpb.Struct, error) { - d, _ := json.Marshal(sbs) - un := map[string]any{} - if err := json.Unmarshal(d, &un); err != nil { - return nil, err - } - return structpb.NewStruct(un) -} - -// TODO maybe use generics here? -func ToModelsSandbox(grpcSandbox *structpb.Struct) (*models.Sandbox, error) { - d, e := grpcSandbox.MarshalJSON() - if e != nil { - return nil, e - } - sb := &models.Sandbox{} - if err := json.Unmarshal(d, sb); err != nil { - return nil, err - } - return sb, nil -} - func ToGRPCCIConfig(ciConfig *config.ConnectInvocationConfig) (*structpb.Struct, error) { d, _ := json.Marshal(ciConfig) un := map[string]any{} From eaf51d88248e472a8cafec20433975ce1a1cd6cc Mon Sep 17 00:00:00 2001 From: Daniel De Vera Date: Thu, 9 Nov 2023 16:39:13 -0300 Subject: [PATCH 07/10] Get rid of API and API key in locald command --- internal/command/local/connect.go | 3 --- internal/command/local/printers.go | 9 +-------- internal/config/locald.go | 8 -------- internal/locald/sandboxmanager/sandbox_server.go | 1 - 4 files changed, 1 insertion(+), 20 deletions(-) diff --git a/internal/command/local/connect.go b/internal/command/local/connect.go index 9c7aeb2..939f4dd 100644 --- a/internal/command/local/connect.go +++ b/internal/command/local/connect.go @@ -19,7 +19,6 @@ import ( "github.com/signadot/cli/internal/utils/system" "github.com/signadot/libconnect/common/processes" "github.com/spf13/cobra" - "github.com/spf13/viper" "sigs.k8s.io/yaml" ) @@ -89,8 +88,6 @@ func runConnect(cmd *cobra.Command, out io.Writer, cfg *config.LocalConnect, arg Username: user.Username, }, ConnectionConfig: connConfig, - API: cfg.API, - APIKey: viper.GetString("api_key"), Debug: cfg.LocalConfig.Debug, } if cfg.DumpCIConfig { diff --git a/internal/command/local/printers.go b/internal/command/local/printers.go index 3b4d0c7..8632006 100644 --- a/internal/command/local/printers.go +++ b/internal/command/local/printers.go @@ -72,7 +72,6 @@ func getRawRuntimeConfig(cfg *config.LocalStatus, ciConfig *config.ConnectInvoca ConfigDir string `json:"configDir"` User *PrintableUser `json:"user"` ConnectionConfig *connectcfg.ConnectionConfig `json:"connectionConfig"` - API *PrintableAPI `json:"api"` Debug bool `json:"debug"` } @@ -88,13 +87,7 @@ func getRawRuntimeConfig(cfg *config.LocalStatus, ciConfig *config.ConnectInvoca UIDHome: ciConfig.User.UIDHome, }, ConnectionConfig: ciConfig.ConnectionConfig, - API: &PrintableAPI{ - ConfigFile: ciConfig.API.ConfigFile, - Org: ciConfig.API.Org, - MaskedAPIKey: ciConfig.API.MaskedAPIKey, - APIURL: ciConfig.API.APIURL, - }, - Debug: ciConfig.Debug, + Debug: ciConfig.Debug, } } else { // Standard view diff --git a/internal/config/locald.go b/internal/config/locald.go index aa8921f..8458b30 100644 --- a/internal/config/locald.go +++ b/internal/config/locald.go @@ -7,7 +7,6 @@ import ( connectcfg "github.com/signadot/libconnect/config" "github.com/spf13/cobra" - "github.com/spf13/viper" "sigs.k8s.io/yaml" ) @@ -54,11 +53,6 @@ func (ld *LocalDaemon) InitLocalDaemon() error { return err } - viper.Set("api_url", ciConfig.API.APIURL) - viper.Set("api_key", ciConfig.APIKey) - if err := ciConfig.API.InitAPITransport(ciConfig.APIKey); err != nil { - return err - } ld.ConnectInvocationConfig = ciConfig return nil @@ -77,8 +71,6 @@ type ConnectInvocationConfig struct { SignadotDir string `json:"signadotDir"` User *ConnectInvocationUser `json:"user"` ConnectionConfig *connectcfg.ConnectionConfig `json:"connectionConfig"` - API *API `json:"api"` - APIKey string `json:"apiKey"` Debug bool `json:"debug"` } diff --git a/internal/locald/sandboxmanager/sandbox_server.go b/internal/locald/sandboxmanager/sandbox_server.go index 73727d7..aabbe13 100644 --- a/internal/locald/sandboxmanager/sandbox_server.go +++ b/internal/locald/sandboxmanager/sandbox_server.go @@ -57,7 +57,6 @@ func newSandboxManagerGRPCServer(log *slog.Logger, ciConfig *config.ConnectInvoc func (s *sbmServer) Status(ctx context.Context, req *sbapi.StatusRequest) (*sbapi.StatusResponse, error) { // make a local copy sbConfig := *s.ciConfig - sbConfig.APIKey = sbConfig.APIKey[:6] + "..." grpcCIConfig, err := sbapi.ToGRPCCIConfig(&sbConfig) if err != nil { From 399b23ef5910fcfe517802ba8cf0b2f8512fcf7f Mon Sep 17 00:00:00 2001 From: daniel-de-vera <118383315+daniel-de-vera@users.noreply.github.com> Date: Wed, 15 Nov 2023 09:27:20 -0300 Subject: [PATCH 08/10] Implementation of sandboxes watcher status (#92) * Implementation of sandboxes watcher status * PR feeback * Include machine id to local status --- internal/command/local/printers.go | 212 +++++++++-------- internal/locald/api/common.pb.go | 224 ++++++++++++------ internal/locald/api/common.proto | 5 + .../sandboxmanager/sandbox_manager_api.pb.go | 83 ++++--- .../sandboxmanager/sandbox_manager_api.proto | 1 + .../locald/sandboxmanager/sandbox_server.go | 7 + .../sandboxmanager/sandboxes_watcher.go | 81 +++++-- internal/locald/sandboxmanager/sdk.go | 22 ++ 8 files changed, 405 insertions(+), 230 deletions(-) diff --git a/internal/command/local/printers.go b/internal/command/local/printers.go index 8632006..977ccfa 100644 --- a/internal/command/local/printers.go +++ b/internal/command/local/printers.go @@ -9,6 +9,7 @@ import ( commonapi "github.com/signadot/cli/internal/locald/api" sbmapi "github.com/signadot/cli/internal/locald/api/sandboxmanager" sbmgr "github.com/signadot/cli/internal/locald/sandboxmanager" + "github.com/signadot/cli/internal/utils/system" connectcfg "github.com/signadot/libconnect/config" ) @@ -28,25 +29,28 @@ func printRawStatus(cfg *config.LocalStatus, out io.Writer, printer func(out io. } type rawStatus struct { - RuntimeConfig any `json:"runtimeConfig,omitempty"` - Localnet any `json:"localnet,omitempty"` - Hosts any `json:"hosts,omitempty"` - Portforward any `json:"portforward,omitempty"` - Sandboxes any `json:"sandboxes,omitempty"` + RuntimeConfig any `json:"runtimeConfig,omitempty"` + Localnet any `json:"localnet,omitempty"` + Hosts any `json:"hosts,omitempty"` + Portforward any `json:"portforward,omitempty"` + SandboxesWatcher any `json:"sandboxesWatcher,omitempty"` + Sandboxes any `json:"sandboxes,omitempty"` } rawSt := rawStatus{ - RuntimeConfig: getRawRuntimeConfig(cfg, ciConfig), - Localnet: getRawLocalnet(cfg, ciConfig, status.Localnet, statusMap), - Hosts: getRawHosts(cfg, ciConfig, status.Hosts, statusMap), - Portforward: getRawPortforward(cfg, ciConfig, status.Portforward, statusMap), - Sandboxes: statusMap["sandboxes"], + RuntimeConfig: getRawRuntimeConfig(cfg, ciConfig), + Localnet: getRawLocalnet(cfg, ciConfig, status.Localnet, statusMap), + Hosts: getRawHosts(cfg, ciConfig, status.Hosts, statusMap), + Portforward: getRawPortforward(cfg, ciConfig, status.Portforward, statusMap), + SandboxesWatcher: getRawWatcher(cfg, status.Watcher, statusMap), + Sandboxes: statusMap["sandboxes"], } return printer(out, rawSt) } func getRawRuntimeConfig(cfg *config.LocalStatus, ciConfig *config.ConnectInvocationConfig) any { + machineID, _ := system.GetMachineID() var runtimeConfig any if cfg.Details { @@ -58,19 +62,13 @@ func getRawRuntimeConfig(cfg *config.LocalStatus, ciConfig *config.ConnectInvoca UIDHome string `json:"uidHome"` } - type PrintableAPI struct { - ConfigFile string `json:"configFile"` - Org string `json:"org"` - MaskedAPIKey string `json:"maskedAPIKey"` - APIURL string `json:"apiURL"` - } - type PrintableRuntimeConfig struct { RootDaemon bool `json:"rootDaemon"` APIPort uint16 `json:"apiPort"` LocalNetPort uint16 `json:"localNetPort"` ConfigDir string `json:"configDir"` User *PrintableUser `json:"user"` + MachineID string `json:"machineID"` ConnectionConfig *connectcfg.ConnectionConfig `json:"connectionConfig"` Debug bool `json:"debug"` } @@ -86,6 +84,7 @@ func getRawRuntimeConfig(cfg *config.LocalStatus, ciConfig *config.ConnectInvoca Username: ciConfig.User.Username, UIDHome: ciConfig.User.UIDHome, }, + MachineID: machineID, ConnectionConfig: ciConfig.ConnectionConfig, Debug: ciConfig.Debug, } @@ -109,39 +108,35 @@ func getRawRuntimeConfig(cfg *config.LocalStatus, ciConfig *config.ConnectInvoca func getRawLocalnet(cfg *config.LocalStatus, ciConfig *config.ConnectInvocationConfig, localnet *commonapi.LocalNetStatus, statusMap map[string]any) any { - var result any - if !ciConfig.WithRootManager { return localnet } if cfg.Details { // Details view - result = statusMap["localnet"] - } else { - // Standard view - type PrintableLocalnet struct { - Healthy bool `json:"healthy"` - LastErrorReason string `json:"lastErrorReason,omitempty"` - } + return statusMap["localnet"] + } + + // Standard view + type PrintableLocalnet struct { + Healthy bool `json:"healthy"` + LastErrorReason string `json:"lastErrorReason,omitempty"` + } + result := &PrintableLocalnet{ + Healthy: false, + } + if localnet == nil || localnet.Health == nil { + return result + } + if localnet.Health.Healthy { result = &PrintableLocalnet{ - Healthy: false, + Healthy: true, } - - if localnet != nil { - if localnet.Health != nil { - if localnet.Health.Healthy { - result = &PrintableLocalnet{ - Healthy: true, - } - } else { - result = &PrintableLocalnet{ - Healthy: false, - LastErrorReason: localnet.Health.LastErrorReason, - } - } - } + } else { + result = &PrintableLocalnet{ + Healthy: false, + LastErrorReason: localnet.Health.LastErrorReason, } } return result @@ -149,41 +144,37 @@ func getRawLocalnet(cfg *config.LocalStatus, ciConfig *config.ConnectInvocationC func getRawHosts(cfg *config.LocalStatus, ciConfig *config.ConnectInvocationConfig, hosts *commonapi.HostsStatus, statusMap map[string]any) any { - var result any - if !ciConfig.WithRootManager { return hosts } if cfg.Details { // Details view - result = statusMap["hosts"] - } else { - // Standard view - type PrintableHosts struct { - Healthy bool `json:"healthy"` - NumHosts uint32 `json:"numHosts"` - LastErrorReason string `json:"lastErrorReason,omitempty"` - } + return statusMap["hosts"] + } + + // Standard view + type PrintableHosts struct { + Healthy bool `json:"healthy"` + NumHosts uint32 `json:"numHosts"` + LastErrorReason string `json:"lastErrorReason,omitempty"` + } + result := &PrintableHosts{ + Healthy: false, + } + if hosts == nil || hosts.Health == nil { + return result + } + if hosts.Health.Healthy { result = &PrintableHosts{ - Healthy: false, + Healthy: true, + NumHosts: hosts.NumHosts, } - - if hosts != nil { - if hosts.Health != nil { - if hosts.Health.Healthy { - result = &PrintableHosts{ - Healthy: true, - NumHosts: hosts.NumHosts, - } - } else { - result = &PrintableHosts{ - Healthy: false, - LastErrorReason: hosts.Health.LastErrorReason, - } - } - } + } else { + result = &PrintableHosts{ + Healthy: false, + LastErrorReason: hosts.Health.LastErrorReason, } } return result @@ -191,41 +182,69 @@ func getRawHosts(cfg *config.LocalStatus, ciConfig *config.ConnectInvocationConf func getRawPortforward(cfg *config.LocalStatus, ciConfig *config.ConnectInvocationConfig, portforward *commonapi.PortForwardStatus, statusMap map[string]any) any { - var result any - if ciConfig.ConnectionConfig.Type != connectcfg.PortForwardLinkType { return portforward } if cfg.Details { // Details view - result = statusMap["portforward"] - } else { - // Standard view - type PrintablePortforward struct { - Healthy bool `json:"healthy"` - LocalAddress string `json:"localAddress"` - LastErrorReason string `json:"lastErrorReason,omitempty"` - } + return statusMap["portforward"] + } + + // Standard view + type PrintablePortforward struct { + Healthy bool `json:"healthy"` + LocalAddress string `json:"localAddress"` + LastErrorReason string `json:"lastErrorReason,omitempty"` + } + result := &PrintablePortforward{ + Healthy: false, + } + if portforward == nil || portforward.Health == nil { + return result + } + if portforward.Health.Healthy { + result = &PrintablePortforward{ + Healthy: true, + LocalAddress: portforward.LocalAddress, + } + } else { result = &PrintablePortforward{ - Healthy: false, + Healthy: false, + LastErrorReason: portforward.Health.LastErrorReason, } + } + return result +} - if portforward != nil { - if portforward.Health != nil { - if portforward.Health.Healthy { - result = &PrintablePortforward{ - Healthy: true, - LocalAddress: portforward.LocalAddress, - } - } else { - result = &PrintablePortforward{ - Healthy: false, - LastErrorReason: portforward.Health.LastErrorReason, - } - } - } +func getRawWatcher(cfg *config.LocalStatus, watcher *commonapi.WatcherStatus, + statusMap map[string]any) any { + if cfg.Details { + // Details view + return statusMap["watcher"] + } + + // Standard view + type PrintableWatcher struct { + Healthy bool `json:"healthy"` + LastErrorReason string `json:"lastErrorReason,omitempty"` + } + + result := &PrintableWatcher{ + Healthy: false, + } + if watcher == nil || watcher.Health == nil { + return result + } + if watcher.Health.Healthy { + result = &PrintableWatcher{ + Healthy: true, + } + } else { + result = &PrintableWatcher{ + Healthy: false, + LastErrorReason: watcher.Health.LastErrorReason, } } return result @@ -270,6 +289,8 @@ type statusPrinter struct { } func (p *statusPrinter) printRuntimeConfig() { + machineID, _ := system.GetMachineID() + var runtimeConfig string if p.ciConfig.WithRootManager { runtimeConfig = fmt.Sprintf("runtime config: cluster %s, running with root-daemon", @@ -279,7 +300,7 @@ func (p *statusPrinter) printRuntimeConfig() { p.white(p.ciConfig.ConnectionConfig.Cluster)) } if p.cfg.Details { - runtimeConfig += fmt.Sprintf(" (config-dir: %s)", p.ciConfig.SignadotDir) + runtimeConfig += fmt.Sprintf(" (config-dir: %s, machine-id %s)", p.ciConfig.SignadotDir, machineID) } p.printLine(p.out, 0, runtimeConfig, "*") } @@ -300,6 +321,7 @@ func (p *statusPrinter) printSuccess() { p.printLocalnetStatus() p.printHostsStatus() } + p.printSandboxesWatcherStatus() p.printSandboxStatus() } @@ -329,6 +351,10 @@ func (p *statusPrinter) printHostsStatus() { p.printLine(p.out, 1, fmt.Sprintf("%d hosts accessible via /etc/hosts", p.status.Hosts.NumHosts), "*") } +func (p *statusPrinter) printSandboxesWatcherStatus() { + p.printLine(p.out, 1, "sandboxes watcher is running", "*") +} + func (p *statusPrinter) printSandboxStatus() { p.printLine(p.out, 0, "Connected Sandboxes:", "*") if len(p.status.Sandboxes) == 0 { diff --git a/internal/locald/api/common.pb.go b/internal/locald/api/common.pb.go index 05eaf6a..db8a63a 100644 --- a/internal/locald/api/common.pb.go +++ b/internal/locald/api/common.pb.go @@ -285,6 +285,54 @@ func (x *PortForwardStatus) GetLocalAddress() string { return "" } +// Sandboxes watcher status (produced by local controller) +type WatcherStatus struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Health *ServiceHealth `protobuf:"bytes,1,opt,name=health,proto3" json:"health,omitempty"` +} + +func (x *WatcherStatus) Reset() { + *x = WatcherStatus{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_locald_api_common_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WatcherStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WatcherStatus) ProtoMessage() {} + +func (x *WatcherStatus) ProtoReflect() protoreflect.Message { + mi := &file_internal_locald_api_common_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WatcherStatus.ProtoReflect.Descriptor instead. +func (*WatcherStatus) Descriptor() ([]byte, []int) { + return file_internal_locald_api_common_proto_rawDescGZIP(), []int{4} +} + +func (x *WatcherStatus) GetHealth() *ServiceHealth { + if x != nil { + return x.Health + } + return nil +} + // Sandbox status (produced by local controller) type SandboxStatus struct { state protoimpl.MessageState @@ -299,7 +347,7 @@ type SandboxStatus struct { func (x *SandboxStatus) Reset() { *x = SandboxStatus{} if protoimpl.UnsafeEnabled { - mi := &file_internal_locald_api_common_proto_msgTypes[4] + mi := &file_internal_locald_api_common_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -312,7 +360,7 @@ func (x *SandboxStatus) String() string { func (*SandboxStatus) ProtoMessage() {} func (x *SandboxStatus) ProtoReflect() protoreflect.Message { - mi := &file_internal_locald_api_common_proto_msgTypes[4] + mi := &file_internal_locald_api_common_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -325,7 +373,7 @@ func (x *SandboxStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxStatus.ProtoReflect.Descriptor instead. func (*SandboxStatus) Descriptor() ([]byte, []int) { - return file_internal_locald_api_common_proto_rawDescGZIP(), []int{4} + return file_internal_locald_api_common_proto_rawDescGZIP(), []int{5} } func (x *SandboxStatus) GetName() string { @@ -363,7 +411,7 @@ type SandboxStatus_Baseline struct { func (x *SandboxStatus_Baseline) Reset() { *x = SandboxStatus_Baseline{} if protoimpl.UnsafeEnabled { - mi := &file_internal_locald_api_common_proto_msgTypes[5] + mi := &file_internal_locald_api_common_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -376,7 +424,7 @@ func (x *SandboxStatus_Baseline) String() string { func (*SandboxStatus_Baseline) ProtoMessage() {} func (x *SandboxStatus_Baseline) ProtoReflect() protoreflect.Message { - mi := &file_internal_locald_api_common_proto_msgTypes[5] + mi := &file_internal_locald_api_common_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -389,7 +437,7 @@ func (x *SandboxStatus_Baseline) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxStatus_Baseline.ProtoReflect.Descriptor instead. func (*SandboxStatus_Baseline) Descriptor() ([]byte, []int) { - return file_internal_locald_api_common_proto_rawDescGZIP(), []int{4, 0} + return file_internal_locald_api_common_proto_rawDescGZIP(), []int{5, 0} } func (x *SandboxStatus_Baseline) GetApiVersion() string { @@ -432,7 +480,7 @@ type SandboxStatus_BaselineToLocal struct { func (x *SandboxStatus_BaselineToLocal) Reset() { *x = SandboxStatus_BaselineToLocal{} if protoimpl.UnsafeEnabled { - mi := &file_internal_locald_api_common_proto_msgTypes[6] + mi := &file_internal_locald_api_common_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -445,7 +493,7 @@ func (x *SandboxStatus_BaselineToLocal) String() string { func (*SandboxStatus_BaselineToLocal) ProtoMessage() {} func (x *SandboxStatus_BaselineToLocal) ProtoReflect() protoreflect.Message { - mi := &file_internal_locald_api_common_proto_msgTypes[6] + mi := &file_internal_locald_api_common_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -458,7 +506,7 @@ func (x *SandboxStatus_BaselineToLocal) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxStatus_BaselineToLocal.ProtoReflect.Descriptor instead. func (*SandboxStatus_BaselineToLocal) Descriptor() ([]byte, []int) { - return file_internal_locald_api_common_proto_rawDescGZIP(), []int{4, 1} + return file_internal_locald_api_common_proto_rawDescGZIP(), []int{5, 1} } func (x *SandboxStatus_BaselineToLocal) GetBaselinePort() int32 { @@ -494,7 +542,7 @@ type SandboxStatus_LocalWorkload struct { func (x *SandboxStatus_LocalWorkload) Reset() { *x = SandboxStatus_LocalWorkload{} if protoimpl.UnsafeEnabled { - mi := &file_internal_locald_api_common_proto_msgTypes[7] + mi := &file_internal_locald_api_common_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -507,7 +555,7 @@ func (x *SandboxStatus_LocalWorkload) String() string { func (*SandboxStatus_LocalWorkload) ProtoMessage() {} func (x *SandboxStatus_LocalWorkload) ProtoReflect() protoreflect.Message { - mi := &file_internal_locald_api_common_proto_msgTypes[7] + mi := &file_internal_locald_api_common_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -520,7 +568,7 @@ func (x *SandboxStatus_LocalWorkload) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxStatus_LocalWorkload.ProtoReflect.Descriptor instead. func (*SandboxStatus_LocalWorkload) Descriptor() ([]byte, []int) { - return file_internal_locald_api_common_proto_rawDescGZIP(), []int{4, 2} + return file_internal_locald_api_common_proto_rawDescGZIP(), []int{5, 2} } func (x *SandboxStatus_LocalWorkload) GetName() string { @@ -597,49 +645,53 @@ var file_internal_locald_api_common_proto_rawDesc = []byte{ 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0xe4, - 0x04, 0x0a, 0x0d, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, - 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x69, - 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x4f, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x77, - 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, - 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, - 0x6f, 0x78, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x57, 0x6f, - 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x57, 0x6f, 0x72, - 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x1a, 0x70, 0x0a, 0x08, 0x42, 0x61, 0x73, 0x65, 0x6c, 0x69, - 0x6e, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x1a, 0x5b, 0x0a, 0x0f, 0x42, 0x61, 0x73, 0x65, - 0x6c, 0x69, 0x6e, 0x65, 0x54, 0x6f, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x62, - 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x0c, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x50, 0x6f, 0x72, 0x74, - 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0xfd, 0x01, 0x0a, 0x0d, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x57, - 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x08, 0x62, - 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, - 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, - 0x78, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, - 0x52, 0x08, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x5a, 0x0a, 0x13, 0x77, 0x6f, - 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, - 0x67, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x54, 0x6f, 0x4c, 0x6f, 0x63, 0x61, - 0x6c, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x4d, - 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x3d, 0x0a, 0x0d, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, - 0x5f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, - 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x0c, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x48, - 0x65, 0x61, 0x6c, 0x74, 0x68, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x2f, 0x63, 0x6c, 0x69, - 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, - 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x41, + 0x0a, 0x0d, 0x57, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x30, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x18, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, + 0x68, 0x22, 0xe4, 0x04, 0x0a, 0x0d, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x6f, 0x75, 0x74, 0x69, + 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x6f, + 0x75, 0x74, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x4f, 0x0a, 0x0f, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x61, + 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x4c, 0x6f, 0x63, 0x61, + 0x6c, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x1a, 0x70, 0x0a, 0x08, 0x42, 0x61, 0x73, + 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x1a, 0x5b, 0x0a, 0x0f, 0x42, + 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x54, 0x6f, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x12, 0x23, + 0x0a, 0x0d, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x50, + 0x6f, 0x72, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0xfd, 0x01, 0x0a, 0x0d, 0x4c, 0x6f, 0x63, + 0x61, 0x6c, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3d, + 0x0a, 0x08, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x61, 0x6e, + 0x64, 0x62, 0x6f, 0x78, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x6c, + 0x69, 0x6e, 0x65, 0x52, 0x08, 0x62, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x5a, 0x0a, + 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x4d, 0x61, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x70, 0x69, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x54, 0x6f, 0x4c, + 0x6f, 0x63, 0x61, 0x6c, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x6f, + 0x72, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x3d, 0x0a, 0x0d, 0x74, 0x75, 0x6e, + 0x6e, 0x65, 0x6c, 0x5f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x0c, 0x74, 0x75, 0x6e, 0x6e, + 0x65, 0x6c, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x2f, + 0x63, 0x6c, 0x69, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, + 0x61, 0x6c, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -654,33 +706,35 @@ func file_internal_locald_api_common_proto_rawDescGZIP() []byte { return file_internal_locald_api_common_proto_rawDescData } -var file_internal_locald_api_common_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_internal_locald_api_common_proto_msgTypes = make([]protoimpl.MessageInfo, 9) var file_internal_locald_api_common_proto_goTypes = []interface{}{ (*ServiceHealth)(nil), // 0: apicommon.ServiceHealth (*LocalNetStatus)(nil), // 1: apicommon.LocalNetStatus (*HostsStatus)(nil), // 2: apicommon.HostsStatus (*PortForwardStatus)(nil), // 3: apicommon.PortForwardStatus - (*SandboxStatus)(nil), // 4: apicommon.SandboxStatus - (*SandboxStatus_Baseline)(nil), // 5: apicommon.SandboxStatus.Baseline - (*SandboxStatus_BaselineToLocal)(nil), // 6: apicommon.SandboxStatus.BaselineToLocal - (*SandboxStatus_LocalWorkload)(nil), // 7: apicommon.SandboxStatus.LocalWorkload - (*timestamp.Timestamp)(nil), // 8: google.protobuf.Timestamp + (*WatcherStatus)(nil), // 4: apicommon.WatcherStatus + (*SandboxStatus)(nil), // 5: apicommon.SandboxStatus + (*SandboxStatus_Baseline)(nil), // 6: apicommon.SandboxStatus.Baseline + (*SandboxStatus_BaselineToLocal)(nil), // 7: apicommon.SandboxStatus.BaselineToLocal + (*SandboxStatus_LocalWorkload)(nil), // 8: apicommon.SandboxStatus.LocalWorkload + (*timestamp.Timestamp)(nil), // 9: google.protobuf.Timestamp } var file_internal_locald_api_common_proto_depIdxs = []int32{ - 8, // 0: apicommon.ServiceHealth.last_error_time:type_name -> google.protobuf.Timestamp - 0, // 1: apicommon.LocalNetStatus.health:type_name -> apicommon.ServiceHealth - 0, // 2: apicommon.HostsStatus.health:type_name -> apicommon.ServiceHealth - 8, // 3: apicommon.HostsStatus.last_update_time:type_name -> google.protobuf.Timestamp - 0, // 4: apicommon.PortForwardStatus.health:type_name -> apicommon.ServiceHealth - 7, // 5: apicommon.SandboxStatus.local_workloads:type_name -> apicommon.SandboxStatus.LocalWorkload - 5, // 6: apicommon.SandboxStatus.LocalWorkload.baseline:type_name -> apicommon.SandboxStatus.Baseline - 6, // 7: apicommon.SandboxStatus.LocalWorkload.workloadPortMapping:type_name -> apicommon.SandboxStatus.BaselineToLocal - 0, // 8: apicommon.SandboxStatus.LocalWorkload.tunnel_health:type_name -> apicommon.ServiceHealth - 9, // [9:9] is the sub-list for method output_type - 9, // [9:9] is the sub-list for method input_type - 9, // [9:9] is the sub-list for extension type_name - 9, // [9:9] is the sub-list for extension extendee - 0, // [0:9] is the sub-list for field type_name + 9, // 0: apicommon.ServiceHealth.last_error_time:type_name -> google.protobuf.Timestamp + 0, // 1: apicommon.LocalNetStatus.health:type_name -> apicommon.ServiceHealth + 0, // 2: apicommon.HostsStatus.health:type_name -> apicommon.ServiceHealth + 9, // 3: apicommon.HostsStatus.last_update_time:type_name -> google.protobuf.Timestamp + 0, // 4: apicommon.PortForwardStatus.health:type_name -> apicommon.ServiceHealth + 0, // 5: apicommon.WatcherStatus.health:type_name -> apicommon.ServiceHealth + 8, // 6: apicommon.SandboxStatus.local_workloads:type_name -> apicommon.SandboxStatus.LocalWorkload + 6, // 7: apicommon.SandboxStatus.LocalWorkload.baseline:type_name -> apicommon.SandboxStatus.Baseline + 7, // 8: apicommon.SandboxStatus.LocalWorkload.workloadPortMapping:type_name -> apicommon.SandboxStatus.BaselineToLocal + 0, // 9: apicommon.SandboxStatus.LocalWorkload.tunnel_health:type_name -> apicommon.ServiceHealth + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name } func init() { file_internal_locald_api_common_proto_init() } @@ -738,7 +792,7 @@ func file_internal_locald_api_common_proto_init() { } } file_internal_locald_api_common_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxStatus); i { + switch v := v.(*WatcherStatus); i { case 0: return &v.state case 1: @@ -750,7 +804,7 @@ func file_internal_locald_api_common_proto_init() { } } file_internal_locald_api_common_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxStatus_Baseline); i { + switch v := v.(*SandboxStatus); i { case 0: return &v.state case 1: @@ -762,7 +816,7 @@ func file_internal_locald_api_common_proto_init() { } } file_internal_locald_api_common_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxStatus_BaselineToLocal); i { + switch v := v.(*SandboxStatus_Baseline); i { case 0: return &v.state case 1: @@ -774,6 +828,18 @@ func file_internal_locald_api_common_proto_init() { } } file_internal_locald_api_common_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SandboxStatus_BaselineToLocal); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_locald_api_common_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SandboxStatus_LocalWorkload); i { case 0: return &v.state @@ -792,7 +858,7 @@ func file_internal_locald_api_common_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_internal_locald_api_common_proto_rawDesc, NumEnums: 0, - NumMessages: 8, + NumMessages: 9, NumExtensions: 0, NumServices: 0, }, diff --git a/internal/locald/api/common.proto b/internal/locald/api/common.proto index cf795c3..ffa6ba9 100644 --- a/internal/locald/api/common.proto +++ b/internal/locald/api/common.proto @@ -36,6 +36,11 @@ message PortForwardStatus { string local_address = 2; } +// Sandboxes watcher status (produced by local controller) +message WatcherStatus { + ServiceHealth health = 1; +} + // Sandbox status (produced by local controller) message SandboxStatus { message Baseline { diff --git a/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go b/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go index 2febfb0..1062649 100644 --- a/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go +++ b/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go @@ -71,6 +71,7 @@ type StatusResponse struct { Localnet *api.LocalNetStatus `protobuf:"bytes,2,opt,name=localnet,proto3" json:"localnet,omitempty"` Hosts *api.HostsStatus `protobuf:"bytes,3,opt,name=hosts,proto3" json:"hosts,omitempty"` Portforward *api.PortForwardStatus `protobuf:"bytes,4,opt,name=portforward,proto3" json:"portforward,omitempty"` + Watcher *api.WatcherStatus `protobuf:"bytes,6,opt,name=watcher,proto3" json:"watcher,omitempty"` Sandboxes []*api.SandboxStatus `protobuf:"bytes,5,rep,name=sandboxes,proto3" json:"sandboxes,omitempty"` } @@ -134,6 +135,13 @@ func (x *StatusResponse) GetPortforward() *api.PortForwardStatus { return nil } +func (x *StatusResponse) GetWatcher() *api.WatcherStatus { + if x != nil { + return x.Watcher + } + return nil +} + func (x *StatusResponse) GetSandboxes() []*api.SandboxStatus { if x != nil { return x.Sandboxes @@ -230,7 +238,7 @@ var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDesc = 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x0f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, - 0xa3, 0x02, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0xd7, 0x02, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x09, 0x63, 0x69, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x08, @@ -244,29 +252,32 @@ var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDesc = 0x0b, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x0b, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x36, 0x0a, - 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x61, 0x6e, - 0x64, 0x62, 0x6f, 0x78, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, - 0x62, 0x6f, 0x78, 0x65, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x53, 0x68, 0x75, 0x74, - 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xaf, 0x01, 0x0a, - 0x11, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x41, - 0x50, 0x49, 0x12, 0x49, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x2e, 0x73, - 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x61, - 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4f, 0x0a, - 0x08, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1f, 0x2e, 0x73, 0x61, 0x6e, 0x64, - 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, - 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x61, 0x6e, - 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x68, 0x75, 0x74, - 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x3c, - 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x61, - 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x0b, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x32, 0x0a, + 0x07, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, + 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, + 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x07, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x72, 0x12, 0x36, 0x0a, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x09, + 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x68, 0x75, + 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x12, 0x0a, 0x10, + 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x32, 0xaf, 0x01, 0x0a, 0x11, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x72, 0x41, 0x50, 0x49, 0x12, 0x49, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x1d, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1e, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x4f, 0x0a, 0x08, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1f, 0x2e, + 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, + 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, + 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, + 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x42, 0x3c, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -291,23 +302,25 @@ var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_goTypes = (*api.LocalNetStatus)(nil), // 5: apicommon.LocalNetStatus (*api.HostsStatus)(nil), // 6: apicommon.HostsStatus (*api.PortForwardStatus)(nil), // 7: apicommon.PortForwardStatus - (*api.SandboxStatus)(nil), // 8: apicommon.SandboxStatus + (*api.WatcherStatus)(nil), // 8: apicommon.WatcherStatus + (*api.SandboxStatus)(nil), // 9: apicommon.SandboxStatus } var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_depIdxs = []int32{ 4, // 0: sandboxmanager.StatusResponse.ci_config:type_name -> google.protobuf.Struct 5, // 1: sandboxmanager.StatusResponse.localnet:type_name -> apicommon.LocalNetStatus 6, // 2: sandboxmanager.StatusResponse.hosts:type_name -> apicommon.HostsStatus 7, // 3: sandboxmanager.StatusResponse.portforward:type_name -> apicommon.PortForwardStatus - 8, // 4: sandboxmanager.StatusResponse.sandboxes:type_name -> apicommon.SandboxStatus - 0, // 5: sandboxmanager.SandboxManagerAPI.Status:input_type -> sandboxmanager.StatusRequest - 2, // 6: sandboxmanager.SandboxManagerAPI.Shutdown:input_type -> sandboxmanager.ShutdownRequest - 1, // 7: sandboxmanager.SandboxManagerAPI.Status:output_type -> sandboxmanager.StatusResponse - 3, // 8: sandboxmanager.SandboxManagerAPI.Shutdown:output_type -> sandboxmanager.ShutdownResponse - 7, // [7:9] is the sub-list for method output_type - 5, // [5:7] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 8, // 4: sandboxmanager.StatusResponse.watcher:type_name -> apicommon.WatcherStatus + 9, // 5: sandboxmanager.StatusResponse.sandboxes:type_name -> apicommon.SandboxStatus + 0, // 6: sandboxmanager.SandboxManagerAPI.Status:input_type -> sandboxmanager.StatusRequest + 2, // 7: sandboxmanager.SandboxManagerAPI.Shutdown:input_type -> sandboxmanager.ShutdownRequest + 1, // 8: sandboxmanager.SandboxManagerAPI.Status:output_type -> sandboxmanager.StatusResponse + 3, // 9: sandboxmanager.SandboxManagerAPI.Shutdown:output_type -> sandboxmanager.ShutdownResponse + 8, // [8:10] is the sub-list for method output_type + 6, // [6:8] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_init() } diff --git a/internal/locald/api/sandboxmanager/sandbox_manager_api.proto b/internal/locald/api/sandboxmanager/sandbox_manager_api.proto index 5164a18..96ce7b5 100644 --- a/internal/locald/api/sandboxmanager/sandbox_manager_api.proto +++ b/internal/locald/api/sandboxmanager/sandbox_manager_api.proto @@ -29,6 +29,7 @@ message StatusResponse { apicommon.LocalNetStatus localnet = 2; apicommon.HostsStatus hosts = 3; apicommon.PortForwardStatus portforward = 4; + apicommon.WatcherStatus watcher = 6; repeated apicommon.SandboxStatus sandboxes = 5; } diff --git a/internal/locald/sandboxmanager/sandbox_server.go b/internal/locald/sandboxmanager/sandbox_server.go index aabbe13..edebefe 100644 --- a/internal/locald/sandboxmanager/sandbox_server.go +++ b/internal/locald/sandboxmanager/sandbox_server.go @@ -66,6 +66,7 @@ func (s *sbmServer) Status(ctx context.Context, req *sbapi.StatusRequest) (*sbap resp := &sbapi.StatusResponse{ CiConfig: grpcCIConfig, Portforward: s.portForwardStatus(), + Watcher: s.watcherStatus(), Sandboxes: s.sbStatuses(), } resp.Hosts, resp.Localnet = s.rootStatus() @@ -136,6 +137,12 @@ func (s *sbmServer) portForwardStatus() *commonapi.PortForwardStatus { return grpcPFStatus } +func (s *sbmServer) watcherStatus() *commonapi.WatcherStatus { + return &commonapi.WatcherStatus{ + Health: commonapi.ToGRPCServiceHealth(s.sbmWatcher.getStatus()), + } +} + func (s *sbmServer) sbStatuses() []*commonapi.SandboxStatus { sandboxes := s.sbmWatcher.getSandboxes() diff --git a/internal/locald/sandboxmanager/sandboxes_watcher.go b/internal/locald/sandboxmanager/sandboxes_watcher.go index 553401e..1541969 100644 --- a/internal/locald/sandboxmanager/sandboxes_watcher.go +++ b/internal/locald/sandboxmanager/sandboxes_watcher.go @@ -2,12 +2,14 @@ package sandboxmanager import ( "context" + "fmt" "log/slog" "sync" "time" tunapiv1 "github.com/signadot/libconnect/apiv1" tunapiclient "github.com/signadot/libconnect/common/apiclient" + "github.com/signadot/libconnect/common/svchealth" "github.com/signadot/libconnect/revtun" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -20,6 +22,7 @@ type sbmWatcher struct { // sandbox controllers sbMu sync.Mutex + status svchealth.ServiceHealth sbControllers map[string]*sbController revtunClient func() revtun.Client @@ -30,8 +33,12 @@ type sbmWatcher struct { func newSandboxManagerWatcher(log *slog.Logger, machineID string, revtunClient func() revtun.Client, shutdownCh chan struct{}) *sbmWatcher { srv := &sbmWatcher{ - log: log, - machineID: machineID, + log: log, + machineID: machineID, + status: svchealth.ServiceHealth{ + Healthy: false, + LastErrorReason: "Starting", + }, sbControllers: make(map[string]*sbController), revtunClient: revtunClient, shutdownCh: shutdownCh, @@ -57,35 +64,26 @@ func (sbw *sbmWatcher) watchSandboxes(ctx context.Context, tunAPIClient tunapicl default: } - sbw.log.Error("error getting local sandboxes watch stream, retrying", "error", err) + sbw.setError("error getting local sandboxes watch stream", err) <-time.After(3 * time.Second) continue } sbw.log.Debug("successfully got local sandboxes watch client") - err = sbw.readStream(sbwClient) - if err == nil { - // NotFound - break - } + sbw.readStream(sbwClient) } } -func (sbw *sbmWatcher) readStream(sbwClient tunapiv1.TunnelAPI_WatchLocalSandboxesClient) error { - var ( - ok bool - err error - event *tunapiv1.WatchLocalSandboxesResponse - grpcStatus *status.Status - ) +func (sbw *sbmWatcher) readStream(sbwClient tunapiv1.TunnelAPI_WatchLocalSandboxesClient) { for { - event, err = sbwClient.Recv() + event, err := sbwClient.Recv() if err == nil { + sbw.setSuccess() sbw.processStreamEvent(event) continue } - if grpcStatus, ok = status.FromError(err); !ok { - sbw.log.Error("sandboxes watch grpc stream error: no status", - "error", err) + grpcStatus, ok := status.FromError(err) + if !ok { + sbw.setError("sandboxes watch grpc stream error: no status", err) break } switch grpcStatus.Code() { @@ -94,15 +92,18 @@ func (sbw *sbmWatcher) readStream(sbwClient tunapiv1.TunnelAPI_WatchLocalSandbox sbw.processStreamEvent(event) continue case codes.Internal: - sbw.log.Error("sandboxes watch internal grpc error", - "error", err) + sbw.setError("sandboxes watch internal grpc error", err) <-time.After(3 * time.Second) + case codes.Unimplemented: + sbw.setError("incompatible operator version, current CLI requires operator >= 0.15.0", nil) + // in this case, check again in 1 minutes + <-time.After(1 * time.Minute) default: - sbw.log.Error("sandbox watch error", "error", err) + sbw.setError("sandbox watch error", err) + <-time.After(3 * time.Second) } break } - return err } func (sbw *sbmWatcher) processStreamEvent(event *tunapiv1.WatchLocalSandboxesResponse) { @@ -141,6 +142,13 @@ func (sbw *sbmWatcher) processStreamEvent(event *tunapiv1.WatchLocalSandboxesRes } } +func (sbw *sbmWatcher) getStatus() *svchealth.ServiceHealth { + sbw.sbMu.Lock() + defer sbw.sbMu.Unlock() + + return &sbw.status +} + func (sbw *sbmWatcher) getSandboxes() []*tunapiv1.Sandbox { sbw.sbMu.Lock() defer sbw.sbMu.Unlock() @@ -171,3 +179,30 @@ func (sbw *sbmWatcher) stop() { // wait until all sandbox controllers have stopped wg.Wait() } + +func (sbw *sbmWatcher) setSuccess() { + sbw.sbMu.Lock() + defer sbw.sbMu.Unlock() + + sbw.status.Healthy = true +} + +func (sbw *sbmWatcher) setError(errMsg string, err error) { + sbw.sbMu.Lock() + defer sbw.sbMu.Unlock() + + now := time.Now() + var reason string + if err != nil { + reason = fmt.Sprintf("%s, %s", errMsg, err.Error()) + sbw.log.Error(errMsg, "error", err) + } else { + reason = errMsg + sbw.log.Error(errMsg) + } + + sbw.status.Healthy = false + sbw.status.LastErrorReason = reason + sbw.status.LastErrorTime = &now + sbw.status.ErrorCount += 1 +} diff --git a/internal/locald/sandboxmanager/sdk.go b/internal/locald/sandboxmanager/sdk.go index 0cf7d51..96d7401 100644 --- a/internal/locald/sandboxmanager/sdk.go +++ b/internal/locald/sandboxmanager/sdk.go @@ -57,6 +57,7 @@ func CheckStatusConnectErrors(status *sbmapi.StatusResponse, ciConfig *config.Co errs = append(errs, err) } } + // check root manager (if running) if ciConfig.WithRootManager { // check localnet service @@ -70,6 +71,12 @@ func CheckStatusConnectErrors(status *sbmapi.StatusResponse, ciConfig *config.Co errs = append(errs, err) } } + + // check sandboxes watcher service + err := checkWatcherStatus(status.Watcher) + if err != nil { + errs = append(errs, err) + } return errs } @@ -117,3 +124,18 @@ func checkHostsStatus(hosts *commonapi.HostsStatus) error { } return fmt.Errorf(errorMsg) } + +func checkWatcherStatus(watcher *commonapi.WatcherStatus) error { + errorMsg := "failed to run sandboxes watcher" + if watcher != nil { + if watcher.Health != nil { + if watcher.Health.Healthy { + return nil + } + if watcher.Health.LastErrorReason != "" { + errorMsg += fmt.Sprintf(" (%q)", watcher.Health.LastErrorReason) + } + } + } + return fmt.Errorf(errorMsg) +} From 47283b347c464879d2b837b1a90bee6dd86e7ab0 Mon Sep 17 00:00:00 2001 From: daniel-de-vera <118383315+daniel-de-vera@users.noreply.github.com> Date: Fri, 17 Nov 2023 09:58:07 -0300 Subject: [PATCH 09/10] Add support for old operators (< 0.14.1) (#94) --- go.mod | 2 +- go.sum | 2 + internal/command/local/printers.go | 10 +- internal/command/sandbox/apply.go | 14 +- .../sandboxmanager/sandbox_manager_api.pb.go | 219 ++++++++++++++---- .../sandboxmanager/sandbox_manager_api.proto | 16 ++ .../sandbox_manager_api_grpc.pb.go | 47 +++- .../sandboxmanager/sandbox_controller.go | 7 +- .../locald/sandboxmanager/sandbox_monitor.go | 128 ++++++++++ .../locald/sandboxmanager/sandbox_server.go | 6 + .../sandboxmanager/sandboxes_watcher.go | 138 +++++++++-- internal/locald/sandboxmanager/sdk.go | 73 +++--- 12 files changed, 561 insertions(+), 101 deletions(-) create mode 100644 internal/locald/sandboxmanager/sandbox_monitor.go diff --git a/go.mod b/go.mod index 167faf6..faf3592 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 github.com/signadot/go-sdk v0.3.8-0.20231107200143-6c7fe4258298 - github.com/signadot/libconnect v0.1.1-0.20231109133751-e261a2f69044 + github.com/signadot/libconnect v0.1.1-0.20231115123918-678c2bc7a5cd github.com/spf13/cobra v1.6.0 github.com/spf13/viper v1.11.0 github.com/theckman/yacspin v0.13.12 diff --git a/go.sum b/go.sum index aa18ce3..7d017c4 100644 --- a/go.sum +++ b/go.sum @@ -366,6 +366,8 @@ github.com/signadot/go-sdk v0.3.8-0.20231107200143-6c7fe4258298 h1:zNEYJUQEbYMpE github.com/signadot/go-sdk v0.3.8-0.20231107200143-6c7fe4258298/go.mod h1:mLzoMuSE0GsFLONRjjYYHQBsU9twXML1BrExSvpMqeI= github.com/signadot/libconnect v0.1.1-0.20231109133751-e261a2f69044 h1:sl4y7UE8aar1gud3yCZUfMyUHeLkstNXJ2MRnoX7jBI= github.com/signadot/libconnect v0.1.1-0.20231109133751-e261a2f69044/go.mod h1:4OzWoyxyoh56h4jgCw/FBJVxyHB45qpwHDVWbsGfFTg= +github.com/signadot/libconnect v0.1.1-0.20231115123918-678c2bc7a5cd h1:yBTUTPK2viYd1tjvop5FTfXiebH91Ipt89y9WXY6jhQ= +github.com/signadot/libconnect v0.1.1-0.20231115123918-678c2bc7a5cd/go.mod h1:4OzWoyxyoh56h4jgCw/FBJVxyHB45qpwHDVWbsGfFTg= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= diff --git a/internal/command/local/printers.go b/internal/command/local/printers.go index 977ccfa..3c2da79 100644 --- a/internal/command/local/printers.go +++ b/internal/command/local/printers.go @@ -352,7 +352,15 @@ func (p *statusPrinter) printHostsStatus() { } func (p *statusPrinter) printSandboxesWatcherStatus() { - p.printLine(p.out, 1, "sandboxes watcher is running", "*") + msg := "sandboxes watcher is not running" + if p.status.Watcher != nil && p.status.Watcher.Health != nil { + if p.status.Watcher.Health.Healthy { + msg = "sandboxes watcher is running" + } else { + msg += fmt.Sprintf(" (%q)", p.status.Watcher.Health.LastErrorReason) + } + } + p.printLine(p.out, 1, msg, "*") } func (p *statusPrinter) printSandboxStatus() { diff --git a/internal/command/sandbox/apply.go b/internal/command/sandbox/apply.go index 5910011..8ea2286 100644 --- a/internal/command/sandbox/apply.go +++ b/internal/command/sandbox/apply.go @@ -49,9 +49,10 @@ func apply(cfg *config.SandboxApply, out, log io.Writer, args []string) error { return fmt.Errorf("sandbox spec must specify cluster") } + var status *sbmapi.StatusResponse if len(req.Spec.Local) > 0 { // Confirm sandboxmanager is running and connected to the right cluster - status, err := sbmgr.GetStatus() + status, err = sbmgr.GetStatus() if err != nil { return err } @@ -88,6 +89,17 @@ func apply(cfg *config.SandboxApply, out, log io.Writer, args []string) error { fmt.Fprintf(log, "Created sandbox %q (routing key: %s) in cluster %q.\n\n", req.Name, resp.RoutingKey, *req.Spec.Cluster) + if len(req.Spec.Local) > 0 && !sbmgr.IsWatcherRunning(status) { + // We don't really know here if it is a temporal problem or if we are + // dealing with an old operator that doesn't support it, in any case we + // will go ahead and register the sandbox in sandboxmanager. If this is + // a temporal issue, it will fix itself inside of sandboxmanager. + + if err = sbmgr.RegisterSandbox(resp.Name, resp.RoutingKey); err != nil { + return fmt.Errorf("couldn't register sandbox in sandboxmanager, %v", err) + } + } + if cfg.Wait { // Wait for the sandbox to be ready. // store latest resp for output below diff --git a/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go b/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go index 1062649..b0a2afd 100644 --- a/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go +++ b/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go @@ -225,6 +225,99 @@ func (*ShutdownResponse) Descriptor() ([]byte, []int) { return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZIP(), []int{3} } +type RegisterSandboxRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SandboxName string `protobuf:"bytes,1,opt,name=sandbox_name,json=sandboxName,proto3" json:"sandbox_name,omitempty"` + RoutingKey string `protobuf:"bytes,2,opt,name=routing_key,json=routingKey,proto3" json:"routing_key,omitempty"` +} + +func (x *RegisterSandboxRequest) Reset() { + *x = RegisterSandboxRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterSandboxRequest) ProtoMessage() {} + +func (x *RegisterSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterSandboxRequest.ProtoReflect.Descriptor instead. +func (*RegisterSandboxRequest) Descriptor() ([]byte, []int) { + return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZIP(), []int{4} +} + +func (x *RegisterSandboxRequest) GetSandboxName() string { + if x != nil { + return x.SandboxName + } + return "" +} + +func (x *RegisterSandboxRequest) GetRoutingKey() string { + if x != nil { + return x.RoutingKey + } + return "" +} + +type RegisterSandboxResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RegisterSandboxResponse) Reset() { + *x = RegisterSandboxResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterSandboxResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterSandboxResponse) ProtoMessage() {} + +func (x *RegisterSandboxResponse) ProtoReflect() protoreflect.Message { + mi := &file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterSandboxResponse.ProtoReflect.Descriptor instead. +func (*RegisterSandboxResponse) Descriptor() ([]byte, []int) { + return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZIP(), []int{5} +} + var File_internal_locald_api_sandboxmanager_sandbox_manager_api_proto protoreflect.FileDescriptor var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDesc = []byte{ @@ -262,22 +355,36 @@ var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDesc = 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x32, 0xaf, 0x01, 0x0a, 0x11, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x72, 0x41, 0x50, 0x49, 0x12, 0x49, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x1d, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, - 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1e, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x4f, 0x0a, 0x08, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1f, 0x2e, - 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, - 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, + 0x22, 0x5c, 0x0a, 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x61, + 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, + 0x0b, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x22, 0x19, + 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x95, 0x02, 0x0a, 0x11, 0x53, 0x61, + 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x41, 0x50, 0x49, 0x12, + 0x49, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x2e, 0x73, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, + 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x08, 0x53, 0x68, + 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1f, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x64, 0x0a, 0x0f, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x12, 0x26, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, - 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x42, 0x3c, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x42, 0x3c, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -292,35 +399,39 @@ func file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescGZ return file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDescData } -var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_goTypes = []interface{}{ - (*StatusRequest)(nil), // 0: sandboxmanager.StatusRequest - (*StatusResponse)(nil), // 1: sandboxmanager.StatusResponse - (*ShutdownRequest)(nil), // 2: sandboxmanager.ShutdownRequest - (*ShutdownResponse)(nil), // 3: sandboxmanager.ShutdownResponse - (*_struct.Struct)(nil), // 4: google.protobuf.Struct - (*api.LocalNetStatus)(nil), // 5: apicommon.LocalNetStatus - (*api.HostsStatus)(nil), // 6: apicommon.HostsStatus - (*api.PortForwardStatus)(nil), // 7: apicommon.PortForwardStatus - (*api.WatcherStatus)(nil), // 8: apicommon.WatcherStatus - (*api.SandboxStatus)(nil), // 9: apicommon.SandboxStatus + (*StatusRequest)(nil), // 0: sandboxmanager.StatusRequest + (*StatusResponse)(nil), // 1: sandboxmanager.StatusResponse + (*ShutdownRequest)(nil), // 2: sandboxmanager.ShutdownRequest + (*ShutdownResponse)(nil), // 3: sandboxmanager.ShutdownResponse + (*RegisterSandboxRequest)(nil), // 4: sandboxmanager.RegisterSandboxRequest + (*RegisterSandboxResponse)(nil), // 5: sandboxmanager.RegisterSandboxResponse + (*_struct.Struct)(nil), // 6: google.protobuf.Struct + (*api.LocalNetStatus)(nil), // 7: apicommon.LocalNetStatus + (*api.HostsStatus)(nil), // 8: apicommon.HostsStatus + (*api.PortForwardStatus)(nil), // 9: apicommon.PortForwardStatus + (*api.WatcherStatus)(nil), // 10: apicommon.WatcherStatus + (*api.SandboxStatus)(nil), // 11: apicommon.SandboxStatus } var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_depIdxs = []int32{ - 4, // 0: sandboxmanager.StatusResponse.ci_config:type_name -> google.protobuf.Struct - 5, // 1: sandboxmanager.StatusResponse.localnet:type_name -> apicommon.LocalNetStatus - 6, // 2: sandboxmanager.StatusResponse.hosts:type_name -> apicommon.HostsStatus - 7, // 3: sandboxmanager.StatusResponse.portforward:type_name -> apicommon.PortForwardStatus - 8, // 4: sandboxmanager.StatusResponse.watcher:type_name -> apicommon.WatcherStatus - 9, // 5: sandboxmanager.StatusResponse.sandboxes:type_name -> apicommon.SandboxStatus - 0, // 6: sandboxmanager.SandboxManagerAPI.Status:input_type -> sandboxmanager.StatusRequest - 2, // 7: sandboxmanager.SandboxManagerAPI.Shutdown:input_type -> sandboxmanager.ShutdownRequest - 1, // 8: sandboxmanager.SandboxManagerAPI.Status:output_type -> sandboxmanager.StatusResponse - 3, // 9: sandboxmanager.SandboxManagerAPI.Shutdown:output_type -> sandboxmanager.ShutdownResponse - 8, // [8:10] is the sub-list for method output_type - 6, // [6:8] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name + 6, // 0: sandboxmanager.StatusResponse.ci_config:type_name -> google.protobuf.Struct + 7, // 1: sandboxmanager.StatusResponse.localnet:type_name -> apicommon.LocalNetStatus + 8, // 2: sandboxmanager.StatusResponse.hosts:type_name -> apicommon.HostsStatus + 9, // 3: sandboxmanager.StatusResponse.portforward:type_name -> apicommon.PortForwardStatus + 10, // 4: sandboxmanager.StatusResponse.watcher:type_name -> apicommon.WatcherStatus + 11, // 5: sandboxmanager.StatusResponse.sandboxes:type_name -> apicommon.SandboxStatus + 0, // 6: sandboxmanager.SandboxManagerAPI.Status:input_type -> sandboxmanager.StatusRequest + 2, // 7: sandboxmanager.SandboxManagerAPI.Shutdown:input_type -> sandboxmanager.ShutdownRequest + 4, // 8: sandboxmanager.SandboxManagerAPI.RegisterSandbox:input_type -> sandboxmanager.RegisterSandboxRequest + 1, // 9: sandboxmanager.SandboxManagerAPI.Status:output_type -> sandboxmanager.StatusResponse + 3, // 10: sandboxmanager.SandboxManagerAPI.Shutdown:output_type -> sandboxmanager.ShutdownResponse + 5, // 11: sandboxmanager.SandboxManagerAPI.RegisterSandbox:output_type -> sandboxmanager.RegisterSandboxResponse + 9, // [9:12] is the sub-list for method output_type + 6, // [6:9] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_init() } @@ -377,6 +488,30 @@ func file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_init() { return nil } } + file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterSandboxRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterSandboxResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -384,7 +519,7 @@ func file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDesc, NumEnums: 0, - NumMessages: 4, + NumMessages: 6, NumExtensions: 0, NumServices: 1, }, diff --git a/internal/locald/api/sandboxmanager/sandbox_manager_api.proto b/internal/locald/api/sandboxmanager/sandbox_manager_api.proto index 96ce7b5..fbc3582 100644 --- a/internal/locald/api/sandboxmanager/sandbox_manager_api.proto +++ b/internal/locald/api/sandboxmanager/sandbox_manager_api.proto @@ -14,6 +14,11 @@ service SandboxManagerAPI { // This method requests the root controller to shutdown rpc Shutdown(ShutdownRequest) returns (ShutdownResponse) {} + + // This method is used to register sandboxes in the local controller. It is + // mainly used in the context of old operators (the ones that don't support + // WatchLocalSandboxes in tunnel-api) + rpc RegisterSandbox(RegisterSandboxRequest) returns (RegisterSandboxResponse) {} } // Status @@ -41,3 +46,14 @@ message ShutdownRequest { message ShutdownResponse { } + +// RegisterSandbox +// ---------------------------------------------------------------------------- + +message RegisterSandboxRequest { + string sandbox_name = 1; + string routing_key = 2; +} + +message RegisterSandboxResponse { +} diff --git a/internal/locald/api/sandboxmanager/sandbox_manager_api_grpc.pb.go b/internal/locald/api/sandboxmanager/sandbox_manager_api_grpc.pb.go index 2345794..fbc54ba 100644 --- a/internal/locald/api/sandboxmanager/sandbox_manager_api_grpc.pb.go +++ b/internal/locald/api/sandboxmanager/sandbox_manager_api_grpc.pb.go @@ -19,8 +19,9 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - SandboxManagerAPI_Status_FullMethodName = "/sandboxmanager.SandboxManagerAPI/Status" - SandboxManagerAPI_Shutdown_FullMethodName = "/sandboxmanager.SandboxManagerAPI/Shutdown" + SandboxManagerAPI_Status_FullMethodName = "/sandboxmanager.SandboxManagerAPI/Status" + SandboxManagerAPI_Shutdown_FullMethodName = "/sandboxmanager.SandboxManagerAPI/Shutdown" + SandboxManagerAPI_RegisterSandbox_FullMethodName = "/sandboxmanager.SandboxManagerAPI/RegisterSandbox" ) // SandboxManagerAPIClient is the client API for SandboxManagerAPI service. @@ -31,6 +32,10 @@ type SandboxManagerAPIClient interface { Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) // This method requests the root controller to shutdown Shutdown(ctx context.Context, in *ShutdownRequest, opts ...grpc.CallOption) (*ShutdownResponse, error) + // This method is used to register sandboxes in the local controller. It is + // mainly used in the context of old operators (the ones that don't support + // WatchLocalSandboxes in tunnel-api) + RegisterSandbox(ctx context.Context, in *RegisterSandboxRequest, opts ...grpc.CallOption) (*RegisterSandboxResponse, error) } type sandboxManagerAPIClient struct { @@ -59,6 +64,15 @@ func (c *sandboxManagerAPIClient) Shutdown(ctx context.Context, in *ShutdownRequ return out, nil } +func (c *sandboxManagerAPIClient) RegisterSandbox(ctx context.Context, in *RegisterSandboxRequest, opts ...grpc.CallOption) (*RegisterSandboxResponse, error) { + out := new(RegisterSandboxResponse) + err := c.cc.Invoke(ctx, SandboxManagerAPI_RegisterSandbox_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // SandboxManagerAPIServer is the server API for SandboxManagerAPI service. // All implementations must embed UnimplementedSandboxManagerAPIServer // for forward compatibility @@ -67,6 +81,10 @@ type SandboxManagerAPIServer interface { Status(context.Context, *StatusRequest) (*StatusResponse, error) // This method requests the root controller to shutdown Shutdown(context.Context, *ShutdownRequest) (*ShutdownResponse, error) + // This method is used to register sandboxes in the local controller. It is + // mainly used in the context of old operators (the ones that don't support + // WatchLocalSandboxes in tunnel-api) + RegisterSandbox(context.Context, *RegisterSandboxRequest) (*RegisterSandboxResponse, error) mustEmbedUnimplementedSandboxManagerAPIServer() } @@ -80,6 +98,9 @@ func (UnimplementedSandboxManagerAPIServer) Status(context.Context, *StatusReque func (UnimplementedSandboxManagerAPIServer) Shutdown(context.Context, *ShutdownRequest) (*ShutdownResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Shutdown not implemented") } +func (UnimplementedSandboxManagerAPIServer) RegisterSandbox(context.Context, *RegisterSandboxRequest) (*RegisterSandboxResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RegisterSandbox not implemented") +} func (UnimplementedSandboxManagerAPIServer) mustEmbedUnimplementedSandboxManagerAPIServer() {} // UnsafeSandboxManagerAPIServer may be embedded to opt out of forward compatibility for this service. @@ -129,6 +150,24 @@ func _SandboxManagerAPI_Shutdown_Handler(srv interface{}, ctx context.Context, d return interceptor(ctx, in, info, handler) } +func _SandboxManagerAPI_RegisterSandbox_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RegisterSandboxRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SandboxManagerAPIServer).RegisterSandbox(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SandboxManagerAPI_RegisterSandbox_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SandboxManagerAPIServer).RegisterSandbox(ctx, req.(*RegisterSandboxRequest)) + } + return interceptor(ctx, in, info, handler) +} + // SandboxManagerAPI_ServiceDesc is the grpc.ServiceDesc for SandboxManagerAPI service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -144,6 +183,10 @@ var SandboxManagerAPI_ServiceDesc = grpc.ServiceDesc{ MethodName: "Shutdown", Handler: _SandboxManagerAPI_Shutdown_Handler, }, + { + MethodName: "RegisterSandbox", + Handler: _SandboxManagerAPI_RegisterSandbox_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "internal/locald/api/sandboxmanager/sandbox_manager_api.proto", diff --git a/internal/locald/sandboxmanager/sandbox_controller.go b/internal/locald/sandboxmanager/sandbox_controller.go index e6f5b19..9b6844a 100644 --- a/internal/locald/sandboxmanager/sandbox_controller.go +++ b/internal/locald/sandboxmanager/sandbox_controller.go @@ -43,12 +43,13 @@ func newSBController(log *slog.Logger, sandbox *tunapiv1.Sandbox, } // run the controller go ctrl.run() - // trigger a reconcile - ctrl.triggerReconcile() return ctrl } func (ctrl *sbController) run() { + // trigger a reconcile + ctrl.triggerReconcile() + // run the reconcile loop ticker := time.NewTicker(reconcilePeriod) defer ticker.Stop() @@ -204,8 +205,8 @@ func (ctrl *sbController) closeRevTunnel(xwName string) { select { case <-revtun.rtToClose: default: - ctrl.log.Debug("sandbox controller closing revtun", "local", xwName) close(revtun.rtToClose) + ctrl.log.Debug("sandbox controller closing revtun", "local", xwName) } } diff --git a/internal/locald/sandboxmanager/sandbox_monitor.go b/internal/locald/sandboxmanager/sandbox_monitor.go new file mode 100644 index 0000000..4950980 --- /dev/null +++ b/internal/locald/sandboxmanager/sandbox_monitor.go @@ -0,0 +1,128 @@ +package sandboxmanager + +import ( + "context" + "time" + + "log/slog" + + tunapiv1 "github.com/signadot/libconnect/apiv1" + tunapiclient "github.com/signadot/libconnect/common/apiclient" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type sbMonitor struct { + log *slog.Logger + routingKey string + tunAPIClient tunapiclient.Client + eventFn func(string, *tunapiv1.WatchSandboxResponse) + doneCh chan struct{} +} + +func newSBMonitor(log *slog.Logger, sandboxName, routingKey string, + tunAPIClient tunapiclient.Client, eventFn func(string, *tunapiv1.WatchSandboxResponse)) *sbMonitor { + res := &sbMonitor{ + log: log.With("sandbox", sandboxName), + routingKey: routingKey, + tunAPIClient: tunAPIClient, + eventFn: eventFn, + doneCh: make(chan struct{}), + } + go res.monitor() + return res +} + +func (sbm *sbMonitor) stop() { + select { + case <-sbm.doneCh: + default: + close(sbm.doneCh) + } +} + +func (sbm *sbMonitor) monitor() { + // setup context for grpc stream + ctx, cancel := context.WithCancel(context.Background()) + + // watch the given sandbox + go sbm.watchSandbox(ctx) + + // wait until done + <-sbm.doneCh + // we are done, cancel the context + cancel() +} + +func (sbm *sbMonitor) watchSandbox(ctx context.Context) { + // watch loop + for { + sbwClient, err := sbm.tunAPIClient.WatchSandbox(ctx, &tunapiv1.WatchSandboxRequest{ + RoutingKey: sbm.routingKey, + }) + if err != nil { + // don't retry if the context has been cancelled + select { + case <-ctx.Done(): + return + default: + } + + sbm.log.Error("error getting sb watch stream, retrying", "error", err) + <-time.After(3 * time.Second) + continue + } + + sbm.log.Debug("successfully got sandbox watch client") + err = sbm.readStream(ctx, sbwClient) + if err == nil { + // NotFound + break + } + } + + // There is no sandbox, stop the monitor + sbm.stop() +} + +func (sbm *sbMonitor) readStream(ctx context.Context, + sbwClient tunapiv1.TunnelAPI_WatchSandboxClient) error { + var err error + for { + sbStatus, err := sbwClient.Recv() + if err == nil { + sbm.eventFn(sbm.routingKey, sbStatus) + continue + } + // just return if the context has been cancelled + select { + case <-ctx.Done(): + return nil + default: + } + // extract the grpc status + grpcStatus, ok := status.FromError(err) + if !ok { + sbm.log.Error("sandbox monitor grpc stream error: no status", + "error", err) + break + } + switch grpcStatus.Code() { + case codes.OK: + sbm.log.Debug("sandbox watch stream error code is ok") + sbm.eventFn(sbm.routingKey, sbStatus) + continue + case codes.Internal: + sbm.log.Error("sandbox watch: internal grpc error", "error", err) + <-time.After(3 * time.Second) + case codes.NotFound: + sbm.log.Info("sandbox watch: sandbox not found") + sbm.eventFn(sbm.routingKey, nil) + err = nil + default: + sbm.log.Error("sandbox watch error", "error", err) + } + break + } + return err +} diff --git a/internal/locald/sandboxmanager/sandbox_server.go b/internal/locald/sandboxmanager/sandbox_server.go index edebefe..e5018e2 100644 --- a/internal/locald/sandboxmanager/sandbox_server.go +++ b/internal/locald/sandboxmanager/sandbox_server.go @@ -82,6 +82,12 @@ func (s *sbmServer) Shutdown(ctx context.Context, req *sbapi.ShutdownRequest) (* return &sbapi.ShutdownResponse{}, nil } +func (s *sbmServer) RegisterSandbox(ctx context.Context, req *sbapi.RegisterSandboxRequest) ( + *sbapi.RegisterSandboxResponse, error) { + s.sbmWatcher.registerSandbox(req.SandboxName, req.RoutingKey) + return &sbapi.RegisterSandboxResponse{}, nil +} + func (s *sbmServer) rootStatus() (*commonapi.HostsStatus, *commonapi.LocalNetStatus) { if !s.ciConfig.WithRootManager { // We are running without a root manager diff --git a/internal/locald/sandboxmanager/sandboxes_watcher.go b/internal/locald/sandboxmanager/sandboxes_watcher.go index 1541969..afa0107 100644 --- a/internal/locald/sandboxmanager/sandboxes_watcher.go +++ b/internal/locald/sandboxmanager/sandboxes_watcher.go @@ -24,7 +24,9 @@ type sbmWatcher struct { sbMu sync.Mutex status svchealth.ServiceHealth sbControllers map[string]*sbController + sbMonitors map[string]*sbMonitor revtunClient func() revtun.Client + tunAPIClient tunapiclient.Client // shutdown shutdownCh chan struct{} @@ -39,7 +41,8 @@ func newSandboxManagerWatcher(log *slog.Logger, machineID string, revtunClient f Healthy: false, LastErrorReason: "Starting", }, - sbControllers: make(map[string]*sbController), + sbControllers: map[string]*sbController{}, + sbMonitors: map[string]*sbMonitor{}, revtunClient: revtunClient, shutdownCh: shutdownCh, } @@ -47,6 +50,7 @@ func newSandboxManagerWatcher(log *slog.Logger, machineID string, revtunClient f } func (sbw *sbmWatcher) run(ctx context.Context, tunAPIClient tunapiclient.Client) { + sbw.tunAPIClient = tunAPIClient go sbw.watchSandboxes(ctx, tunAPIClient) } @@ -69,11 +73,12 @@ func (sbw *sbmWatcher) watchSandboxes(ctx context.Context, tunAPIClient tunapicl continue } sbw.log.Debug("successfully got local sandboxes watch client") - sbw.readStream(sbwClient) + sbw.readStream(ctx, sbwClient) } } -func (sbw *sbmWatcher) readStream(sbwClient tunapiv1.TunnelAPI_WatchLocalSandboxesClient) { +func (sbw *sbmWatcher) readStream(ctx context.Context, + sbwClient tunapiv1.TunnelAPI_WatchLocalSandboxesClient) { for { event, err := sbwClient.Recv() if err == nil { @@ -81,6 +86,13 @@ func (sbw *sbmWatcher) readStream(sbwClient tunapiv1.TunnelAPI_WatchLocalSandbox sbw.processStreamEvent(event) continue } + // just return if the context has been cancelled + select { + case <-ctx.Done(): + return + default: + } + // extract the grpc status grpcStatus, ok := status.FromError(err) if !ok { sbw.setError("sandboxes watch grpc stream error: no status", err) @@ -95,7 +107,7 @@ func (sbw *sbmWatcher) readStream(sbwClient tunapiv1.TunnelAPI_WatchLocalSandbox sbw.setError("sandboxes watch internal grpc error", err) <-time.After(3 * time.Second) case codes.Unimplemented: - sbw.setError("incompatible operator version, current CLI requires operator >= 0.15.0", nil) + sbw.setError("this feature requires operator >= 0.14.1", nil) // in this case, check again in 1 minutes <-time.After(1 * time.Minute) default: @@ -114,22 +126,8 @@ func (sbw *sbmWatcher) processStreamEvent(event *tunapiv1.WatchLocalSandboxesRes for i := range event.Sandboxes { sds := event.Sandboxes[i] desiredSandboxes[sds.SandboxName] = true - - if ctrl := sbw.sbControllers[sds.SandboxName]; ctrl != nil { - // update the sandbox in the controller - ctrl.updateSandbox(sds) - } else { - // create a new sandbox controller - sbw.log.Debug("creating sandbox", "sandbox", sds) - sbw.sbControllers[sds.SandboxName] = newSBController( - sbw.log, sds, sbw.revtunClient(), - func() { - sbw.sbMu.Lock() - defer sbw.sbMu.Unlock() - delete(sbw.sbControllers, sds.SandboxName) - }, - ) - } + // update the sds object + sbw.processSDS(sds) } // remove unwanted sandboxes @@ -142,6 +140,24 @@ func (sbw *sbmWatcher) processStreamEvent(event *tunapiv1.WatchLocalSandboxesRes } } +func (sbw *sbmWatcher) processSDS(sds *tunapiv1.Sandbox) { + if ctrl := sbw.sbControllers[sds.SandboxName]; ctrl != nil { + // update the sandbox in the controller + ctrl.updateSandbox(sds) + } else { + // create a new sandbox controller + sbw.log.Debug("creating sandbox", "sandbox", sds) + sbw.sbControllers[sds.SandboxName] = newSBController( + sbw.log, sds, sbw.revtunClient(), + func() { + sbw.sbMu.Lock() + defer sbw.sbMu.Unlock() + delete(sbw.sbControllers, sds.SandboxName) + }, + ) + } +} + func (sbw *sbmWatcher) getStatus() *svchealth.ServiceHealth { sbw.sbMu.Lock() defer sbw.sbMu.Unlock() @@ -163,16 +179,25 @@ func (sbw *sbmWatcher) getSandboxes() []*tunapiv1.Sandbox { func (sbw *sbmWatcher) stop() { var wg sync.WaitGroup - // stop all sandbox controllers sbw.sbMu.Lock() - for _, sbMon := range sbw.sbControllers { + // stop all sandbox monitor (if any) + sbw.stopMonitors() + + // stop all sandbox controllers: + // + // - the grpcserver has called graceful stop, so no new sandboxes will be + // processed during a call to this function + // - the delFn is called at the end of the sb controller run, so the wg will + // wait for all monitors to stop running. + // + for _, ctrl := range sbw.sbControllers { wg.Add(1) // overwrite the delete function - sbMon.delFn = func() { + ctrl.delFn = func() { defer wg.Done() } // stop the sandbox controller - sbMon.stop() + ctrl.stop() } sbw.sbMu.Unlock() @@ -180,11 +205,24 @@ func (sbw *sbmWatcher) stop() { wg.Wait() } +// This function does not perform any locking, thus so the lock should acquired +// by the caller. +func (sbw *sbmWatcher) stopMonitors() { + for sandboxName, sbm := range sbw.sbMonitors { + sbm.stop() + delete(sbw.sbMonitors, sandboxName) + } +} + func (sbw *sbmWatcher) setSuccess() { sbw.sbMu.Lock() defer sbw.sbMu.Unlock() + // update the status sbw.status.Healthy = true + + // stop all sandbox monitor (if any) + sbw.stopMonitors() } func (sbw *sbmWatcher) setError(errMsg string, err error) { @@ -206,3 +244,55 @@ func (sbw *sbmWatcher) setError(errMsg string, err error) { sbw.status.LastErrorTime = &now sbw.status.ErrorCount += 1 } + +func (sbw *sbmWatcher) registerSandbox(sandboxName, routingKey string) { + sbw.sbMu.Lock() + defer sbw.sbMu.Unlock() + + if sbw.status.Healthy { + // the sandbox watcher is running, no need to register this sandbox (it + // should happen via WatchLocalSandboxes stream) + return + } + + // create a sandbox monitor (that will watch events specific to that sandbox) + if sbm := sbw.sbMonitors[sandboxName]; sbm != nil { + sbm.stop() + } + sbw.sbMonitors[sandboxName] = newSBMonitor(sbw.log, sandboxName, routingKey, + sbw.tunAPIClient, sbw.monitorUpdatedSandbox) +} + +func (sbw *sbmWatcher) monitorUpdatedSandbox(routingKey string, event *tunapiv1.WatchSandboxResponse) { + sbw.sbMu.Lock() + defer sbw.sbMu.Unlock() + + if _, ok := sbw.sbMonitors[event.SandboxName]; !ok { + // this could only happen while the sandbox monitor is being deleted, + // just ignore this event + return + } + + if event == nil { + // the sandbox has been deleted, the monitor will automatically stop, + // lets stop its controller here + ctrl := sbw.sbControllers[event.SandboxName] + if ctrl != nil { + sbw.log.Debug("removing sandbox", "sandboxName", event.SandboxName) + ctrl.stop() + } + + // remove the reference to the monitor + delete(sbw.sbMonitors, event.SandboxName) + return + } + + // a sandbox has been added/updated + sds := &tunapiv1.Sandbox{ + SandboxName: event.SandboxName, + RoutingKey: routingKey, + ExternalWorkloads: event.ExternalWorkloads, + Resources: event.Resources, + } + sbw.processSDS(sds) +} diff --git a/internal/locald/sandboxmanager/sdk.go b/internal/locald/sandboxmanager/sdk.go index 96d7401..cc18cd2 100644 --- a/internal/locald/sandboxmanager/sdk.go +++ b/internal/locald/sandboxmanager/sdk.go @@ -15,10 +15,10 @@ import ( ) func GetStatus() (*sbmapi.StatusResponse, error) { - // Get a sandbox manager API client - grpcConn, err := grpc.Dial("127.0.0.1:6666", grpc.WithTransportCredentials(insecure.NewCredentials())) + // get a sandbox manager API client + grpcConn, err := connectSandboxManager() if err != nil { - return nil, fmt.Errorf("couldn't connect sandboxmanager: %w", err) + return nil, err } defer grpcConn.Close() @@ -26,14 +26,7 @@ func GetStatus() (*sbmapi.StatusResponse, error) { sbManagerClient := sbmapi.NewSandboxManagerAPIClient(grpcConn) sbStatus, err := sbManagerClient.Status(context.Background(), &sbmapi.StatusRequest{}) if err != nil { - grpcStatus, ok := status.FromError(err) - if ok { - switch grpcStatus.Code() { - case codes.Unavailable: - return nil, fmt.Errorf("sandboxmanager is not running, start it with \"signadot local connect\"") - } - } - return nil, fmt.Errorf("unable to get status from sandboxmanager: %w", err) + return nil, processGRPCError("unable to get status from sandboxmanager", err) } return sbStatus, nil } @@ -72,11 +65,6 @@ func CheckStatusConnectErrors(status *sbmapi.StatusResponse, ciConfig *config.Co } } - // check sandboxes watcher service - err := checkWatcherStatus(status.Watcher) - if err != nil { - errs = append(errs, err) - } return errs } @@ -125,17 +113,48 @@ func checkHostsStatus(hosts *commonapi.HostsStatus) error { return fmt.Errorf(errorMsg) } -func checkWatcherStatus(watcher *commonapi.WatcherStatus) error { - errorMsg := "failed to run sandboxes watcher" - if watcher != nil { - if watcher.Health != nil { - if watcher.Health.Healthy { - return nil - } - if watcher.Health.LastErrorReason != "" { - errorMsg += fmt.Sprintf(" (%q)", watcher.Health.LastErrorReason) - } +func IsWatcherRunning(status *sbmapi.StatusResponse) bool { + if status == nil || status.Watcher == nil || status.Watcher.Health == nil { + return false + } + return status.Watcher.Health.Healthy +} + +func RegisterSandbox(sandboxName, routingKey string) error { + // get a sandbox manager API client + grpcConn, err := connectSandboxManager() + if err != nil { + return err + } + defer grpcConn.Close() + + // register the sandbox + sbManagerClient := sbmapi.NewSandboxManagerAPIClient(grpcConn) + _, err = sbManagerClient.RegisterSandbox(context.Background(), &sbmapi.RegisterSandboxRequest{ + SandboxName: sandboxName, + RoutingKey: routingKey, + }) + if err != nil { + return processGRPCError("unable to register sandbox in sandboxmanager", err) + } + return nil +} + +func connectSandboxManager() (*grpc.ClientConn, error) { + grpcConn, err := grpc.Dial("127.0.0.1:6666", grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return nil, fmt.Errorf("couldn't connect sandboxmanager: %w", err) + } + return grpcConn, nil +} + +func processGRPCError(action string, err error) error { + grpcStatus, ok := status.FromError(err) + if ok { + switch grpcStatus.Code() { + case codes.Unavailable: + return fmt.Errorf("sandboxmanager is not running, start it with \"signadot local connect\"") } } - return fmt.Errorf(errorMsg) + return fmt.Errorf("%s: %w", action, err) } From 54bc79c61d7bb61273153c9324fff9afa30e981c Mon Sep 17 00:00:00 2001 From: daniel-de-vera <118383315+daniel-de-vera@users.noreply.github.com> Date: Mon, 20 Nov 2023 09:19:21 -0300 Subject: [PATCH 10/10] Include operator info as par of the status (#95) * Add support for old operators (< 0.14.1) * Addition of operatorInfoUpdater * Minor fix * Bug fix * Point libconnect to main * Point github.com/signadot/go-sdk to main version * PR feedback --- go.mod | 4 +- go.sum | 10 +- internal/command/local/connect.go | 24 ++- internal/command/local/printers.go | 49 ++++- internal/command/sandbox/apply.go | 9 +- internal/locald/api/common.pb.go | 129 +++++++++++--- internal/locald/api/common.proto | 6 + .../sandboxmanager/sandbox_manager_api.pb.go | 168 ++++++++++-------- .../sandboxmanager/sandbox_manager_api.proto | 1 + .../sandboxmanager/operator_info_updater.go | 82 +++++++++ .../locald/sandboxmanager/sandbox_manager.go | 19 +- .../locald/sandboxmanager/sandbox_server.go | 13 +- .../sandboxmanager/sandboxes_watcher.go | 21 ++- internal/locald/sandboxmanager/sdk.go | 6 +- 14 files changed, 404 insertions(+), 137 deletions(-) create mode 100644 internal/locald/sandboxmanager/operator_info_updater.go diff --git a/go.mod b/go.mod index faf3592..32e65a9 100644 --- a/go.mod +++ b/go.mod @@ -11,8 +11,8 @@ require ( github.com/golang/protobuf v1.5.3 github.com/hashicorp/go-multierror v1.1.1 github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 - github.com/signadot/go-sdk v0.3.8-0.20231107200143-6c7fe4258298 - github.com/signadot/libconnect v0.1.1-0.20231115123918-678c2bc7a5cd + github.com/signadot/go-sdk v0.3.8-0.20231120112931-5aa0810b12b7 + github.com/signadot/libconnect v0.1.1-0.20231117125146-85eb3e9106d5 github.com/spf13/cobra v1.6.0 github.com/spf13/viper v1.11.0 github.com/theckman/yacspin v0.13.12 diff --git a/go.sum b/go.sum index 7d017c4..e30b172 100644 --- a/go.sum +++ b/go.sum @@ -362,12 +362,10 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/signadot/go-sdk v0.3.8-0.20231107200143-6c7fe4258298 h1:zNEYJUQEbYMpEkFekq8wDjC6atbKRxPHIrC5UT6pE/A= -github.com/signadot/go-sdk v0.3.8-0.20231107200143-6c7fe4258298/go.mod h1:mLzoMuSE0GsFLONRjjYYHQBsU9twXML1BrExSvpMqeI= -github.com/signadot/libconnect v0.1.1-0.20231109133751-e261a2f69044 h1:sl4y7UE8aar1gud3yCZUfMyUHeLkstNXJ2MRnoX7jBI= -github.com/signadot/libconnect v0.1.1-0.20231109133751-e261a2f69044/go.mod h1:4OzWoyxyoh56h4jgCw/FBJVxyHB45qpwHDVWbsGfFTg= -github.com/signadot/libconnect v0.1.1-0.20231115123918-678c2bc7a5cd h1:yBTUTPK2viYd1tjvop5FTfXiebH91Ipt89y9WXY6jhQ= -github.com/signadot/libconnect v0.1.1-0.20231115123918-678c2bc7a5cd/go.mod h1:4OzWoyxyoh56h4jgCw/FBJVxyHB45qpwHDVWbsGfFTg= +github.com/signadot/go-sdk v0.3.8-0.20231120112931-5aa0810b12b7 h1:PgIayNxGde2TvVYCFOsDVZ65WsrBdlh6MN3tzHGeXtM= +github.com/signadot/go-sdk v0.3.8-0.20231120112931-5aa0810b12b7/go.mod h1:mLzoMuSE0GsFLONRjjYYHQBsU9twXML1BrExSvpMqeI= +github.com/signadot/libconnect v0.1.1-0.20231117125146-85eb3e9106d5 h1:ndZrB3jPa0xIL7deNcHWXE7HKvRBi0njVLj7nLnl0GQ= +github.com/signadot/libconnect v0.1.1-0.20231117125146-85eb3e9106d5/go.mod h1:4OzWoyxyoh56h4jgCw/FBJVxyHB45qpwHDVWbsGfFTg= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= diff --git a/internal/command/local/connect.go b/internal/command/local/connect.go index 939f4dd..abdfa7b 100644 --- a/internal/command/local/connect.go +++ b/internal/command/local/connect.go @@ -203,10 +203,30 @@ func waitConnect(localConfig *config.LocalConnect, out io.Writer) error { goto tick } + // wait until the local connection has been established connectErrs = sbmgr.CheckStatusConnectErrors(status, ciConfig) - if len(connectErrs) == 0 { - break + if len(connectErrs) != 0 { + goto tick + } + // wait until all local sandboxes are ready (all tunnels have connected) + if isRunning, lastError := sbmgr.IsWatcherRunning(status); !isRunning { + if lastError == sbmgr.SandboxesWatcherUnimplemented { + // this is an old operator, we are done + break + } + goto tick + } + for i := range status.Sandboxes { + sds := status.Sandboxes[i] + for j := range sds.LocalWorkloads { + lw := sds.LocalWorkloads[j] + if lw.TunnelHealth == nil || !lw.TunnelHealth.Healthy { + connectErrs = []error{fmt.Errorf("sandbox %s is not ready", sds.Name)} + goto tick + } + } } + break tick: select { case <-ticker.C: diff --git a/internal/command/local/printers.go b/internal/command/local/printers.go index 3c2da79..b4d59a7 100644 --- a/internal/command/local/printers.go +++ b/internal/command/local/printers.go @@ -30,6 +30,7 @@ func printRawStatus(cfg *config.LocalStatus, out io.Writer, printer func(out io. type rawStatus struct { RuntimeConfig any `json:"runtimeConfig,omitempty"` + OperatorInfo any `json:"operatorInfo,omitempty"` Localnet any `json:"localnet,omitempty"` Hosts any `json:"hosts,omitempty"` Portforward any `json:"portforward,omitempty"` @@ -39,6 +40,7 @@ func printRawStatus(cfg *config.LocalStatus, out io.Writer, printer func(out io. rawSt := rawStatus{ RuntimeConfig: getRawRuntimeConfig(cfg, ciConfig), + OperatorInfo: getRawOperatorInfo(cfg, status.OperatorInfo), Localnet: getRawLocalnet(cfg, ciConfig, status.Localnet, statusMap), Hosts: getRawHosts(cfg, ciConfig, status.Hosts, statusMap), Portforward: getRawPortforward(cfg, ciConfig, status.Portforward, statusMap), @@ -106,6 +108,39 @@ func getRawRuntimeConfig(cfg *config.LocalStatus, ciConfig *config.ConnectInvoca return runtimeConfig } +func getRawOperatorInfo(cfg *config.LocalStatus, info *commonapi.OperatorInfo) any { + var operatorInfo any + if info == nil { + return operatorInfo + } + + if cfg.Details { + // Details view + type PrintableOperatorInfo struct { + Version string `json:"version"` + GitCommit string `json:"gitCommit"` + BuildDate string `json:"buildDate"` + } + + operatorInfo = &PrintableOperatorInfo{ + Version: info.Version, + GitCommit: info.GitCommit, + BuildDate: info.BuildDate, + } + } else { + // Standard view + type PrintableOperatorInfo struct { + Version string `json:"version"` + } + + operatorInfo = &PrintableOperatorInfo{ + Version: info.Version, + } + } + + return operatorInfo +} + func getRawLocalnet(cfg *config.LocalStatus, ciConfig *config.ConnectInvocationConfig, localnet *commonapi.LocalNetStatus, statusMap map[string]any) any { if !ciConfig.WithRootManager { @@ -300,7 +335,7 @@ func (p *statusPrinter) printRuntimeConfig() { p.white(p.ciConfig.ConnectionConfig.Cluster)) } if p.cfg.Details { - runtimeConfig += fmt.Sprintf(" (config-dir: %s, machine-id %s)", p.ciConfig.SignadotDir, machineID) + runtimeConfig += fmt.Sprintf(" (config-dir: %s, machine-id: %s)", p.ciConfig.SignadotDir, machineID) } p.printLine(p.out, 0, runtimeConfig, "*") } @@ -314,6 +349,9 @@ func (p *statusPrinter) printErrors(errs []error) { func (p *statusPrinter) printSuccess() { p.printLine(p.out, 0, fmt.Sprintf("Local connection healthy!"), p.green("✓")) + if p.status.OperatorInfo != nil { + p.printOperatorInfo() + } if p.ciConfig.ConnectionConfig.Type == connectcfg.PortForwardLinkType { p.printPortforwardStatus() } @@ -325,6 +363,15 @@ func (p *statusPrinter) printSuccess() { p.printSandboxStatus() } +func (p *statusPrinter) printOperatorInfo() { + msg := fmt.Sprintf("operator version %s", p.status.OperatorInfo.Version) + if p.cfg.Details { + msg += fmt.Sprintf(" (git-commit: %s, build-date: %s)", + p.status.OperatorInfo.GitCommit, p.status.OperatorInfo.BuildDate) + } + p.printLine(p.out, 1, msg, "*") +} + func (p *statusPrinter) printPortforwardStatus() { p.printLine(p.out, 1, fmt.Sprintf("port-forward listening at %q", p.status.Portforward.LocalAddress), "*") } diff --git a/internal/command/sandbox/apply.go b/internal/command/sandbox/apply.go index 8ea2286..e6a5b45 100644 --- a/internal/command/sandbox/apply.go +++ b/internal/command/sandbox/apply.go @@ -89,12 +89,9 @@ func apply(cfg *config.SandboxApply, out, log io.Writer, args []string) error { fmt.Fprintf(log, "Created sandbox %q (routing key: %s) in cluster %q.\n\n", req.Name, resp.RoutingKey, *req.Spec.Cluster) - if len(req.Spec.Local) > 0 && !sbmgr.IsWatcherRunning(status) { - // We don't really know here if it is a temporal problem or if we are - // dealing with an old operator that doesn't support it, in any case we - // will go ahead and register the sandbox in sandboxmanager. If this is - // a temporal issue, it will fix itself inside of sandboxmanager. - + if len(req.Spec.Local) > 0 && status.OperatorInfo == nil { + // we are dealing with an old operator that doesn't support sandboxes + // watcher, go ahead and register the sandbox in sandboxmanager. if err = sbmgr.RegisterSandbox(resp.Name, resp.RoutingKey); err != nil { return fmt.Errorf("couldn't register sandbox in sandboxmanager, %v", err) } diff --git a/internal/locald/api/common.pb.go b/internal/locald/api/common.pb.go index db8a63a..49cf85d 100644 --- a/internal/locald/api/common.pb.go +++ b/internal/locald/api/common.pb.go @@ -397,6 +397,69 @@ func (x *SandboxStatus) GetLocalWorkloads() []*SandboxStatus_LocalWorkload { return nil } +type OperatorInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + GitCommit string `protobuf:"bytes,2,opt,name=git_commit,json=gitCommit,proto3" json:"git_commit,omitempty"` + BuildDate string `protobuf:"bytes,3,opt,name=build_date,json=buildDate,proto3" json:"build_date,omitempty"` +} + +func (x *OperatorInfo) Reset() { + *x = OperatorInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_locald_api_common_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OperatorInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OperatorInfo) ProtoMessage() {} + +func (x *OperatorInfo) ProtoReflect() protoreflect.Message { + mi := &file_internal_locald_api_common_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OperatorInfo.ProtoReflect.Descriptor instead. +func (*OperatorInfo) Descriptor() ([]byte, []int) { + return file_internal_locald_api_common_proto_rawDescGZIP(), []int{6} +} + +func (x *OperatorInfo) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *OperatorInfo) GetGitCommit() string { + if x != nil { + return x.GitCommit + } + return "" +} + +func (x *OperatorInfo) GetBuildDate() string { + if x != nil { + return x.BuildDate + } + return "" +} + type SandboxStatus_Baseline struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -411,7 +474,7 @@ type SandboxStatus_Baseline struct { func (x *SandboxStatus_Baseline) Reset() { *x = SandboxStatus_Baseline{} if protoimpl.UnsafeEnabled { - mi := &file_internal_locald_api_common_proto_msgTypes[6] + mi := &file_internal_locald_api_common_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -424,7 +487,7 @@ func (x *SandboxStatus_Baseline) String() string { func (*SandboxStatus_Baseline) ProtoMessage() {} func (x *SandboxStatus_Baseline) ProtoReflect() protoreflect.Message { - mi := &file_internal_locald_api_common_proto_msgTypes[6] + mi := &file_internal_locald_api_common_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -480,7 +543,7 @@ type SandboxStatus_BaselineToLocal struct { func (x *SandboxStatus_BaselineToLocal) Reset() { *x = SandboxStatus_BaselineToLocal{} if protoimpl.UnsafeEnabled { - mi := &file_internal_locald_api_common_proto_msgTypes[7] + mi := &file_internal_locald_api_common_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -493,7 +556,7 @@ func (x *SandboxStatus_BaselineToLocal) String() string { func (*SandboxStatus_BaselineToLocal) ProtoMessage() {} func (x *SandboxStatus_BaselineToLocal) ProtoReflect() protoreflect.Message { - mi := &file_internal_locald_api_common_proto_msgTypes[7] + mi := &file_internal_locald_api_common_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -542,7 +605,7 @@ type SandboxStatus_LocalWorkload struct { func (x *SandboxStatus_LocalWorkload) Reset() { *x = SandboxStatus_LocalWorkload{} if protoimpl.UnsafeEnabled { - mi := &file_internal_locald_api_common_proto_msgTypes[8] + mi := &file_internal_locald_api_common_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -555,7 +618,7 @@ func (x *SandboxStatus_LocalWorkload) String() string { func (*SandboxStatus_LocalWorkload) ProtoMessage() {} func (x *SandboxStatus_LocalWorkload) ProtoReflect() protoreflect.Message { - mi := &file_internal_locald_api_common_proto_msgTypes[8] + mi := &file_internal_locald_api_common_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -688,10 +751,17 @@ var file_internal_locald_api_common_proto_rawDesc = []byte{ 0x6e, 0x65, 0x6c, 0x5f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x0c, 0x74, 0x75, 0x6e, 0x6e, - 0x65, 0x6c, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x2f, - 0x63, 0x6c, 0x69, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, - 0x61, 0x6c, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x6c, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x22, 0x66, 0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x69, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x61, 0x74, 0x65, + 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -706,7 +776,7 @@ func file_internal_locald_api_common_proto_rawDescGZIP() []byte { return file_internal_locald_api_common_proto_rawDescData } -var file_internal_locald_api_common_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_internal_locald_api_common_proto_msgTypes = make([]protoimpl.MessageInfo, 10) var file_internal_locald_api_common_proto_goTypes = []interface{}{ (*ServiceHealth)(nil), // 0: apicommon.ServiceHealth (*LocalNetStatus)(nil), // 1: apicommon.LocalNetStatus @@ -714,21 +784,22 @@ var file_internal_locald_api_common_proto_goTypes = []interface{}{ (*PortForwardStatus)(nil), // 3: apicommon.PortForwardStatus (*WatcherStatus)(nil), // 4: apicommon.WatcherStatus (*SandboxStatus)(nil), // 5: apicommon.SandboxStatus - (*SandboxStatus_Baseline)(nil), // 6: apicommon.SandboxStatus.Baseline - (*SandboxStatus_BaselineToLocal)(nil), // 7: apicommon.SandboxStatus.BaselineToLocal - (*SandboxStatus_LocalWorkload)(nil), // 8: apicommon.SandboxStatus.LocalWorkload - (*timestamp.Timestamp)(nil), // 9: google.protobuf.Timestamp + (*OperatorInfo)(nil), // 6: apicommon.OperatorInfo + (*SandboxStatus_Baseline)(nil), // 7: apicommon.SandboxStatus.Baseline + (*SandboxStatus_BaselineToLocal)(nil), // 8: apicommon.SandboxStatus.BaselineToLocal + (*SandboxStatus_LocalWorkload)(nil), // 9: apicommon.SandboxStatus.LocalWorkload + (*timestamp.Timestamp)(nil), // 10: google.protobuf.Timestamp } var file_internal_locald_api_common_proto_depIdxs = []int32{ - 9, // 0: apicommon.ServiceHealth.last_error_time:type_name -> google.protobuf.Timestamp + 10, // 0: apicommon.ServiceHealth.last_error_time:type_name -> google.protobuf.Timestamp 0, // 1: apicommon.LocalNetStatus.health:type_name -> apicommon.ServiceHealth 0, // 2: apicommon.HostsStatus.health:type_name -> apicommon.ServiceHealth - 9, // 3: apicommon.HostsStatus.last_update_time:type_name -> google.protobuf.Timestamp + 10, // 3: apicommon.HostsStatus.last_update_time:type_name -> google.protobuf.Timestamp 0, // 4: apicommon.PortForwardStatus.health:type_name -> apicommon.ServiceHealth 0, // 5: apicommon.WatcherStatus.health:type_name -> apicommon.ServiceHealth - 8, // 6: apicommon.SandboxStatus.local_workloads:type_name -> apicommon.SandboxStatus.LocalWorkload - 6, // 7: apicommon.SandboxStatus.LocalWorkload.baseline:type_name -> apicommon.SandboxStatus.Baseline - 7, // 8: apicommon.SandboxStatus.LocalWorkload.workloadPortMapping:type_name -> apicommon.SandboxStatus.BaselineToLocal + 9, // 6: apicommon.SandboxStatus.local_workloads:type_name -> apicommon.SandboxStatus.LocalWorkload + 7, // 7: apicommon.SandboxStatus.LocalWorkload.baseline:type_name -> apicommon.SandboxStatus.Baseline + 8, // 8: apicommon.SandboxStatus.LocalWorkload.workloadPortMapping:type_name -> apicommon.SandboxStatus.BaselineToLocal 0, // 9: apicommon.SandboxStatus.LocalWorkload.tunnel_health:type_name -> apicommon.ServiceHealth 10, // [10:10] is the sub-list for method output_type 10, // [10:10] is the sub-list for method input_type @@ -816,7 +887,7 @@ func file_internal_locald_api_common_proto_init() { } } file_internal_locald_api_common_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxStatus_Baseline); i { + switch v := v.(*OperatorInfo); i { case 0: return &v.state case 1: @@ -828,7 +899,7 @@ func file_internal_locald_api_common_proto_init() { } } file_internal_locald_api_common_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxStatus_BaselineToLocal); i { + switch v := v.(*SandboxStatus_Baseline); i { case 0: return &v.state case 1: @@ -840,6 +911,18 @@ func file_internal_locald_api_common_proto_init() { } } file_internal_locald_api_common_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SandboxStatus_BaselineToLocal); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_locald_api_common_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SandboxStatus_LocalWorkload); i { case 0: return &v.state @@ -858,7 +941,7 @@ func file_internal_locald_api_common_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_internal_locald_api_common_proto_rawDesc, NumEnums: 0, - NumMessages: 9, + NumMessages: 10, NumExtensions: 0, NumServices: 0, }, diff --git a/internal/locald/api/common.proto b/internal/locald/api/common.proto index ffa6ba9..40913b4 100644 --- a/internal/locald/api/common.proto +++ b/internal/locald/api/common.proto @@ -70,4 +70,10 @@ message SandboxStatus { string name = 1; string routing_key = 2; repeated LocalWorkload local_workloads = 3; +} + +message OperatorInfo { + string version = 1; + string git_commit = 2; + string build_date = 3; } \ No newline at end of file diff --git a/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go b/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go index b0a2afd..46bc98e 100644 --- a/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go +++ b/internal/locald/api/sandboxmanager/sandbox_manager_api.pb.go @@ -67,12 +67,13 @@ type StatusResponse struct { // connect invocation config // (instance of internal/config/locald.ConnectInvocationConfig) - CiConfig *_struct.Struct `protobuf:"bytes,1,opt,name=ci_config,json=ciConfig,proto3" json:"ci_config,omitempty"` - Localnet *api.LocalNetStatus `protobuf:"bytes,2,opt,name=localnet,proto3" json:"localnet,omitempty"` - Hosts *api.HostsStatus `protobuf:"bytes,3,opt,name=hosts,proto3" json:"hosts,omitempty"` - Portforward *api.PortForwardStatus `protobuf:"bytes,4,opt,name=portforward,proto3" json:"portforward,omitempty"` - Watcher *api.WatcherStatus `protobuf:"bytes,6,opt,name=watcher,proto3" json:"watcher,omitempty"` - Sandboxes []*api.SandboxStatus `protobuf:"bytes,5,rep,name=sandboxes,proto3" json:"sandboxes,omitempty"` + CiConfig *_struct.Struct `protobuf:"bytes,1,opt,name=ci_config,json=ciConfig,proto3" json:"ci_config,omitempty"` + OperatorInfo *api.OperatorInfo `protobuf:"bytes,7,opt,name=operator_info,json=operatorInfo,proto3" json:"operator_info,omitempty"` + Localnet *api.LocalNetStatus `protobuf:"bytes,2,opt,name=localnet,proto3" json:"localnet,omitempty"` + Hosts *api.HostsStatus `protobuf:"bytes,3,opt,name=hosts,proto3" json:"hosts,omitempty"` + Portforward *api.PortForwardStatus `protobuf:"bytes,4,opt,name=portforward,proto3" json:"portforward,omitempty"` + Watcher *api.WatcherStatus `protobuf:"bytes,6,opt,name=watcher,proto3" json:"watcher,omitempty"` + Sandboxes []*api.SandboxStatus `protobuf:"bytes,5,rep,name=sandboxes,proto3" json:"sandboxes,omitempty"` } func (x *StatusResponse) Reset() { @@ -114,6 +115,13 @@ func (x *StatusResponse) GetCiConfig() *_struct.Struct { return nil } +func (x *StatusResponse) GetOperatorInfo() *api.OperatorInfo { + if x != nil { + return x.OperatorInfo + } + return nil +} + func (x *StatusResponse) GetLocalnet() *api.LocalNetStatus { if x != nil { return x.Localnet @@ -331,60 +339,64 @@ var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_rawDesc = 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x0f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, - 0xd7, 0x02, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x95, 0x03, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x09, 0x63, 0x69, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x08, - 0x63, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, - 0x6c, 0x6e, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x70, 0x69, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4e, 0x65, 0x74, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x6e, 0x65, 0x74, 0x12, - 0x2c, 0x0a, 0x05, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, - 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x05, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x3e, 0x0a, - 0x0b, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, - 0x6f, 0x72, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x0b, 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x32, 0x0a, - 0x07, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, - 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, - 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x07, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, - 0x72, 0x12, 0x36, 0x0a, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x18, 0x05, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x09, - 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x68, 0x75, - 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x12, 0x0a, 0x10, - 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x5c, 0x0a, 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x61, 0x6e, 0x64, - 0x62, 0x6f, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x61, - 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, - 0x0b, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x22, 0x19, - 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, - 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x95, 0x02, 0x0a, 0x11, 0x53, 0x61, - 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x41, 0x50, 0x49, 0x12, - 0x49, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x2e, 0x73, 0x61, 0x6e, 0x64, - 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, - 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x08, 0x53, 0x68, - 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1f, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, - 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, - 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x64, 0x0a, 0x0f, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x12, 0x26, - 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, + 0x63, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3c, 0x0a, 0x0d, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x6f, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x35, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x6e, + 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x4e, 0x65, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x6e, 0x65, 0x74, 0x12, 0x2c, 0x0a, + 0x05, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, + 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x73, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x05, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x3e, 0x0a, 0x0b, 0x70, + 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x6f, 0x72, + 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0b, + 0x70, 0x6f, 0x72, 0x74, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x32, 0x0a, 0x07, 0x77, + 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, + 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x07, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, + 0x36, 0x0a, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, + 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x09, 0x73, 0x61, + 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x68, 0x75, 0x74, 0x64, + 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x53, 0x68, + 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5c, + 0x0a, 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x72, + 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x22, 0x19, 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, - 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, - 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x42, 0x3c, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x95, 0x02, 0x0a, 0x11, 0x53, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x41, 0x50, 0x49, 0x12, 0x49, 0x0a, + 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x08, 0x53, 0x68, 0x75, 0x74, + 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1f, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x64, 0x0a, 0x0f, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x12, 0x26, 0x2e, 0x73, + 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x61, + 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, + 0x3c, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, + 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -408,30 +420,32 @@ var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_goTypes = (*RegisterSandboxRequest)(nil), // 4: sandboxmanager.RegisterSandboxRequest (*RegisterSandboxResponse)(nil), // 5: sandboxmanager.RegisterSandboxResponse (*_struct.Struct)(nil), // 6: google.protobuf.Struct - (*api.LocalNetStatus)(nil), // 7: apicommon.LocalNetStatus - (*api.HostsStatus)(nil), // 8: apicommon.HostsStatus - (*api.PortForwardStatus)(nil), // 9: apicommon.PortForwardStatus - (*api.WatcherStatus)(nil), // 10: apicommon.WatcherStatus - (*api.SandboxStatus)(nil), // 11: apicommon.SandboxStatus + (*api.OperatorInfo)(nil), // 7: apicommon.OperatorInfo + (*api.LocalNetStatus)(nil), // 8: apicommon.LocalNetStatus + (*api.HostsStatus)(nil), // 9: apicommon.HostsStatus + (*api.PortForwardStatus)(nil), // 10: apicommon.PortForwardStatus + (*api.WatcherStatus)(nil), // 11: apicommon.WatcherStatus + (*api.SandboxStatus)(nil), // 12: apicommon.SandboxStatus } var file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_depIdxs = []int32{ 6, // 0: sandboxmanager.StatusResponse.ci_config:type_name -> google.protobuf.Struct - 7, // 1: sandboxmanager.StatusResponse.localnet:type_name -> apicommon.LocalNetStatus - 8, // 2: sandboxmanager.StatusResponse.hosts:type_name -> apicommon.HostsStatus - 9, // 3: sandboxmanager.StatusResponse.portforward:type_name -> apicommon.PortForwardStatus - 10, // 4: sandboxmanager.StatusResponse.watcher:type_name -> apicommon.WatcherStatus - 11, // 5: sandboxmanager.StatusResponse.sandboxes:type_name -> apicommon.SandboxStatus - 0, // 6: sandboxmanager.SandboxManagerAPI.Status:input_type -> sandboxmanager.StatusRequest - 2, // 7: sandboxmanager.SandboxManagerAPI.Shutdown:input_type -> sandboxmanager.ShutdownRequest - 4, // 8: sandboxmanager.SandboxManagerAPI.RegisterSandbox:input_type -> sandboxmanager.RegisterSandboxRequest - 1, // 9: sandboxmanager.SandboxManagerAPI.Status:output_type -> sandboxmanager.StatusResponse - 3, // 10: sandboxmanager.SandboxManagerAPI.Shutdown:output_type -> sandboxmanager.ShutdownResponse - 5, // 11: sandboxmanager.SandboxManagerAPI.RegisterSandbox:output_type -> sandboxmanager.RegisterSandboxResponse - 9, // [9:12] is the sub-list for method output_type - 6, // [6:9] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name + 7, // 1: sandboxmanager.StatusResponse.operator_info:type_name -> apicommon.OperatorInfo + 8, // 2: sandboxmanager.StatusResponse.localnet:type_name -> apicommon.LocalNetStatus + 9, // 3: sandboxmanager.StatusResponse.hosts:type_name -> apicommon.HostsStatus + 10, // 4: sandboxmanager.StatusResponse.portforward:type_name -> apicommon.PortForwardStatus + 11, // 5: sandboxmanager.StatusResponse.watcher:type_name -> apicommon.WatcherStatus + 12, // 6: sandboxmanager.StatusResponse.sandboxes:type_name -> apicommon.SandboxStatus + 0, // 7: sandboxmanager.SandboxManagerAPI.Status:input_type -> sandboxmanager.StatusRequest + 2, // 8: sandboxmanager.SandboxManagerAPI.Shutdown:input_type -> sandboxmanager.ShutdownRequest + 4, // 9: sandboxmanager.SandboxManagerAPI.RegisterSandbox:input_type -> sandboxmanager.RegisterSandboxRequest + 1, // 10: sandboxmanager.SandboxManagerAPI.Status:output_type -> sandboxmanager.StatusResponse + 3, // 11: sandboxmanager.SandboxManagerAPI.Shutdown:output_type -> sandboxmanager.ShutdownResponse + 5, // 12: sandboxmanager.SandboxManagerAPI.RegisterSandbox:output_type -> sandboxmanager.RegisterSandboxResponse + 10, // [10:13] is the sub-list for method output_type + 7, // [7:10] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name } func init() { file_internal_locald_api_sandboxmanager_sandbox_manager_api_proto_init() } diff --git a/internal/locald/api/sandboxmanager/sandbox_manager_api.proto b/internal/locald/api/sandboxmanager/sandbox_manager_api.proto index fbc3582..2e570a7 100644 --- a/internal/locald/api/sandboxmanager/sandbox_manager_api.proto +++ b/internal/locald/api/sandboxmanager/sandbox_manager_api.proto @@ -31,6 +31,7 @@ message StatusResponse { // connect invocation config // (instance of internal/config/locald.ConnectInvocationConfig) google.protobuf.Struct ci_config = 1; + apicommon.OperatorInfo operator_info = 7; apicommon.LocalNetStatus localnet = 2; apicommon.HostsStatus hosts = 3; apicommon.PortForwardStatus portforward = 4; diff --git a/internal/locald/sandboxmanager/operator_info_updater.go b/internal/locald/sandboxmanager/operator_info_updater.go new file mode 100644 index 0000000..d4d95ea --- /dev/null +++ b/internal/locald/sandboxmanager/operator_info_updater.go @@ -0,0 +1,82 @@ +package sandboxmanager + +import ( + "context" + "log/slog" + "sync" + "time" + + commonapi "github.com/signadot/cli/internal/locald/api" + tunapiv1 "github.com/signadot/libconnect/apiv1" + tunapiclient "github.com/signadot/libconnect/common/apiclient" +) + +type operatorInfoUpdater struct { + sync.Mutex + + log *slog.Logger + operatorInfo *commonapi.OperatorInfo + isRunning bool +} + +func (oiu *operatorInfoUpdater) Get() *commonapi.OperatorInfo { + oiu.Lock() + defer oiu.Unlock() + return oiu.operatorInfo +} + +func (oiu *operatorInfoUpdater) Reset() { + oiu.Lock() + defer oiu.Unlock() + oiu.operatorInfo = nil +} + +func (oiu *operatorInfoUpdater) Reload(ctx context.Context, tunAPIClient tunapiclient.Client, force bool) { + oiu.Lock() + defer oiu.Unlock() + + if oiu.isRunning { + // nothing to do here + return + } + if !force && oiu.operatorInfo != nil { + // we already have the operator info + return + } + // reload the data + go oiu.reload(ctx, tunAPIClient) +} + +func (oiu *operatorInfoUpdater) reload(ctx context.Context, tunAPIClient tunapiclient.Client) { + oiu.setIsRunning(true) + defer oiu.setIsRunning(false) + + for { + resp, err := tunAPIClient.GetOperatorInfo(ctx, &tunapiv1.GetOperatorInfoRRequest{}) + if err == nil { + // update the operator info + oiu.Lock() + oiu.operatorInfo = &commonapi.OperatorInfo{ + Version: resp.Version, + GitCommit: resp.GitCommit, + BuildDate: resp.BuildDate, + } + oiu.Unlock() + return + } + + // retry later + oiu.log.Error("getting operator info", "error", err) + select { + case <-ctx.Done(): + return + case <-time.After(3 * time.Second): + } + } +} + +func (oiu *operatorInfoUpdater) setIsRunning(isRunning bool) { + oiu.Lock() + defer oiu.Unlock() + oiu.isRunning = isRunning +} diff --git a/internal/locald/sandboxmanager/sandbox_manager.go b/internal/locald/sandboxmanager/sandbox_manager.go index 5a85a79..e42bf23 100644 --- a/internal/locald/sandboxmanager/sandbox_manager.go +++ b/internal/locald/sandboxmanager/sandbox_manager.go @@ -35,8 +35,6 @@ type sandboxManager struct { hostname string machineID string grpcServer *grpc.Server - sbmServer *sbmServer - sbmWatcher *sbmWatcher portForward *portforward.PortForward shutdownCh chan struct{} @@ -111,13 +109,18 @@ func (m *sandboxManager) Run(ctx context.Context) error { } } + // Create an operator info updater + oiu := &operatorInfoUpdater{ + log: m.log, + } + // Create the watcher - m.sbmWatcher = newSandboxManagerWatcher(m.log, m.machineID, m.revtunClient, m.shutdownCh) + sbmWatcher := newSandboxManagerWatcher(m.log, m.machineID, m.revtunClient, oiu, m.shutdownCh) // Register our service in gRPC server - m.sbmServer = newSandboxManagerGRPCServer(m.log, m.ciConfig, m.portForward, - m.sbmWatcher, m.shutdownCh) - sbapi.RegisterSandboxManagerAPIServer(m.grpcServer, m.sbmServer) + sbmServer := newSandboxManagerGRPCServer(m.log, m.ciConfig, m.portForward, + sbmWatcher, oiu, m.shutdownCh) + sbapi.RegisterSandboxManagerAPIServer(m.grpcServer, sbmServer) // Run the gRPC server if err := m.runAPIServer(); err != nil { @@ -143,7 +146,7 @@ func (m *sandboxManager) Run(ctx context.Context) error { } // Run the sandboxes watcher - m.sbmWatcher.run(ctx, m.tunAPIClient) + sbmWatcher.run(runCtx, m.tunAPIClient) // Wait until termination <-runCtx.Done() @@ -151,7 +154,7 @@ func (m *sandboxManager) Run(ctx context.Context) error { // Clean up m.log.Info("Shutting down") m.grpcServer.GracefulStop() - m.sbmWatcher.stop() + sbmWatcher.stop() if m.portForward != nil { m.portForward.Close() } diff --git a/internal/locald/sandboxmanager/sandbox_server.go b/internal/locald/sandboxmanager/sandbox_server.go index e5018e2..b500f1f 100644 --- a/internal/locald/sandboxmanager/sandbox_server.go +++ b/internal/locald/sandboxmanager/sandbox_server.go @@ -23,6 +23,7 @@ type sbmServer struct { sbapi.UnimplementedSandboxManagerAPIServer log *slog.Logger + oiu *operatorInfoUpdater // runtime config ciConfig *config.ConnectInvocationConfig @@ -42,10 +43,11 @@ type sbmServer struct { } func newSandboxManagerGRPCServer(log *slog.Logger, ciConfig *config.ConnectInvocationConfig, - portForward *portforward.PortForward, sbmWatcher *sbmWatcher, + portForward *portforward.PortForward, sbmWatcher *sbmWatcher, oiu *operatorInfoUpdater, shutdownCh chan struct{}) *sbmServer { srv := &sbmServer{ log: log, + oiu: oiu, ciConfig: ciConfig, portForward: portForward, sbmWatcher: sbmWatcher, @@ -64,10 +66,11 @@ func (s *sbmServer) Status(ctx context.Context, req *sbapi.StatusRequest) (*sbap } resp := &sbapi.StatusResponse{ - CiConfig: grpcCIConfig, - Portforward: s.portForwardStatus(), - Watcher: s.watcherStatus(), - Sandboxes: s.sbStatuses(), + CiConfig: grpcCIConfig, + OperatorInfo: s.oiu.Get(), + Portforward: s.portForwardStatus(), + Watcher: s.watcherStatus(), + Sandboxes: s.sbStatuses(), } resp.Hosts, resp.Localnet = s.rootStatus() return resp, nil diff --git a/internal/locald/sandboxmanager/sandboxes_watcher.go b/internal/locald/sandboxmanager/sandboxes_watcher.go index afa0107..f5d6a2e 100644 --- a/internal/locald/sandboxmanager/sandboxes_watcher.go +++ b/internal/locald/sandboxmanager/sandboxes_watcher.go @@ -15,8 +15,13 @@ import ( "google.golang.org/grpc/status" ) +const ( + SandboxesWatcherUnimplemented = "this feature requires operator >= 0.14.1" +) + type sbmWatcher struct { log *slog.Logger + oiu *operatorInfoUpdater machineID string @@ -33,9 +38,10 @@ type sbmWatcher struct { } func newSandboxManagerWatcher(log *slog.Logger, machineID string, revtunClient func() revtun.Client, - shutdownCh chan struct{}) *sbmWatcher { + oiu *operatorInfoUpdater, shutdownCh chan struct{}) *sbmWatcher { srv := &sbmWatcher{ log: log, + oiu: oiu, machineID: machineID, status: svchealth.ServiceHealth{ Healthy: false, @@ -82,7 +88,7 @@ func (sbw *sbmWatcher) readStream(ctx context.Context, for { event, err := sbwClient.Recv() if err == nil { - sbw.setSuccess() + sbw.setSuccess(ctx) sbw.processStreamEvent(event) continue } @@ -107,7 +113,7 @@ func (sbw *sbmWatcher) readStream(ctx context.Context, sbw.setError("sandboxes watch internal grpc error", err) <-time.After(3 * time.Second) case codes.Unimplemented: - sbw.setError("this feature requires operator >= 0.14.1", nil) + sbw.setError(SandboxesWatcherUnimplemented, nil) // in this case, check again in 1 minutes <-time.After(1 * time.Minute) default: @@ -214,13 +220,16 @@ func (sbw *sbmWatcher) stopMonitors() { } } -func (sbw *sbmWatcher) setSuccess() { +func (sbw *sbmWatcher) setSuccess(ctx context.Context) { sbw.sbMu.Lock() defer sbw.sbMu.Unlock() // update the status sbw.status.Healthy = true + // try loading the operator info + sbw.oiu.Reload(ctx, sbw.tunAPIClient, false) + // stop all sandbox monitor (if any) sbw.stopMonitors() } @@ -229,6 +238,7 @@ func (sbw *sbmWatcher) setError(errMsg string, err error) { sbw.sbMu.Lock() defer sbw.sbMu.Unlock() + // update the status now := time.Now() var reason string if err != nil { @@ -243,6 +253,9 @@ func (sbw *sbmWatcher) setError(errMsg string, err error) { sbw.status.LastErrorReason = reason sbw.status.LastErrorTime = &now sbw.status.ErrorCount += 1 + + // reset the operator info + sbw.oiu.Reset() } func (sbw *sbmWatcher) registerSandbox(sandboxName, routingKey string) { diff --git a/internal/locald/sandboxmanager/sdk.go b/internal/locald/sandboxmanager/sdk.go index cc18cd2..5504d8b 100644 --- a/internal/locald/sandboxmanager/sdk.go +++ b/internal/locald/sandboxmanager/sdk.go @@ -113,11 +113,11 @@ func checkHostsStatus(hosts *commonapi.HostsStatus) error { return fmt.Errorf(errorMsg) } -func IsWatcherRunning(status *sbmapi.StatusResponse) bool { +func IsWatcherRunning(status *sbmapi.StatusResponse) (bool, string) { if status == nil || status.Watcher == nil || status.Watcher.Health == nil { - return false + return false, "" } - return status.Watcher.Health.Healthy + return status.Watcher.Health.Healthy, status.Watcher.Health.LastErrorReason } func RegisterSandbox(sandboxName, routingKey string) error {