From 466b58c08b3b1a27bedf032f20218e5e1cb6263e Mon Sep 17 00:00:00 2001 From: Johan Brandhorst-Satzkorn Date: Thu, 21 Nov 2024 16:38:51 -0800 Subject: [PATCH] WIP --- .../daemon/cluster/handlers/worker_service.go | 569 +++++-- .../handlers/worker_service_status_test.go | 34 +- internal/daemon/worker/common/common.go | 24 + internal/daemon/worker/job_info.go | 240 +++ internal/daemon/worker/routing_info.go | 165 ++ internal/daemon/worker/statistics.go | 71 + internal/daemon/worker/status.go | 368 +---- internal/daemon/worker/worker.go | 82 +- .../daemon/worker/worker_proxy_service.go | 17 +- internal/daemon/worker/worker_test.go | 2 +- internal/gen/controller/servers/servers.pb.go | 19 +- .../server_coordination_service.pb.go | 1385 +++++++++++++---- .../server_coordination_service_grpc.pb.go | 147 +- .../v1/server_coordination_service.proto | 187 ++- .../proto/controller/servers/v1/servers.proto | 5 +- internal/server/repository_worker.go | 43 +- internal/server/rewrapping.go | 3 - internal/server/worker.go | 11 +- internal/session/repository_connection.go | 4 +- .../session/repository_connection_test.go | 4 +- .../session/service_worker_status_report.go | 5 - .../cluster/multi_controller_worker_test.go | 6 +- version/feature_manager.go | 30 +- 23 files changed, 2407 insertions(+), 1014 deletions(-) create mode 100644 internal/daemon/worker/job_info.go create mode 100644 internal/daemon/worker/routing_info.go create mode 100644 internal/daemon/worker/statistics.go diff --git a/internal/daemon/cluster/handlers/worker_service.go b/internal/daemon/cluster/handlers/worker_service.go index 2e3209f2a7..6498cd24fe 100644 --- a/internal/daemon/cluster/handlers/worker_service.go +++ b/internal/daemon/cluster/handlers/worker_service.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/boundary/internal/daemon/controller/common" "github.com/hashicorp/boundary/internal/daemon/controller/handlers" + "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/event" pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services" intglobals "github.com/hashicorp/boundary/internal/globals" @@ -21,6 +22,7 @@ import ( "github.com/hashicorp/boundary/internal/types/scope" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets" "github.com/hashicorp/boundary/sdk/pbs/plugin" + "github.com/hashicorp/boundary/version" "github.com/hashicorp/go-bexpr" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -94,143 +96,18 @@ func NewWorkerServiceServer( } } -func (ws *workerServiceServer) Status(ctx context.Context, req *pbs.StatusRequest) (*pbs.StatusResponse, error) { - const op = "workers.(workerServiceServer).Status" - // TODO: on the worker, if we get errors back from this repeatedly, do we - // terminate all sessions since we can't know if they were canceled? - - wStat := req.GetWorkerStatus() - if wStat == nil { - return &pbs.StatusResponse{}, status.Error(codes.InvalidArgument, "Worker sent nil status.") - } - switch { - case wStat.GetName() == "" && wStat.GetKeyId() == "": - return &pbs.StatusResponse{}, status.Error(codes.InvalidArgument, "Name and keyId are not set in the request; one is required.") - case wStat.GetAddress() == "": - return &pbs.StatusResponse{}, status.Error(codes.InvalidArgument, "Address is not set but is required.") - } - // This Store call is currently only for testing purposes - ws.updateTimes.Store(wStat.GetName(), time.Now()) - - serverRepo, err := ws.serversRepoFn() - if err != nil { - event.WriteError(ctx, op, err, event.WithInfoMsg("error getting server repo")) - return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error acquiring repo to store worker status: %v", err) - } - - // Convert API tags to storage tags - wTags := wStat.GetTags() - workerTags := make([]*server.Tag, 0, len(wTags)) - for _, v := range wTags { - workerTags = append(workerTags, &server.Tag{ - Key: v.GetKey(), - Value: v.GetValue(), - }) - } - - if wStat.OperationalState == "" { - // If this is an older worker (pre 0.11), it will not have ReleaseVersion and we'll default to active. - // Otherwise, default to Unknown. - if wStat.ReleaseVersion == "" { - wStat.OperationalState = server.ActiveOperationalState.String() - } else { - wStat.OperationalState = server.UnknownOperationalState.String() - } - } - - if wStat.LocalStorageState == "" { - // If this is an older worker (pre 0.15), it will not have LocalStorageState as part of it's status - // so we'll default to unknown. - wStat.LocalStorageState = server.UnknownLocalStorageState.String() - } - - wConf := server.NewWorker(scope.Global.String(), - server.WithName(wStat.GetName()), - server.WithDescription(wStat.GetDescription()), - server.WithAddress(wStat.GetAddress()), - server.WithWorkerTags(workerTags...), - server.WithReleaseVersion(wStat.ReleaseVersion), - server.WithOperationalState(wStat.OperationalState), - server.WithLocalStorageState(wStat.LocalStorageState)) - opts := []server.Option{server.WithUpdateTags(req.GetUpdateTags())} - if wStat.GetPublicId() != "" { - opts = append(opts, server.WithPublicId(wStat.GetPublicId())) - } - if wStat.GetKeyId() != "" { - opts = append(opts, server.WithKeyId(wStat.GetKeyId())) - } - wrk, err := serverRepo.UpsertWorkerStatus(ctx, wConf, opts...) - if err != nil { - event.WriteError(ctx, op, err, event.WithInfoMsg("error storing worker status")) - return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error storing worker status: %v", err) - } - - // update storage states - if sbcStates := wStat.GetStorageBucketCredentialStates(); sbcStates != nil && wrk.GetPublicId() != "" { - updateWorkerStorageBucketCredentialStatesFn(ctx, serverRepo, wrk.GetPublicId(), sbcStates) - } - - controllers, err := serverRepo.ListControllers(ctx, server.WithLiveness(time.Duration(ws.livenessTimeToStale.Load()))) - if err != nil { - event.WriteError(ctx, op, err, event.WithInfoMsg("error getting current controllers")) - return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error getting current controllers: %v", err) - } - - responseControllers := []*pbs.UpstreamServer{} - for _, c := range controllers { - thisController := &pbs.UpstreamServer{ - Address: c.Address, - Type: pbs.UpstreamServer_TYPE_CONTROLLER, - } - responseControllers = append(responseControllers, thisController) - } - - workerAuthRepo, err := ws.workerAuthRepoFn() - if err != nil { - event.WriteError(ctx, op, err, event.WithInfoMsg("error getting worker auth repo")) - return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error acquiring repo to lookup worker auth info: %v", err) - } - - authorizedDownstreams := &pbs.AuthorizedDownstreamWorkerList{} - if len(req.GetConnectedWorkerPublicIds()) > 0 { - knownConnectedWorkers, err := serverRepo.ListWorkers(ctx, []string{scope.Global.String()}, server.WithWorkerPool(req.GetConnectedWorkerPublicIds()), server.WithLiveness(-1)) - if err != nil { - event.WriteError(ctx, op, err, event.WithInfoMsg("error getting known connected worker ids")) - return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error getting known connected worker ids: %v", err) - } - authorizedDownstreams.WorkerPublicIds = server.WorkerList(knownConnectedWorkers).PublicIds() - } - - if len(req.GetConnectedUnmappedWorkerKeyIdentifiers()) > 0 { - authorizedKeyIds, err := workerAuthRepo.FilterToAuthorizedWorkerKeyIds(ctx, req.GetConnectedUnmappedWorkerKeyIdentifiers()) - if err != nil { - event.WriteError(ctx, op, err, event.WithInfoMsg("error getting authorized unmapped worker key ids")) - return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error getting authorized worker key ids: %v", err) - } - authorizedDownstreams.UnmappedWorkerKeyIdentifiers = authorizedKeyIds - } - - authorizedWorkerList := &pbs.AuthorizedWorkerList{} - if len(req.GetConnectedWorkerKeyIdentifiers()) > 0 { - authorizedKeyIds, err := workerAuthRepo.FilterToAuthorizedWorkerKeyIds(ctx, req.GetConnectedWorkerKeyIdentifiers()) - if err != nil { - event.WriteError(ctx, op, err, event.WithInfoMsg("error getting authorized worker key ids")) - return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error getting authorized worker key ids: %v", err) - } - authorizedWorkerList.WorkerKeyIdentifiers = authorizedKeyIds - } - - ret := &pbs.StatusResponse{ - CalculatedUpstreams: responseControllers, - WorkerId: wrk.GetPublicId(), - AuthorizedWorkers: authorizedWorkerList, - AuthorizedDownstreamWorkers: authorizedDownstreams, - } - - stateReport := make([]*session.StateReport, 0, len(req.GetJobs())) +func calculateJobChanges( + ctx context.Context, + jobs []*pbs.JobStatus, + sessRepo *session.Repository, + connectionRepo *session.ConnectionRepository, + workerId string, +) ([]*pbs.JobChangeRequest, error) { + const op = "workers.calculateJobChanges" + stateReport := make([]*session.StateReport, 0, len(jobs)) var monitoredSessionIds []string - for _, jobStatus := range req.GetJobs() { + for _, jobStatus := range jobs { switch jobStatus.Job.GetType() { case pbs.JOBTYPE_JOBTYPE_MONITOR_SESSION: si := jobStatus.GetJob().GetMonitorSessionInfo() @@ -277,22 +154,12 @@ func (ws *workerServiceServer) Status(ctx context.Context, req *pbs.StatusReques } } - sessRepo, err := ws.sessionRepoFn() - if err != nil { - event.WriteError(ctx, op, err, event.WithInfoMsg("error getting sessions repo")) - return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error acquiring repo to query session status: %v", err) - } - connectionRepo, err := ws.connectionRepoFn() - if err != nil { - event.WriteError(ctx, op, err, event.WithInfoMsg("error getting connection repo")) - return &pbs.StatusResponse{}, status.Errorf(codes.Internal, "Error acquiring repo to query session status: %v", err) - } - - notActive, err := session.WorkerStatusReport(ctx, sessRepo, connectionRepo, wrk.GetPublicId(), stateReport) + var jobRequests []*pbs.JobChangeRequest + notActive, err := session.WorkerStatusReport(ctx, sessRepo, connectionRepo, workerId, stateReport) if err != nil { return nil, status.Errorf(codes.Internal, "Error comparing state of sessions for worker with public id %q: %v", - wrk.GetPublicId(), err) + workerId, err) } for _, na := range notActive { var connChanges []*pbs.Connection @@ -306,12 +173,14 @@ func (ws *workerServiceServer) Status(ctx context.Context, req *pbs.StatusReques if na.Unrecognized { processErr = pbs.SessionProcessingError_SESSION_PROCESSING_ERROR_UNRECOGNIZED } - ret.JobsRequests = append(ret.JobsRequests, &pbs.JobChangeRequest{ + // Tell the worker which managed sessions should be canceled + jobRequests = append(jobRequests, &pbs.JobChangeRequest{ Job: &pbs.Job{ Type: pbs.JOBTYPE_JOBTYPE_SESSION, JobInfo: &pbs.Job_SessionInfo{ SessionInfo: &pbs.SessionJobInfo{ - SessionId: na.SessionId, + SessionId: na.SessionId, + // The status is either canceling or terminated at this point Status: na.Status.ProtoVal(), Connections: connChanges, ProcessingError: processErr, @@ -332,12 +201,14 @@ func (ws *workerServiceServer) Status(ctx context.Context, req *pbs.StatusReques if na.Unrecognized { processErr = pbs.SessionProcessingError_SESSION_PROCESSING_ERROR_UNRECOGNIZED } - ret.JobsRequests = append(ret.JobsRequests, &pbs.JobChangeRequest{ + // Tell the worker which monitored sessions should be canceled + jobRequests = append(jobRequests, &pbs.JobChangeRequest{ Job: &pbs.Job{ Type: pbs.JOBTYPE_JOBTYPE_MONITOR_SESSION, JobInfo: &pbs.Job_MonitorSessionInfo{ MonitorSessionInfo: &pbs.MonitorSessionJobInfo{ - SessionId: na.SessionId, + SessionId: na.SessionId, + // The status is either canceling or terminated at this point Status: na.Status.ProtoVal(), ProcessingError: processErr, }, @@ -347,6 +218,294 @@ func (ws *workerServiceServer) Status(ctx context.Context, req *pbs.StatusReques }) } + return jobRequests, nil +} + +func calculateUpstreams( + ctx context.Context, + serverRepo *server.Repository, + livenessTimeToStale time.Duration, +) ([]*pbs.UpstreamServer, error) { + const op = "workers.calculateUpstreams" + + controllers, err := serverRepo.ListControllers(ctx, server.WithLiveness(livenessTimeToStale)) + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error getting current controllers")) + return nil, status.Errorf(codes.Internal, "Error getting current controllers: %v", err) + } + + var calculatedUpstreams []*pbs.UpstreamServer + for _, c := range controllers { + thisController := &pbs.UpstreamServer{ + Address: c.Address, + Type: pbs.UpstreamServer_TYPE_CONTROLLER, + } + calculatedUpstreams = append(calculatedUpstreams, thisController) + } + + return calculatedUpstreams, nil +} + +func calculateDownstreams( + ctx context.Context, + serverRepo *server.Repository, + workerAuthRepo *server.WorkerAuthRepositoryStorage, + connectedWorkerPublicIds []string, + connectedUnmappedWorkerKeyIdentifiers []string, +) (*pbs.AuthorizedDownstreamWorkerList, error) { + const op = "workers.calculateDownstreams" + + authorizedDownstreamWorkers := &pbs.AuthorizedDownstreamWorkerList{} + if len(connectedWorkerPublicIds) > 0 { + knownConnectedWorkers, err := serverRepo.ListWorkers(ctx, []string{scope.Global.String()}, server.WithWorkerPool(connectedWorkerPublicIds), server.WithLiveness(-1)) + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error getting known connected worker ids")) + return nil, status.Errorf(codes.Internal, "Error getting known connected worker ids: %v", err) + } + authorizedDownstreamWorkers.WorkerPublicIds = server.WorkerList(knownConnectedWorkers).PublicIds() + } + + if len(connectedUnmappedWorkerKeyIdentifiers) > 0 { + authorizedKeyIds, err := workerAuthRepo.FilterToAuthorizedWorkerKeyIds(ctx, connectedUnmappedWorkerKeyIdentifiers) + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error getting authorized unmapped worker key ids")) + return nil, status.Errorf(codes.Internal, "Error getting authorized worker key ids: %v", err) + } + authorizedDownstreamWorkers.UnmappedWorkerKeyIdentifiers = authorizedKeyIds + } + + return authorizedDownstreamWorkers, nil +} + +func updateBytesUpBytesDown( + ctx context.Context, + connectionRepo *session.ConnectionRepository, + sessions []*pbs.SessionStatistics, +) error { + const op = "workers.UpdateBytesUpBytesDown" + var reportedConnections []*session.Connection + for _, si := range sessions { + if si == nil { + return status.Error(codes.Internal, "Error getting session info at status time") + } + + for _, conn := range si.GetConnections() { + reportedConnections = append(reportedConnections, &session.Connection{ + PublicId: conn.GetConnectionId(), + BytesUp: conn.GetBytesUp(), + BytesDown: conn.GetBytesDown(), + }) + } + } + err := connectionRepo.UpdateBytesUpBytesDown(ctx, reportedConnections...) + if err != nil { + return errors.New(ctx, errors.Internal, op, fmt.Sprintf("failed to update bytes up and down for worker reported connections: %v", err)) + } + return nil +} + +func workerTooOld(controllerVer, workerVer *version.Info) bool { + cSeg := controllerVer.Semver().Segments() + cMajor := cSeg[0] + cMinor := cSeg[1] + wSeg := workerVer.Semver().Segments() + wMajor := wSeg[0] + wMinor := wSeg[1] + + // If we're older than 0.21, the worker version doesn't matter + if cMajor == 0 && cMinor < 21 { + return false + } + // If the worker version is greater than or equal to 0.19, we're ok + if wMajor == 0 && wMinor >= 19 { + return false + } + // Controller is >= 0.21 and worker is < 0.19, worker is too old + return true +} + +func (ws *workerServiceServer) Status(ctx context.Context, req *pbs.StatusRequest) (*pbs.StatusResponse, error) { + const op = "workers.(workerServiceServer).Status" + + workerVer := version.FromVersionString(req.GetReleaseVersion()) + if workerVer == nil { + // Older workers will set the release version in the deprecated worker status + workerVer = version.FromVersionString(req.GetWorkerStatus().GetReleaseVersion()) + } + switch { + case workerVer == nil: + return nil, status.Error(codes.InvalidArgument, "ReleaseVersion is not set but is required.") + case version.Get().Semver().LessThan(workerVer.Semver()): + return nil, status.Errorf(codes.InvalidArgument, "Worker version %s is greater than the controller version", workerVer.FullVersionNumber(false)) + case workerTooOld(version.Get(), workerVer): + return nil, status.Errorf(codes.FailedPrecondition, "Worker version %s is unsupported by the controller version, please upgrade", workerVer.FullVersionNumber(false)) + } + serverRepo, err := ws.serversRepoFn() + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error getting server repo")) + return nil, status.Errorf(codes.Internal, "Error acquiring repo to store worker status: %v", err) + } + + if version.SupportsFeature(workerVer.Semver(), version.MultipleWorkerStatusRpcs) { + // If the worker uses multiple worker status RPCs, we just need to upsert the + // update time in the DB and potentially generate a worker ID + + wConf := server.NewWorker( + scope.Global.String(), + server.WithReleaseVersion(workerVer.VersionNumber()), + ) + var opts []server.Option + if req.GetWorkerId() != "" { + opts = append(opts, server.WithPublicId(req.GetWorkerId())) + } + if req.GetKeyId() != "" { + opts = append(opts, server.WithKeyId(req.GetKeyId())) + } + wrk, err := serverRepo.UpsertWorkerStatus(ctx, wConf, opts...) + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error storing worker status")) + return nil, status.Errorf(codes.Internal, "Error storing worker status: %v", err) + } + + return &pbs.StatusResponse{ + WorkerId: wrk.GetPublicId(), + }, nil + } + + // This is an older worker that only supports a single status RPC, so we need to do the rest of the work + // TODO: Remove the code below this line after the 0.21.0 release + sessRepo, err := ws.sessionRepoFn() + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error getting sessions repo")) + return nil, status.Errorf(codes.Internal, "Error acquiring repo to query session status: %v", err) + } + connectionRepo, err := ws.connectionRepoFn() + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error getting connection repo")) + return nil, status.Errorf(codes.Internal, "Error acquiring repo to query connection status: %v", err) + } + workerAuthRepo, err := ws.workerAuthRepoFn() + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error getting worker auth repo")) + return nil, status.Errorf(codes.Internal, "Error acquiring repo to lookup worker auth info: %v", err) + } + + wStat := req.GetWorkerStatus() + if wStat == nil { + return nil, status.Error(codes.InvalidArgument, "Worker sent nil status.") + } + switch { + case wStat.GetName() == "" && wStat.GetKeyId() == "": + return nil, status.Error(codes.InvalidArgument, "Name and keyId are not set in the request; one is required.") + case wStat.GetAddress() == "": + return nil, status.Error(codes.InvalidArgument, "Address is not set but is required.") + case wStat.GetReleaseVersion() == "" || workerVer == nil: + return nil, status.Error(codes.InvalidArgument, "ReleaseVersion is not set but is required.") + case version.Get().Semver().LessThan(workerVer.Semver()): + return nil, status.Errorf(codes.InvalidArgument, "Worker version %s is greater than the controller version", wStat.ReleaseVersion) + case wStat.GetOperationalState() == "": + return nil, status.Error(codes.InvalidArgument, "OperationalState is not set but is required.") + case wStat.GetLocalStorageState() == "": + return nil, status.Error(codes.InvalidArgument, "LocalStorageState is not set but is required.") + } + // This Store call is currently only for testing purposes + ws.updateTimes.Store(wStat.GetName(), time.Now()) + + // Convert API tags to storage tags + wTags := wStat.GetTags() + workerTags := make([]*server.Tag, 0, len(wTags)) + for _, v := range wTags { + workerTags = append(workerTags, &server.Tag{ + Key: v.GetKey(), + Value: v.GetValue(), + }) + } + + wConf := server.NewWorker(scope.Global.String(), + server.WithName(wStat.GetName()), + server.WithDescription(wStat.GetDescription()), + server.WithAddress(wStat.GetAddress()), + server.WithWorkerTags(workerTags...), + server.WithReleaseVersion(wStat.ReleaseVersion), + server.WithOperationalState(wStat.OperationalState), + server.WithLocalStorageState(wStat.LocalStorageState)) + opts := []server.Option{server.WithUpdateTags(req.GetUpdateTags())} + if wStat.GetPublicId() != "" { + opts = append(opts, server.WithPublicId(wStat.GetPublicId())) + } + if wStat.GetKeyId() != "" { + opts = append(opts, server.WithKeyId(wStat.GetKeyId())) + } + wrk, err := serverRepo.UpsertWorkerStatus(ctx, wConf, opts...) + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error storing worker status")) + return nil, status.Errorf(codes.Internal, "Error storing worker status: %v", err) + } + + ret := &pbs.StatusResponse{ + WorkerId: wrk.GetPublicId(), + } + ret.JobsRequests, err = calculateJobChanges(ctx, req.GetJobs(), sessRepo, connectionRepo, wrk.GetPublicId()) + if err != nil { + return nil, err + } + + if sbcStates := wStat.GetStorageBucketCredentialStates(); sbcStates != nil && wrk.GetPublicId() != "" { + updateWorkerStorageBucketCredentialStatesFn(ctx, serverRepo, wrk.GetPublicId(), sbcStates) + } + + var sessions []*pbs.SessionJobInfo + for _, job := range req.GetJobs() { + if job.GetJob().GetType() == pbs.JOBTYPE_JOBTYPE_SESSION && job.GetJob().GetSessionInfo() != nil { + sessions = append(sessions, job.Job.GetSessionInfo()) + } + } + + // Convert incoming session stats to the new format + var sessionStats []*pbs.SessionStatistics + for _, si := range sessions { + var sessionStat pbs.SessionStatistics + switch si.Status { + case pbs.SESSIONSTATUS_SESSIONSTATUS_CANCELING, + pbs.SESSIONSTATUS_SESSIONSTATUS_TERMINATED: + // No need to see about canceling anything + continue + } + + for _, conn := range si.GetConnections() { + switch conn.Status { + case pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_AUTHORIZED, + pbs.CONNECTIONSTATUS_CONNECTIONSTATUS_CONNECTED: + sessionStat.Connections = append(sessionStat.Connections, &pbs.ConnectionStatistics{ + ConnectionId: conn.GetConnectionId(), + BytesUp: conn.GetBytesUp(), + BytesDown: conn.GetBytesDown(), + }) + } + } + sessionStats = append(sessionStats, &sessionStat) + } + + if err := updateBytesUpBytesDown(ctx, connectionRepo, sessionStats); err != nil { + return nil, err + } + + ret.CalculatedUpstreams, err = calculateUpstreams(ctx, serverRepo, time.Duration(ws.livenessTimeToStale.Load())) + if err != nil { + return nil, err + } + + ret.AuthorizedDownstreamWorkers, err = calculateDownstreams( + ctx, + serverRepo, + workerAuthRepo, + req.GetConnectedWorkerPublicIds(), + req.GetConnectedUnmappedWorkerKeyIdentifiers(), + ) + if err != nil { + return nil, err + } + return ret, nil } @@ -387,6 +546,112 @@ func (ws *workerServiceServer) ListHcpbWorkers(ctx context.Context, req *pbs.Lis return resp, nil } +func (ws *workerServiceServer) JobInfo(ctx context.Context, req *pbs.JobInfoRequest) (*pbs.JobInfoResponse, error) { + const op = "workers.(workerServiceServer).JobInfo" + + switch { + case req.GetWorkerId() == "": + return nil, status.Error(codes.InvalidArgument, "Worker ID is required.") + } + + sessRepo, err := ws.sessionRepoFn() + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error getting sessions repo")) + return nil, status.Errorf(codes.Internal, "Error acquiring repo to query session status: %v", err) + } + connectionRepo, err := ws.connectionRepoFn() + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error getting connection repo")) + return nil, status.Errorf(codes.Internal, "Error acquiring repo to query connection status: %v", err) + } + + ret := &pbs.JobInfoResponse{} + + ret.JobsRequests, err = calculateJobChanges(ctx, req.GetJobs(), sessRepo, connectionRepo, req.GetWorkerId()) + if err != nil { + return nil, err + } + return ret, nil +} + +func (ws *workerServiceServer) RoutingInfo(ctx context.Context, req *pbs.RoutingInfoRequest) (*pbs.RoutingInfoResponse, error) { + const op = "workers.(workerServiceServer).RoutingInfo" + + switch { + case req.GetWorkerId() == "": + return nil, status.Error(codes.InvalidArgument, "Worker ID is required.") + } + + serverRepo, err := ws.serversRepoFn() + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error getting server repo")) + return nil, status.Errorf(codes.Internal, "Error acquiring repo to store worker status: %v", err) + } + workerAuthRepo, err := ws.workerAuthRepoFn() + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error getting worker auth repo")) + return nil, status.Errorf(codes.Internal, "Error acquiring repo to lookup worker auth info: %v", err) + } + + // Convert API tags to storage tags + wTags := req.GetTags() + workerTags := make([]*server.Tag, 0, len(wTags)) + for _, v := range wTags { + workerTags = append(workerTags, &server.Tag{ + Key: v.GetKey(), + Value: v.GetValue(), + }) + } + + wConf := server.NewWorker(scope.Global.String(), + server.WithPublicId(req.GetWorkerId()), + server.WithWorkerTags(workerTags...), + server.WithOperationalState(req.GetOperationalState()), + server.WithLocalStorageState(req.GetLocalStorageState())) + opts := []server.Option{server.WithUpdateTags(req.GetUpdateTags())} + _, err = serverRepo.UpsertWorkerStatus(ctx, wConf, opts...) + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error storing worker routing updates")) + return nil, status.Errorf(codes.Internal, "Error storing worker status: %v", err) + } + + if sbcStates := req.GetStorageBucketCredentialStates(); sbcStates != nil && req.GetWorkerId() != "" { + updateWorkerStorageBucketCredentialStatesFn(ctx, serverRepo, req.GetWorkerId(), sbcStates) + } + + ret := &pbs.RoutingInfoResponse{} + ret.CalculatedUpstreams, err = calculateUpstreams(ctx, serverRepo, time.Duration(ws.livenessTimeToStale.Load())) + if err != nil { + return nil, err + } + + ret.AuthorizedDownstreamWorkers, err = calculateDownstreams( + ctx, + serverRepo, + workerAuthRepo, + req.GetConnectedWorkerPublicIds(), + req.GetConnectedUnmappedWorkerKeyIdentifiers(), + ) + if err != nil { + return nil, err + } + return ret, nil +} + +func (ws *workerServiceServer) Statistics(ctx context.Context, req *pbs.StatisticsRequest) (*pbs.StatisticsResponse, error) { + const op = "workers.(workerServiceServer).Statistics" + + connectionRepo, err := ws.connectionRepoFn() + if err != nil { + event.WriteError(ctx, op, err, event.WithInfoMsg("error getting connection repo")) + return nil, status.Errorf(codes.Internal, "Error acquiring repo to query connection status: %v", err) + } + if err := updateBytesUpBytesDown(ctx, connectionRepo, req.GetSessions()); err != nil { + return nil, err + } + return &pbs.StatisticsResponse{}, nil +} + // Single-hop filter lookup. We have either an egress filter or worker filter to use, if any // Used to verify that the worker serving this session to a client matches this filter func egressFilterSelector(sessionInfo *session.Session) string { diff --git a/internal/daemon/cluster/handlers/worker_service_status_test.go b/internal/daemon/cluster/handlers/worker_service_status_test.go index 1183372751..8517c2698a 100644 --- a/internal/daemon/cluster/handlers/worker_service_status_test.go +++ b/internal/daemon/cluster/handlers/worker_service_status_test.go @@ -148,7 +148,6 @@ func TestStatus(t *testing.T) { }, }, WorkerId: worker1.PublicId, - AuthorizedWorkers: &pbs.AuthorizedWorkerList{}, AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{}, }, }, @@ -228,7 +227,6 @@ func TestStatus(t *testing.T) { }, }, WorkerId: worker1.PublicId, - AuthorizedWorkers: &pbs.AuthorizedWorkerList{}, AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{}, JobsRequests: []*pbs.JobChangeRequest{ { @@ -336,7 +334,6 @@ func TestStatus(t *testing.T) { }, }, WorkerId: worker1.PublicId, - AuthorizedWorkers: &pbs.AuthorizedWorkerList{}, AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{}, JobsRequests: []*pbs.JobChangeRequest{ { @@ -414,7 +411,6 @@ func TestStatus(t *testing.T) { }, }, WorkerId: worker1.PublicId, - AuthorizedWorkers: &pbs.AuthorizedWorkerList{}, AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{}, }, }, @@ -468,7 +464,6 @@ func TestStatus(t *testing.T) { pbs.SessionJobInfo{}, pbs.MonitorSessionJobInfo{}, pbs.Connection{}, - pbs.AuthorizedWorkerList{}, pbs.AuthorizedDownstreamWorkerList{}, ), cmpopts.IgnoreFields(pb.ServerWorkerStatus{}, "Tags"), @@ -628,7 +623,6 @@ func TestStatusSessionClosed(t *testing.T) { }, }, WorkerId: worker1.PublicId, - AuthorizedWorkers: &pbs.AuthorizedWorkerList{}, AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{}, }, }, @@ -662,7 +656,6 @@ func TestStatusSessionClosed(t *testing.T) { pbs.Job_SessionInfo{}, pbs.SessionJobInfo{}, pbs.Connection{}, - pbs.AuthorizedWorkerList{}, pbs.AuthorizedDownstreamWorkerList{}, ), cmpopts.IgnoreFields(pb.ServerWorkerStatus{}, "Tags"), @@ -797,7 +790,6 @@ func TestStatusDeadConnection(t *testing.T) { }, }, WorkerId: worker1.PublicId, - AuthorizedWorkers: &pbs.AuthorizedWorkerList{}, AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{}, } @@ -816,7 +808,6 @@ func TestStatusDeadConnection(t *testing.T) { pbs.Job_SessionInfo{}, pbs.SessionJobInfo{}, pbs.Connection{}, - pbs.AuthorizedWorkerList{}, pbs.AuthorizedDownstreamWorkerList{}, ), cmpopts.IgnoreFields(pb.ServerWorkerStatus{}, "Tags"), @@ -952,7 +943,6 @@ func TestStatusWorkerWithKeyId(t *testing.T) { }, }, WorkerId: worker1.PublicId, - AuthorizedWorkers: &pbs.AuthorizedWorkerList{}, AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{}, }, }, @@ -992,7 +982,6 @@ func TestStatusWorkerWithKeyId(t *testing.T) { }, }, WorkerId: worker1.PublicId, - AuthorizedWorkers: &pbs.AuthorizedWorkerList{}, AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{}, }, }, @@ -1023,7 +1012,6 @@ func TestStatusWorkerWithKeyId(t *testing.T) { pbs.Job_SessionInfo{}, pbs.SessionJobInfo{}, pbs.Connection{}, - pbs.AuthorizedWorkerList{}, pbs.AuthorizedDownstreamWorkerList{}, ), cmpopts.IgnoreFields(pb.ServerWorkerStatus{}, "Tags"), @@ -1094,7 +1082,6 @@ func TestStatusAuthorizedWorkers(t *testing.T) { Name: worker1.GetName(), Address: worker1.GetAddress(), }, - ConnectedWorkerKeyIdentifiers: []string{}, }, want: &pbs.StatusResponse{ CalculatedUpstreams: []*pbs.UpstreamServer{ @@ -1104,7 +1091,6 @@ func TestStatusAuthorizedWorkers(t *testing.T) { }, }, WorkerId: worker1.PublicId, - AuthorizedWorkers: &pbs.AuthorizedWorkerList{}, AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{}, }, }, @@ -1126,7 +1112,6 @@ func TestStatusAuthorizedWorkers(t *testing.T) { }, }, WorkerId: worker1.PublicId, - AuthorizedWorkers: &pbs.AuthorizedWorkerList{}, AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{}, }, }, @@ -1139,7 +1124,6 @@ func TestStatusAuthorizedWorkers(t *testing.T) { Name: worker1.GetName(), Address: worker1.GetAddress(), }, - ConnectedWorkerKeyIdentifiers: []string{w1KeyId, w2KeyId, "unknown"}, }, want: &pbs.StatusResponse{ CalculatedUpstreams: []*pbs.UpstreamServer{ @@ -1148,10 +1132,7 @@ func TestStatusAuthorizedWorkers(t *testing.T) { Address: "127.0.0.1", }, }, - WorkerId: worker1.PublicId, - AuthorizedWorkers: &pbs.AuthorizedWorkerList{ - WorkerKeyIdentifiers: []string{w1KeyId, w2KeyId}, - }, + WorkerId: worker1.PublicId, AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{}, }, }, @@ -1164,7 +1145,6 @@ func TestStatusAuthorizedWorkers(t *testing.T) { Name: worker1.GetName(), Address: worker1.GetAddress(), }, - ConnectedWorkerKeyIdentifiers: []string{w1KeyId, w2KeyId, "unknown"}, ConnectedUnmappedWorkerKeyIdentifiers: []string{w2KeyId, "unknown"}, ConnectedWorkerPublicIds: []string{w1.GetPublicId(), "unknown"}, }, @@ -1176,9 +1156,6 @@ func TestStatusAuthorizedWorkers(t *testing.T) { }, }, WorkerId: worker1.PublicId, - AuthorizedWorkers: &pbs.AuthorizedWorkerList{ - WorkerKeyIdentifiers: []string{w1KeyId, w2KeyId}, - }, AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{ UnmappedWorkerKeyIdentifiers: []string{w2KeyId}, WorkerPublicIds: []string{w1.GetPublicId()}, @@ -1194,7 +1171,6 @@ func TestStatusAuthorizedWorkers(t *testing.T) { Name: worker1.GetName(), Address: worker1.GetAddress(), }, - ConnectedWorkerKeyIdentifiers: []string{w1KeyId, w2KeyId, "unknown"}, ConnectedUnmappedWorkerKeyIdentifiers: []string{"unknown"}, ConnectedWorkerPublicIds: []string{w1.GetPublicId(), w2.GetPublicId(), "unknown"}, }, @@ -1206,9 +1182,6 @@ func TestStatusAuthorizedWorkers(t *testing.T) { }, }, WorkerId: worker1.PublicId, - AuthorizedWorkers: &pbs.AuthorizedWorkerList{ - WorkerKeyIdentifiers: []string{w1KeyId, w2KeyId}, - }, AuthorizedDownstreamWorkers: &pbs.AuthorizedDownstreamWorkerList{ WorkerPublicIds: []string{w1.GetPublicId(), w2.GetPublicId()}, }, @@ -1227,10 +1200,6 @@ func TestStatusAuthorizedWorkers(t *testing.T) { assert.Equal(tc.wantErrMsg, err.Error()) return } - gotAuthorizedWorkers := got.GetAuthorizedWorkers() - sort.Strings(gotAuthorizedWorkers.GetWorkerKeyIdentifiers()) - wantAuthorizedWorkers := tc.want.GetAuthorizedWorkers() - sort.Strings(wantAuthorizedWorkers.GetWorkerKeyIdentifiers()) sort.Strings(got.GetAuthorizedDownstreamWorkers().GetWorkerPublicIds()) sort.Strings(tc.want.GetAuthorizedDownstreamWorkers().GetWorkerPublicIds()) sort.Strings(got.GetAuthorizedDownstreamWorkers().GetUnmappedWorkerKeyIdentifiers()) @@ -1248,7 +1217,6 @@ func TestStatusAuthorizedWorkers(t *testing.T) { pbs.Job_SessionInfo{}, pbs.SessionJobInfo{}, pbs.Connection{}, - pbs.AuthorizedWorkerList{}, pbs.AuthorizedDownstreamWorkerList{}, ), cmpopts.IgnoreFields(pb.ServerWorkerStatus{}, "Tags"), diff --git a/internal/daemon/worker/common/common.go b/internal/daemon/worker/common/common.go index 0b6ca43ca3..fd72e52fe3 100644 --- a/internal/daemon/worker/common/common.go +++ b/internal/daemon/worker/common/common.go @@ -18,4 +18,28 @@ const ( // DefaultStatusTimeout is the timeout duration on status calls to the controller from // the worker DefaultStatusTimeout = server.DefaultLiveness / 3 + + // JobInfoInterval is the base duration used in the calculation of the random backoff + // during the worker job info report + JobInfoInterval = 2 * time.Second + + // DefaultJobInfoTimeout is the timeout duration on JobInfo calls to the controller from + // the worker + DefaultJobInfoTimeout = server.DefaultLiveness / 3 + + // RoutingInfoInterval is the base duration used in the calculation of the random backoff + // during the worker routing info report + RoutingInfoInterval = 10 * time.Second + + // DefaultRoutingInfoTimeout is the timeout duration on RoutingInfo calls to the controller from + // the worker + DefaultRoutingInfoTimeout = server.DefaultLiveness / 2 + + // StatisticsInterval is the base duration used in the calculation of the random backoff + // during the worker statistics report + StatisticsInterval = 15 * time.Second + + // DefaultStatisticsTimeout is the timeout duration on Statistics calls to the controller from + // the worker + DefaultStatisticsTimeout = server.DefaultLiveness ) diff --git a/internal/daemon/worker/job_info.go b/internal/daemon/worker/job_info.go new file mode 100644 index 0000000000..4a6f009fc5 --- /dev/null +++ b/internal/daemon/worker/job_info.go @@ -0,0 +1,240 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package worker + +import ( + "context" + "errors" + "math/rand" + "time" + + "github.com/hashicorp/boundary/internal/daemon/worker/common" + "github.com/hashicorp/boundary/internal/daemon/worker/session" + "github.com/hashicorp/boundary/internal/event" + pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services" +) + +type LastJobInfo struct { + *pbs.JobInfoResponse + JobInfoTime time.Time +} + +// LastJobInfoSuccess reports the last time we sent a successful +// session route info request. +func (w *Worker) LastJobInfoSuccess() *LastJobInfo { + s, ok := w.lastJobInfoSuccess.Load().(*LastJobInfo) + if !ok { + return nil + } + return s +} + +func (w *Worker) startJobInfoTicking(cancelCtx context.Context) { + const op = "worker.(Worker).startJobInfoTicking" + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + timer := time.NewTimer(0) + for { + select { + case <-cancelCtx.Done(): + event.WriteSysEvent(w.baseContext, op, "session route info ticking shutting down") + return + + case <-timer.C: + w.sendJobInfo(cancelCtx) + // Add a bit of jitter to the wait, so we aren't always getting, + // status updates at the exact same intervals, to ease the load on the DB. + timer.Reset(common.JobInfoInterval + getRandomInterval(r)) + } + } +} + +func (w *Worker) sendJobInfo(cancelCtx context.Context) { + const op = "worker.(Worker).sendJobInfo" + w.confLock.Lock() + defer w.confLock.Unlock() + + // Collect the different session ids that are being monitored by this worker + var monitoredSessionIds []string + + if w.recorderManager != nil { + recSessIds, err := w.recorderManager.SessionsManaged(cancelCtx) + if err != nil { + event.WriteError(cancelCtx, op, err, event.WithInfoMsg("error getting session ids from recorderManager")) + } else { + monitoredSessionIds = append(monitoredSessionIds, recSessIds...) + } + } + + // First send info as-is. We'll perform cleanup duties after we + // get cancel/job change info back. + var activeJobs []*pbs.JobStatus + + for _, sid := range monitoredSessionIds { + activeJobs = append(activeJobs, &pbs.JobStatus{ + Job: &pbs.Job{ + Type: pbs.JOBTYPE_JOBTYPE_MONITOR_SESSION, + JobInfo: &pbs.Job_MonitorSessionInfo{ + MonitorSessionInfo: &pbs.MonitorSessionJobInfo{ + SessionId: sid, + Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE, + }, + }, + }, + }) + } + + // Range over known sessions and collect info + w.sessionManager.ForEachLocalSession(func(s session.Session) bool { + status := s.GetStatus() + sessionId := s.GetId() + localConnections := s.GetLocalConnections() + connections := make([]*pbs.Connection, 0, len(localConnections)) + for k, v := range localConnections { + connections = append(connections, &pbs.Connection{ + ConnectionId: k, + Status: v.Status, + }) + } + activeJobs = append(activeJobs, &pbs.JobStatus{ + Job: &pbs.Job{ + Type: pbs.JOBTYPE_JOBTYPE_SESSION, + JobInfo: &pbs.Job_SessionInfo{ + SessionInfo: &pbs.SessionJobInfo{ + SessionId: sessionId, + Status: status, + Connections: connections, + }, + }, + }, + }) + return true + }) + + ctx, cancel := context.WithTimeout(cancelCtx, time.Duration(w.jobInfoCallTimeoutDuration.Load())) + defer cancel() + // Send status information + clientCon := w.GrpcClientConn.Load() + client := pbs.NewServerCoordinationServiceClient(clientCon) + result, err := client.JobInfo(ctx, &pbs.JobInfoRequest{ + WorkerId: w.LastStatusSuccess().WorkerId, + Jobs: activeJobs, + }) + if err != nil { + event.WriteError(cancelCtx, op, err, event.WithInfoMsg("error making job info request to controller", "controller_address", clientCon.Target())) + return + } + + var nonActiveMonitoredSessionIds []string + for _, request := range result.GetJobsRequests() { + switch request.GetRequestType() { + case pbs.CHANGETYPE_CHANGETYPE_UPDATE_STATE: + switch request.GetJob().GetType() { + case pbs.JOBTYPE_JOBTYPE_MONITOR_SESSION: + si := request.GetJob().GetMonitorSessionInfo() + if si != nil && si.Status != pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE { + nonActiveMonitoredSessionIds = append(nonActiveMonitoredSessionIds, si.GetSessionId()) + } + case pbs.JOBTYPE_JOBTYPE_SESSION: + sessInfo := request.GetJob().GetSessionInfo() + sessionId := sessInfo.GetSessionId() + si := w.sessionManager.Get(sessionId) + if si == nil { + event.WriteError(cancelCtx, op, errors.New("session change requested but could not find local information for it"), event.WithInfo("session_id", sessionId)) + continue + } + si.ApplyLocalStatus(sessInfo.GetStatus()) + + // Update connection state if there are any connections in + // the request. + for _, conn := range sessInfo.GetConnections() { + if err := si.ApplyLocalConnectionStatus(conn.GetConnectionId(), conn.GetStatus()); err != nil { + event.WriteError(cancelCtx, op, err, event.WithInfo("connection_id", conn.GetConnectionId())) + } + } + } + } + } + if w.recorderManager != nil { + if err := w.recorderManager.ReauthorizeAllExcept(cancelCtx, nonActiveMonitoredSessionIds); err != nil { + event.WriteError(cancelCtx, op, err) + } + } + + // Standard cleanup: Run through current jobs. Cancel connections + // for any canceling session or any session that is expired. + w.cleanupConnections(cancelCtx, false) + + // Store the new route info after updating the addresses so that it can compare to the old route info first + w.lastJobInfoSuccess.Store(&LastJobInfo{JobInfoResponse: result, JobInfoTime: time.Now()}) +} + +// cleanupConnections walks all sessions and shuts down all proxy connections. +// After the local connections are terminated, they are requested to be marked +// close on the controller. +// Additionally, sessions without connections are cleaned up from the +// local worker's state. +// +// Use ignoreSessionState to ignore the state checks, this closes all +// connections, regardless of whether or not the session is still active. +func (w *Worker) cleanupConnections(cancelCtx context.Context, ignoreSessionState bool) { + const op = "worker.(Worker).cleanupConnections" + closeInfo := make(map[string]*session.ConnectionCloseData) + cleanSessionIds := make([]string, 0) + w.sessionManager.ForEachLocalSession(func(s session.Session) bool { + switch { + case ignoreSessionState, + s.GetStatus() == pbs.SESSIONSTATUS_SESSIONSTATUS_CANCELING, + s.GetStatus() == pbs.SESSIONSTATUS_SESSIONSTATUS_TERMINATED, + time.Until(s.GetExpiration()) < 0: + // Cancel connections without regard to individual connection + // state. + closedIds := s.CancelAllLocalConnections() + localConns := s.GetLocalConnections() + for _, connId := range closedIds { + var bytesUp, bytesDown int64 + connInfo, ok := localConns[connId] + if ok { + bytesUp = connInfo.BytesUp() + bytesDown = connInfo.BytesDown() + } + closeInfo[connId] = &session.ConnectionCloseData{ + SessionId: s.GetId(), + BytesUp: bytesUp, + BytesDown: bytesDown, + } + event.WriteSysEvent(cancelCtx, op, "terminated connection due to cancellation or expiration", "session_id", s.GetId(), "connection_id", connId) + } + + // If the session is no longer valid and all connections + // are marked closed, clean up the session. + if len(closedIds) == 0 { + cleanSessionIds = append(cleanSessionIds, s.GetId()) + } + + default: + // Cancel connections *with* regard to individual connection + // state (ie: only ones that the controller has requested be + // terminated). + for _, connId := range s.CancelOpenLocalConnections() { + closeInfo[connId] = &session.ConnectionCloseData{SessionId: s.GetId()} + event.WriteSysEvent(cancelCtx, op, "terminated connection due to cancellation or expiration", "session_id", s.GetId(), "connection_id", connId) + } + } + + return true + }) + + // Note that we won't clean these from the info map until the + // next time we run this function + if len(closeInfo) > 0 { + // Call out to a helper to send the connection close requests to the + // controller, and set the close time. This functionality is shared with + // post-close functionality in the proxy handler. + _ = w.sessionManager.RequestCloseConnections(cancelCtx, closeInfo) + } + // Forget sessions where the session is expired/canceled and all + // connections are canceled and marked closed + w.sessionManager.DeleteLocalSession(cleanSessionIds) +} diff --git a/internal/daemon/worker/routing_info.go b/internal/daemon/worker/routing_info.go new file mode 100644 index 0000000000..240c14e823 --- /dev/null +++ b/internal/daemon/worker/routing_info.go @@ -0,0 +1,165 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package worker + +import ( + "context" + "fmt" + "math/rand" + "slices" + "time" + + "github.com/hashicorp/boundary/internal/daemon/worker/common" + "github.com/hashicorp/boundary/internal/event" + pb "github.com/hashicorp/boundary/internal/gen/controller/servers" + pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services" + "github.com/hashicorp/boundary/internal/server" + "github.com/hashicorp/boundary/sdk/pbs/plugin" +) + +type LastRoutingInfo struct { + *pbs.RoutingInfoResponse + RoutingInfoTime time.Time + LastCalculatedUpstreams []string +} + +// LastRoutingInfoSuccess reports the last time we sent a successful +// session route info request. +func (w *Worker) LastRoutingInfoSuccess() *LastRoutingInfo { + s, ok := w.lastRoutingInfoSuccess.Load().(*LastRoutingInfo) + if !ok { + return nil + } + return s +} + +func (w *Worker) startRoutingInfoTicking(cancelCtx context.Context) { + const op = "worker.(Worker).startRoutingInfoTicking" + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + timer := time.NewTimer(0) + for { + select { + case <-cancelCtx.Done(): + event.WriteSysEvent(w.baseContext, op, "session route info ticking shutting down") + return + + case <-timer.C: + w.sendRoutingInfo(cancelCtx) + // Add a bit of jitter to the wait, so we aren't always getting, + // status updates at the exact same intervals, to ease the load on the DB. + timer.Reset(common.RoutingInfoInterval + getRandomInterval(r)) + } + } +} + +func (w *Worker) sendRoutingInfo(cancelCtx context.Context) { + const op = "worker.(Worker).sendRoutingInfo" + w.confLock.Lock() + defer w.confLock.Unlock() + + var storageBucketCredentialStates map[string]*plugin.StorageBucketCredentialState + if w.RecordingStorage != nil { + storageBucketCredentialStates = w.RecordingStorage.GetStorageBucketCredentialStates() + // If the local storage state is unknown, and we have recording storage set, get the state from the recording storage + // and set it on the worker. This is done once to ensure that the worker has the correct state for the first status + // call. + if w.localStorageState.Load() == server.UnknownLocalStorageState { + w.localStorageState.Store(w.RecordingStorage.GetLocalStorageState(cancelCtx)) + } + } + + var tags []*pb.TagPair + // If we're not going to request a tag update, no reason to have these + // marshaled on every status call. + if w.updateTags.Load() { + tags = w.tags.Load().([]*pb.TagPair) + } + connectionState := w.downstreamConnManager.Connected() + + ctx, cancel := context.WithTimeout(cancelCtx, time.Duration(w.routingInfoCallTimeoutDuration.Load())) + defer cancel() + clientCon := w.GrpcClientConn.Load() + client := pbs.NewServerCoordinationServiceClient(clientCon) + result, err := client.RoutingInfo(ctx, &pbs.RoutingInfoRequest{ + WorkerId: w.LastStatusSuccess().WorkerId, + ConnectedUnmappedWorkerKeyIdentifiers: connectionState.UnmappedKeyIds(), + ConnectedWorkerPublicIds: connectionState.WorkerIds(), + LocalStorageState: w.localStorageState.Load().(server.LocalStorageState).String(), + OperationalState: w.operationalState.Load().(server.OperationalState).String(), + StorageBucketCredentialStates: storageBucketCredentialStates, + Tags: tags, + UpdateTags: w.updateTags.Load(), + }) + if err != nil { + event.WriteError(cancelCtx, op, err, event.WithInfoMsg("error making session route info request to controller", "controller_address", clientCon.Target())) + return + } + + if authorized := result.GetAuthorizedDownstreamWorkers(); authorized != nil { + connectionState.DisconnectMissingWorkers(authorized.GetWorkerPublicIds()) + connectionState.DisconnectMissingUnmappedKeyIds(authorized.GetUnmappedWorkerKeyIdentifiers()) + } + var addrs []string + // This may be empty if we are in a multiple hop scenario + if len(result.CalculatedUpstreams) > 0 { + addrs = make([]string, 0, len(result.CalculatedUpstreams)) + for _, v := range result.CalculatedUpstreams { + addrs = append(addrs, v.Address) + } + } else if checkHCPBUpstreams != nil && checkHCPBUpstreams(w) { + // This is a worker that is one hop away from managed workers, so attempt to get that list + hcpbWorkersCtx, hcpbWorkersCancel := context.WithTimeout(cancelCtx, time.Duration(w.statusCallTimeoutDuration.Load())) + defer hcpbWorkersCancel() + workersResp, err := client.ListHcpbWorkers(hcpbWorkersCtx, &pbs.ListHcpbWorkersRequest{}) + if err != nil { + event.WriteError(hcpbWorkersCtx, op, err, event.WithInfoMsg("error fetching managed worker information")) + } else { + addrs = make([]string, 0, len(workersResp.Workers)) + for _, v := range workersResp.Workers { + addrs = append(addrs, v.Address) + } + } + } + if len(addrs) == 0 { + addrs = append(addrs, w.conf.RawConfig.Worker.InitialUpstreams...) + } + w.updateAddresses(cancelCtx, addrs) + + // Store the new route info after updating the addresses so that it can compare to the old route info first + w.lastRoutingInfoSuccess.Store(&LastRoutingInfo{RoutingInfoResponse: result, RoutingInfoTime: time.Now(), LastCalculatedUpstreams: addrs}) +} + +// Update address receivers and dialing listeners with new addrs +func (w *Worker) updateAddresses(cancelCtx context.Context, addrs []string) { + const op = "worker.(Worker).updateAddrs" + + if len(addrs) == 0 { + return + } + + lastRouteInfo := w.lastRoutingInfoSuccess.Load().(*LastRoutingInfo) + // Compare upstreams; update resolver if there is a difference, and emit an event with old and new addresses + if lastRouteInfo != nil && !slices.Equal(lastRouteInfo.LastCalculatedUpstreams, addrs) { + upstreamsMessage := fmt.Sprintf("Upstreams has changed; old upstreams were: %s, new upstreams are: %s", lastRouteInfo.LastCalculatedUpstreams, addrs) + event.WriteSysEvent(cancelCtx, op, upstreamsMessage) + for _, as := range w.addressReceivers { + as.SetAddresses(addrs) + } + } else if lastRouteInfo == nil { + for _, as := range w.addressReceivers { + as.SetAddresses(addrs) + } + event.WriteSysEvent(cancelCtx, op, fmt.Sprintf("Upstreams after first status set to: %s", addrs)) + } + + // regardless of whether or not it's a new address, we need to set + // them for secondary connections + for _, as := range w.addressReceivers { + switch { + case as.Type() == secondaryConnectionReceiverType: + as.SetAddresses(slices.Clone(addrs)) + } + } +} diff --git a/internal/daemon/worker/statistics.go b/internal/daemon/worker/statistics.go new file mode 100644 index 0000000000..c2ac894304 --- /dev/null +++ b/internal/daemon/worker/statistics.go @@ -0,0 +1,71 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package worker + +import ( + "context" + "math/rand" + "time" + + "github.com/hashicorp/boundary/internal/daemon/worker/common" + "github.com/hashicorp/boundary/internal/daemon/worker/session" + "github.com/hashicorp/boundary/internal/event" + pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services" +) + +func (w *Worker) startStatisticsTicking(cancelCtx context.Context) { + const op = "worker.(Worker).startStatisticsTicking" + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + timer := time.NewTimer(0) + for { + select { + case <-cancelCtx.Done(): + event.WriteSysEvent(w.baseContext, op, "status ticking shutting down") + return + + case <-timer.C: + w.sendWorkerStatistics(cancelCtx) + // Add a bit of jitter to the wait, so we aren't always getting, + // status updates at the exact same intervals, to ease the load on the DB. + timer.Reset(common.StatusInterval + getRandomInterval(r)) + } + } +} + +func (w *Worker) sendWorkerStatistics(cancelCtx context.Context) { + const op = "worker.(Worker).sendWorkerStatistics" + w.confLock.Lock() + defer w.confLock.Unlock() + + // Range over known sessions and collect info + var sessionStats []*pbs.SessionStatistics + w.sessionManager.ForEachLocalSession(func(s session.Session) bool { + var stats pbs.SessionStatistics + localConnections := s.GetLocalConnections() + stats.SessionId = s.GetId() + for k, v := range localConnections { + stats.Connections = append(stats.Connections, &pbs.ConnectionStatistics{ + ConnectionId: k, + BytesUp: v.BytesUp(), + BytesDown: v.BytesDown(), + }) + } + sessionStats = append(sessionStats, &stats) + return true + }) + + ctx, cancel := context.WithTimeout(cancelCtx, time.Duration(w.statisticsCallTimeoutDuration.Load())) + defer cancel() + clientCon := w.GrpcClientConn.Load() + client := pbs.NewServerCoordinationServiceClient(clientCon) + _, err := client.Statistics(ctx, &pbs.StatisticsRequest{ + WorkerId: w.LastStatusSuccess().WorkerId, + Sessions: sessionStats, + }) + if err != nil { + event.WriteError(cancelCtx, op, err, event.WithInfoMsg("error making statistics request to controller", "controller_address", clientCon.Target())) + return + } +} diff --git a/internal/daemon/worker/status.go b/internal/daemon/worker/status.go index 6e4f978702..2a8b3f5d85 100644 --- a/internal/daemon/worker/status.go +++ b/internal/daemon/worker/status.go @@ -8,22 +8,34 @@ import ( "errors" "fmt" "math/rand" + "slices" "time" "github.com/hashicorp/boundary/internal/daemon/worker/common" "github.com/hashicorp/boundary/internal/daemon/worker/session" "github.com/hashicorp/boundary/internal/event" - pb "github.com/hashicorp/boundary/internal/gen/controller/servers" pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services" - "github.com/hashicorp/boundary/internal/server" - "github.com/hashicorp/boundary/sdk/pbs/plugin" "github.com/hashicorp/boundary/version" "github.com/hashicorp/go-secure-stdlib/parseutil" "github.com/hashicorp/go-secure-stdlib/strutil" "google.golang.org/grpc/connectivity" ) -var firstStatusCheckPostHooks []func(context.Context, *Worker) error +var firstStatusCheckPostHooks []func(context.Context, *Worker) error = []func(context.Context, *Worker) error{ + // Start session route info and statistics ticking after first status success + func(ctx context.Context, w *Worker) error { + w.tickerWg.Add(2) + go func() { + defer w.tickerWg.Done() + w.startRoutingInfoTicking(w.baseContext) + }() + go func() { + defer w.tickerWg.Done() + w.startStatisticsTicking(w.baseContext) + }() + return nil + }, +} var downstreamWorkersFactory func(ctx context.Context, workerId string, ver string) (downstreamers, error) @@ -31,25 +43,23 @@ var checkHCPBUpstreams func(w *Worker) bool type LastStatusInformation struct { *pbs.StatusResponse - StatusTime time.Time - LastCalculatedUpstreams []string + StatusTime time.Time +} + +// getRandomInterval returns a duration in a random interval between -0.5 and 0.5 seconds (exclusive). +func getRandomInterval(r *rand.Rand) time.Duration { + // 0 to 0.5 adjustment to the base + f := r.Float64() / 2 + // Half a chance to be faster, not slower + if r.Float32() > 0.5 { + f = -1 * f + } + return time.Duration(f * float64(time.Second)) } -func (w *Worker) startStatusTicking(cancelCtx context.Context, sessionManager session.Manager, addrReceivers *[]addressReceiver, recorderManager recorderManager) { +func (w *Worker) startStatusTicking(cancelCtx context.Context) { const op = "worker.(Worker).startStatusTicking" r := rand.New(rand.NewSource(time.Now().UnixNano())) - // This function exists to desynchronize calls to controllers from - // workers, so we aren't always getting status updates at the exact same - // intervals, to ease the load on the DB. - getRandomInterval := func() time.Duration { - // 0 to 0.5 adjustment to the base - f := r.Float64() / 2 - // Half a chance to be faster, not slower - if r.Float32() > 0.5 { - f = -1 * f - } - return common.StatusInterval + time.Duration(f*float64(time.Second)) - } timer := time.NewTimer(0) for { @@ -67,8 +77,10 @@ func (w *Worker) startStatusTicking(cancelCtx context.Context, sessionManager se continue } - w.sendWorkerStatus(cancelCtx, sessionManager, addrReceivers, recorderManager) - timer.Reset(getRandomInterval()) + w.sendWorkerStatus(cancelCtx) + // Add a bit of jitter to the wait, so we aren't always getting, + // status updates at the exact same intervals, to ease the load on the DB. + timer.Reset(common.StatusInterval + getRandomInterval(r)) } } } @@ -115,120 +127,30 @@ func (w *Worker) WaitForNextSuccessfulStatusUpdate() error { return nil } -func (w *Worker) sendWorkerStatus(cancelCtx context.Context, sessionManager session.Manager, addressReceivers *[]addressReceiver, recorderManager recorderManager) { +func (w *Worker) sendWorkerStatus(cancelCtx context.Context) { const op = "worker.(Worker).sendWorkerStatus" - w.statusLock.Lock() - defer w.statusLock.Unlock() - - // Collect the different session ids that are being monitored by this worker - var monitoredSessionIds []string - - if recorderManager != nil { - recSessIds, err := recorderManager.SessionsManaged(cancelCtx) - if err != nil { - event.WriteError(cancelCtx, op, err, event.WithInfoMsg("error getting session ids from recorderManager")) - } else { - monitoredSessionIds = append(monitoredSessionIds, recSessIds...) - } - } - - // First send info as-is. We'll perform cleanup duties after we - // get cancel/job change info back. - var activeJobs []*pbs.JobStatus - - for _, sid := range monitoredSessionIds { - activeJobs = append(activeJobs, &pbs.JobStatus{ - Job: &pbs.Job{ - Type: pbs.JOBTYPE_JOBTYPE_MONITOR_SESSION, - JobInfo: &pbs.Job_MonitorSessionInfo{ - MonitorSessionInfo: &pbs.MonitorSessionJobInfo{ - SessionId: sid, - Status: pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE, - }, - }, - }, - }) - } - - // Range over known sessions and collect info - sessionManager.ForEachLocalSession(func(s session.Session) bool { - var jobInfo pbs.SessionJobInfo - status := s.GetStatus() - sessionId := s.GetId() - localConnections := s.GetLocalConnections() - connections := make([]*pbs.Connection, 0, len(localConnections)) - for k, v := range localConnections { - connections = append(connections, &pbs.Connection{ - ConnectionId: k, - Status: v.Status, - BytesUp: v.BytesUp(), - BytesDown: v.BytesDown(), - }) - } - jobInfo.SessionId = sessionId - activeJobs = append(activeJobs, &pbs.JobStatus{ - Job: &pbs.Job{ - Type: pbs.JOBTYPE_JOBTYPE_SESSION, - JobInfo: &pbs.Job_SessionInfo{ - SessionInfo: &pbs.SessionJobInfo{ - SessionId: sessionId, - Status: status, - Connections: connections, - }, - }, - }, - }) - return true - }) - - clientCon := w.GrpcClientConn.Load() - // Send status information - client := pbs.NewServerCoordinationServiceClient(clientCon) - var tags []*pb.TagPair - // If we're not going to request a tag update, no reason to have these - // marshaled on every status call. - if w.updateTags.Load() { - tags = w.tags.Load().([]*pb.TagPair) - } - statusCtx, statusCancel := context.WithTimeout(cancelCtx, time.Duration(w.statusCallTimeoutDuration.Load())) - defer statusCancel() + w.confLock.Lock() + defer w.confLock.Unlock() keyId := w.WorkerAuthCurrentKeyId.Load() switch { case w.conf.RawConfig.Worker.Name == "" && keyId == "": event.WriteError(cancelCtx, op, errors.New("worker name and keyId are both empty; at least one is needed to identify a worker"), event.WithInfoMsg("error making status request to controller")) + return } - var storageBucketCredentialStates map[string]*plugin.StorageBucketCredentialState - if w.RecordingStorage != nil { - storageBucketCredentialStates = w.RecordingStorage.GetStorageBucketCredentialStates() - // If the local storage state is unknown, and we have recording storage set, get the state from the recording storage - // and set it on the worker. This is done once to ensure that the worker has the correct state for the first status - // call. - if w.localStorageState.Load() == server.UnknownLocalStorageState { - w.localStorageState.Store(w.RecordingStorage.GetLocalStorageState(cancelCtx)) - } - } + // Send status information versionInfo := version.Get() - connectionState := w.downstreamConnManager.Connected() + // Send status information + clientCon := w.GrpcClientConn.Load() + client := pbs.NewServerCoordinationServiceClient(clientCon) + statusCtx, statusCancel := context.WithTimeout(cancelCtx, time.Duration(w.statusCallTimeoutDuration.Load())) + defer statusCancel() result, err := client.Status(statusCtx, &pbs.StatusRequest{ - Jobs: activeJobs, - WorkerStatus: &pb.ServerWorkerStatus{ - Name: w.conf.RawConfig.Worker.Name, - Description: w.conf.RawConfig.Worker.Description, - Address: w.conf.RawConfig.Worker.PublicAddr, - Tags: tags, - KeyId: keyId, - ReleaseVersion: versionInfo.FullVersionNumber(false), - OperationalState: w.operationalState.Load().(server.OperationalState).String(), - LocalStorageState: w.localStorageState.Load().(server.LocalStorageState).String(), - StorageBucketCredentialStates: storageBucketCredentialStates, - }, - ConnectedWorkerKeyIdentifiers: connectionState.AllKeyIds(), - ConnectedUnmappedWorkerKeyIdentifiers: connectionState.UnmappedKeyIds(), - ConnectedWorkerPublicIds: connectionState.WorkerIds(), - UpdateTags: w.updateTags.Load(), + KeyId: keyId, + WorkerId: w.LastStatusSuccess().WorkerId, + ReleaseVersion: versionInfo.FullVersionNumber(false), }) if err != nil { event.WriteError(cancelCtx, op, err, event.WithInfoMsg("error making status request to controller", "controller_address", clientCon.Target())) @@ -248,7 +170,7 @@ func (w *Worker) sendWorkerStatus(cancelCtx context.Context, sessionManager sess // Cancel connections if grace period has expired. These Connections will be closed in the // database on the next successful status report, or via the Controller’s dead Worker cleanup connections job. - sessionManager.ForEachLocalSession(func(s session.Session) bool { + w.sessionManager.ForEachLocalSession(func(s session.Session) bool { for _, connId := range s.CancelAllLocalConnections() { event.WriteSysEvent(cancelCtx, op, "terminated connection due to status grace period expiration", "session_id", s.GetId(), "connection_id", connId) } @@ -258,9 +180,9 @@ func (w *Worker) sendWorkerStatus(cancelCtx context.Context, sessionManager sess // In the case that the control plane has gone down and come up with different IPs, // append initial upstreams/ cluster addr to the resolver to try if w.GrpcClientConn.Load().GetState() == connectivity.TransientFailure { - lastStatus := w.lastStatusSuccess.Load().(*LastStatusInformation) - if lastStatus != nil && lastStatus.LastCalculatedUpstreams != nil { - addrs := lastStatus.LastCalculatedUpstreams + lastRouteInfo := w.lastRoutingInfoSuccess.Load().(*LastRoutingInfo) + if lastRouteInfo != nil && lastRouteInfo.LastCalculatedUpstreams != nil { + addrs := lastRouteInfo.LastCalculatedUpstreams if len(w.conf.RawConfig.Worker.InitialUpstreams) > 0 { addrs = append(addrs, w.conf.RawConfig.Worker.InitialUpstreams...) @@ -275,14 +197,14 @@ func (w *Worker) sendWorkerStatus(cancelCtx context.Context, sessionManager sess } addrs = strutil.RemoveDuplicates(addrs, false) - if strutil.EquivalentSlices(lastStatus.LastCalculatedUpstreams, addrs) { + if slices.Equal(lastRouteInfo.LastCalculatedUpstreams, addrs) { // Nothing to update return } - w.updateAddresses(cancelCtx, addrs, addressReceivers) - lastStatus.LastCalculatedUpstreams = addrs - w.lastStatusSuccess.Store(lastStatus) + w.updateAddresses(cancelCtx, addrs) + lastRouteInfo.LastCalculatedUpstreams = addrs + w.lastRoutingInfoSuccess.Store(lastRouteInfo) } } @@ -292,84 +214,11 @@ func (w *Worker) sendWorkerStatus(cancelCtx context.Context, sessionManager sess // Standard cleanup: Run through current jobs. Cancel connections // for any canceling session or any session that is expired. - w.cleanupConnections(cancelCtx, false, sessionManager) + w.cleanupConnections(cancelCtx, false) return } - w.updateTags.Store(false) - - if authorized := result.GetAuthorizedDownstreamWorkers(); authorized != nil { - connectionState.DisconnectMissingWorkers(authorized.GetWorkerPublicIds()) - connectionState.DisconnectMissingUnmappedKeyIds(authorized.GetUnmappedWorkerKeyIdentifiers()) - } else if authorized := result.GetAuthorizedWorkers(); authorized != nil { - connectionState.DisconnectAllMissingKeyIds(authorized.GetWorkerKeyIdentifiers()) - } - var addrs []string - // This may be empty if we are in a multiple hop scenario - if len(result.CalculatedUpstreams) > 0 { - addrs = make([]string, 0, len(result.CalculatedUpstreams)) - for _, v := range result.CalculatedUpstreams { - addrs = append(addrs, v.Address) - } - } else if checkHCPBUpstreams != nil && checkHCPBUpstreams(w) { - // This is a worker that is one hop away from managed workers, so attempt to get that list - hcpbWorkersCtx, hcpbWorkersCancel := context.WithTimeout(cancelCtx, time.Duration(w.statusCallTimeoutDuration.Load())) - defer hcpbWorkersCancel() - workersResp, err := client.ListHcpbWorkers(hcpbWorkersCtx, &pbs.ListHcpbWorkersRequest{}) - if err != nil { - event.WriteError(hcpbWorkersCtx, op, err, event.WithInfoMsg("error fetching managed worker information")) - } else { - addrs = make([]string, 0, len(workersResp.Workers)) - for _, v := range workersResp.Workers { - addrs = append(addrs, v.Address) - } - } - } - - w.updateAddresses(cancelCtx, addrs, addressReceivers) - - w.lastStatusSuccess.Store(&LastStatusInformation{StatusResponse: result, StatusTime: time.Now(), LastCalculatedUpstreams: addrs}) - - var nonActiveMonitoredSessionIds []string - - for _, request := range result.GetJobsRequests() { - switch request.GetRequestType() { - case pbs.CHANGETYPE_CHANGETYPE_UPDATE_STATE: - switch request.GetJob().GetType() { - case pbs.JOBTYPE_JOBTYPE_MONITOR_SESSION: - si := request.GetJob().GetMonitorSessionInfo() - if si != nil && si.Status != pbs.SESSIONSTATUS_SESSIONSTATUS_ACTIVE { - nonActiveMonitoredSessionIds = append(nonActiveMonitoredSessionIds, si.GetSessionId()) - } - case pbs.JOBTYPE_JOBTYPE_SESSION: - sessInfo := request.GetJob().GetSessionInfo() - sessionId := sessInfo.GetSessionId() - si := sessionManager.Get(sessionId) - if si == nil { - event.WriteError(cancelCtx, op, errors.New("session change requested but could not find local information for it"), event.WithInfo("session_id", sessionId)) - continue - } - si.ApplyLocalStatus(sessInfo.GetStatus()) - - // Update connection state if there are any connections in - // the request. - for _, conn := range sessInfo.GetConnections() { - if err := si.ApplyLocalConnectionStatus(conn.GetConnectionId(), conn.GetStatus()); err != nil { - event.WriteError(cancelCtx, op, err, event.WithInfo("connection_id", conn.GetConnectionId())) - } - } - } - } - } - if recorderManager != nil { - if err := recorderManager.ReauthorizeAllExcept(cancelCtx, nonActiveMonitoredSessionIds); err != nil { - event.WriteError(cancelCtx, op, err) - } - } - - // Standard cleanup: Run through current jobs. Cancel connections - // for any canceling session or any session that is expired. - w.cleanupConnections(cancelCtx, false, sessionManager) + w.lastStatusSuccess.Store(&LastStatusInformation{StatusResponse: result, StatusTime: time.Now()}) // If we have post hooks for after the first status check, run them now if w.everAuthenticated.CompareAndSwap(authenticationStatusFirstAuthentication, authenticationStatusFirstStatusRpcSuccessful) { @@ -397,111 +246,6 @@ func (w *Worker) sendWorkerStatus(cancelCtx context.Context, sessionManager sess } } -// Update address receivers and dialing listeners with new addrs -func (w *Worker) updateAddresses(cancelCtx context.Context, addrs []string, addressReceivers *[]addressReceiver) { - const op = "worker.(Worker).updateAddrs" - - if len(addrs) > 0 { - lastStatus := w.lastStatusSuccess.Load().(*LastStatusInformation) - // Compare upstreams; update resolver if there is a difference, and emit an event with old and new addresses - if lastStatus != nil && !strutil.EquivalentSlices(lastStatus.LastCalculatedUpstreams, addrs) { - upstreamsMessage := fmt.Sprintf("Upstreams has changed; old upstreams were: %s, new upstreams are: %s", lastStatus.LastCalculatedUpstreams, addrs) - event.WriteSysEvent(cancelCtx, op, upstreamsMessage) - for _, as := range *addressReceivers { - as.SetAddresses(addrs) - } - } else if lastStatus == nil { - for _, as := range *addressReceivers { - as.SetAddresses(addrs) - } - event.WriteSysEvent(cancelCtx, op, fmt.Sprintf("Upstreams after first status set to: %s", addrs)) - } - } - - // regardless of whether or not it's a new address, we need to set - // them for secondary connections - for _, as := range *addressReceivers { - switch { - case as.Type() == secondaryConnectionReceiverType: - tmpAddrs := make([]string, len(addrs)) - copy(tmpAddrs, addrs) - if len(tmpAddrs) == 0 { - tmpAddrs = append(tmpAddrs, w.conf.RawConfig.Worker.InitialUpstreams...) - } - as.SetAddresses(tmpAddrs) - } - } -} - -// cleanupConnections walks all sessions and shuts down all proxy connections. -// After the local connections are terminated, they are requested to be marked -// close on the controller. -// Additionally, sessions without connections are cleaned up from the -// local worker's state. -// -// Use ignoreSessionState to ignore the state checks, this closes all -// connections, regardless of whether or not the session is still active. -func (w *Worker) cleanupConnections(cancelCtx context.Context, ignoreSessionState bool, sessionManager session.Manager) { - const op = "worker.(Worker).cleanupConnections" - closeInfo := make(map[string]*session.ConnectionCloseData) - cleanSessionIds := make([]string, 0) - sessionManager.ForEachLocalSession(func(s session.Session) bool { - switch { - case ignoreSessionState, - s.GetStatus() == pbs.SESSIONSTATUS_SESSIONSTATUS_CANCELING, - s.GetStatus() == pbs.SESSIONSTATUS_SESSIONSTATUS_TERMINATED, - time.Until(s.GetExpiration()) < 0: - // Cancel connections without regard to individual connection - // state. - closedIds := s.CancelAllLocalConnections() - localConns := s.GetLocalConnections() - for _, connId := range closedIds { - var bytesUp, bytesDown int64 - connInfo, ok := localConns[connId] - if ok { - bytesUp = connInfo.BytesUp() - bytesDown = connInfo.BytesDown() - } - closeInfo[connId] = &session.ConnectionCloseData{ - SessionId: s.GetId(), - BytesUp: bytesUp, - BytesDown: bytesDown, - } - event.WriteSysEvent(cancelCtx, op, "terminated connection due to cancellation or expiration", "session_id", s.GetId(), "connection_id", connId) - } - - // If the session is no longer valid and all connections - // are marked closed, clean up the session. - if len(closedIds) == 0 { - cleanSessionIds = append(cleanSessionIds, s.GetId()) - } - - default: - // Cancel connections *with* regard to individual connection - // state (ie: only ones that the controller has requested be - // terminated). - for _, connId := range s.CancelOpenLocalConnections() { - closeInfo[connId] = &session.ConnectionCloseData{SessionId: s.GetId()} - event.WriteSysEvent(cancelCtx, op, "terminated connection due to cancellation or expiration", "session_id", s.GetId(), "connection_id", connId) - } - } - - return true - }) - - // Note that we won't clean these from the info map until the - // next time we run this function - if len(closeInfo) > 0 { - // Call out to a helper to send the connection close requests to the - // controller, and set the close time. This functionality is shared with - // post-close functionality in the proxy handler. - _ = sessionManager.RequestCloseConnections(cancelCtx, closeInfo) - } - // Forget sessions where the session is expired/canceled and all - // connections are canceled and marked closed - sessionManager.DeleteLocalSession(cleanSessionIds) -} - func (w *Worker) lastSuccessfulStatusTime() time.Time { lastStatus := w.LastStatusSuccess() if lastStatus == nil { diff --git a/internal/daemon/worker/worker.go b/internal/daemon/worker/worker.go index 762f7fbd3e..114dbebe05 100644 --- a/internal/daemon/worker/worker.go +++ b/internal/daemon/worker/worker.go @@ -11,6 +11,7 @@ import ( "crypto/tls" "crypto/x509" "fmt" + "slices" "strconv" "strings" "sync" @@ -40,7 +41,6 @@ import ( "github.com/hashicorp/go-secure-stdlib/base62" "github.com/hashicorp/go-secure-stdlib/mlock" "github.com/hashicorp/go-secure-stdlib/pluginutil/v2" - "github.com/hashicorp/go-secure-stdlib/strutil" "github.com/hashicorp/nodeenrollment" nodeenet "github.com/hashicorp/nodeenrollment/net" nodeefile "github.com/hashicorp/nodeenrollment/storage/file" @@ -129,7 +129,10 @@ const ( ) type Worker struct { - conf *Config + conf *Config + // confLock is used to protect the conf field. + confLock sync.Mutex + logger hclog.Logger baseContext context.Context @@ -151,10 +154,12 @@ type Worker struct { recorderManager recorderManager - everAuthenticated *ua.Uint32 - lastStatusSuccess *atomic.Value - workerStartTime time.Time - operationalState *atomic.Value + everAuthenticated *ua.Uint32 + lastStatusSuccess *atomic.Value + lastJobInfoSuccess *atomic.Value + lastRoutingInfoSuccess *atomic.Value + workerStartTime time.Time + operationalState *atomic.Value // localStorageState is the current state of the local storage. // The local storage state is updated based on the local storage events. localStorageState *atomic.Value @@ -196,6 +201,9 @@ type Worker struct { // because they are casted to time.Duration. successfulStatusGracePeriod *atomic.Int64 statusCallTimeoutDuration *atomic.Int64 + jobInfoCallTimeoutDuration *atomic.Int64 + routingInfoCallTimeoutDuration *atomic.Int64 + statisticsCallTimeoutDuration *atomic.Int64 getDownstreamWorkersTimeoutDuration *atomic.Int64 // AuthRotationNextRotation is useful in tests to understand how long to @@ -207,8 +215,6 @@ type Worker struct { TestOverrideX509VerifyCertPool *x509.CertPool TestOverrideAuthRotationPeriod time.Duration - statusLock sync.Mutex - downstreamConnManager *cluster.DownstreamManager HostServiceServer wpbs.HostServiceServer @@ -230,6 +236,8 @@ func New(ctx context.Context, conf *Config) (*Worker, error) { started: ua.NewBool(false), everAuthenticated: ua.NewUint32(authenticationStatusNeverAuthenticated), lastStatusSuccess: new(atomic.Value), + lastJobInfoSuccess: new(atomic.Value), + lastRoutingInfoSuccess: new(atomic.Value), controllerMultihopConn: new(atomic.Value), // controllerUpstreamMsgConn: new(atomic.Value), tags: new(atomic.Value), @@ -241,6 +249,9 @@ func New(ctx context.Context, conf *Config) (*Worker, error) { localStorageState: new(atomic.Value), successfulStatusGracePeriod: new(atomic.Int64), statusCallTimeoutDuration: new(atomic.Int64), + jobInfoCallTimeoutDuration: new(atomic.Int64), + routingInfoCallTimeoutDuration: new(atomic.Int64), + statisticsCallTimeoutDuration: new(atomic.Int64), getDownstreamWorkersTimeoutDuration: new(atomic.Int64), upstreamConnectionState: new(atomic.Value), downstreamWorkers: new(atomic.Pointer[downstreamersContainer]), @@ -249,6 +260,8 @@ func New(ctx context.Context, conf *Config) (*Worker, error) { w.operationalState.Store(server.UnknownOperationalState) w.localStorageState.Store(server.UnknownLocalStorageState) w.lastStatusSuccess.Store((*LastStatusInformation)(nil)) + w.lastJobInfoSuccess.Store((*LastJobInfo)(nil)) + w.lastRoutingInfoSuccess.Store((*LastRoutingInfo)(nil)) scheme := strconv.FormatInt(time.Now().UnixNano(), 36) controllerResolver := manual.NewBuilderWithScheme(scheme) w.addressReceivers = []addressReceiver{&grpcResolverReceiver{controllerResolver}} @@ -373,8 +386,15 @@ func New(ctx context.Context, conf *Config) (*Worker, error) { switch conf.RawConfig.Worker.StatusCallTimeoutDuration { case 0: w.statusCallTimeoutDuration.Store(int64(common.DefaultStatusTimeout)) + w.jobInfoCallTimeoutDuration.Store(int64(common.DefaultJobInfoTimeout)) + w.routingInfoCallTimeoutDuration.Store(int64(common.DefaultRoutingInfoTimeout)) + w.statisticsCallTimeoutDuration.Store(int64(common.DefaultStatisticsTimeout)) default: w.statusCallTimeoutDuration.Store(int64(conf.RawConfig.Worker.StatusCallTimeoutDuration)) + // Use the configured status timeout for the other status-like calls too + w.jobInfoCallTimeoutDuration.Store(int64(conf.RawConfig.Worker.StatusCallTimeoutDuration)) + w.routingInfoCallTimeoutDuration.Store(int64(conf.RawConfig.Worker.StatusCallTimeoutDuration)) + w.statisticsCallTimeoutDuration.Store(int64(conf.RawConfig.Worker.StatusCallTimeoutDuration)) } switch conf.RawConfig.Worker.GetDownstreamWorkersTimeoutDuration { case 0: @@ -442,25 +462,6 @@ func (w *Worker) Reload(ctx context.Context, newConf *config.Config) { w.parseAndStoreTags(newConf.Worker.Tags) - if !strutil.EquivalentSlices(newConf.Worker.InitialUpstreams, w.conf.RawConfig.Worker.InitialUpstreams) { - w.statusLock.Lock() - defer w.statusLock.Unlock() - - upstreamsMessage := fmt.Sprintf( - "Initial Upstreams has changed; old upstreams were: %s, new upstreams are: %s", - w.conf.RawConfig.Worker.InitialUpstreams, - newConf.Worker.InitialUpstreams, - ) - event.WriteSysEvent(ctx, op, upstreamsMessage) - w.conf.RawConfig.Worker.InitialUpstreams = newConf.Worker.InitialUpstreams - - for _, ar := range w.addressReceivers { - ar.SetAddresses(w.conf.RawConfig.Worker.InitialUpstreams) - // set InitialAddresses in case the worker has not successfully dialed yet - ar.InitialAddresses(w.conf.RawConfig.Worker.InitialUpstreams) - } - } - switch newConf.Worker.SuccessfulStatusGracePeriodDuration { case 0: w.successfulStatusGracePeriod.Store(int64(server.DefaultLiveness)) @@ -481,6 +482,24 @@ func (w *Worker) Reload(ctx context.Context, newConf *config.Config) { } // See comment about this in worker.go session.CloseCallTimeout.Store(w.successfulStatusGracePeriod.Load()) + + w.confLock.Lock() + defer w.confLock.Unlock() + if !slices.Equal(newConf.Worker.InitialUpstreams, w.conf.RawConfig.Worker.InitialUpstreams) { + upstreamsMessage := fmt.Sprintf( + "Initial Upstreams has changed; old upstreams were: %s, new upstreams are: %s", + w.conf.RawConfig.Worker.InitialUpstreams, + newConf.Worker.InitialUpstreams, + ) + event.WriteSysEvent(ctx, op, upstreamsMessage) + w.conf.RawConfig.Worker.InitialUpstreams = newConf.Worker.InitialUpstreams + + for _, ar := range w.addressReceivers { + ar.SetAddresses(w.conf.RawConfig.Worker.InitialUpstreams) + // set InitialAddresses in case the worker has not successfully dialed yet + ar.InitialAddresses(w.conf.RawConfig.Worker.InitialUpstreams) + } + } } func (w *Worker) Start() error { @@ -611,9 +630,6 @@ func (w *Worker) Start() error { return fmt.Errorf("error marshaling worker auth fetch credentials request: %w", err) } w.WorkerAuthRegistrationRequest = base58.FastBase58Encoding(reqBytes) - if err != nil { - return fmt.Errorf("error encoding worker auth registration request: %w", err) - } currentKeyId, err := nodeenrollment.KeyIdFromPkix(nodeCreds.CertificatePublicKeyPkix) if err != nil { return fmt.Errorf("error deriving worker auth key id: %w", err) @@ -655,10 +671,10 @@ func (w *Worker) Start() error { // Rather than deal with some of the potential error conditions for Add on // the waitgroup vs. Done (in case a function exits immediately), we will // always start rotation and simply exit early if we're using KMS - w.tickerWg.Add(2) + w.tickerWg.Add(4) go func() { defer w.tickerWg.Done() - w.startStatusTicking(w.baseContext, w.sessionManager, &w.addressReceivers, w.recorderManager) + w.startStatusTicking(w.baseContext) }() go func() { defer w.tickerWg.Done() @@ -764,7 +780,7 @@ func (w *Worker) Shutdown() error { } // Shut down all connections. - w.cleanupConnections(w.baseContext, true, w.sessionManager) + w.cleanupConnections(w.baseContext, true) // Wait for next status request to succeed. Don't wait too long; time it out // at our default liveness value, which is also our default status grace diff --git a/internal/daemon/worker/worker_proxy_service.go b/internal/daemon/worker/worker_proxy_service.go index 5bd351b845..9a8dabad60 100644 --- a/internal/daemon/worker/worker_proxy_service.go +++ b/internal/daemon/worker/worker_proxy_service.go @@ -32,14 +32,19 @@ func NewWorkerProxyServiceServer( func (ws *workerProxyServiceServer) Status(ctx context.Context, req *pbs.StatusRequest) (*pbs.StatusResponse, error) { resp, err := pbs.NewServerCoordinationServiceClient(ws.cc).Status(ctx, req) + return resp, err +} - if resp != nil { - // We don't currently support distributing new addreses to workers - // multiple hops away so ensure they're stripped out - resp.CalculatedUpstreams = nil - } +func (ws *workerProxyServiceServer) JobInfo(ctx context.Context, req *pbs.JobInfoRequest) (*pbs.JobInfoResponse, error) { + return pbs.NewServerCoordinationServiceClient(ws.cc).JobInfo(ctx, req) +} - return resp, err +func (ws *workerProxyServiceServer) RoutingInfo(ctx context.Context, req *pbs.RoutingInfoRequest) (*pbs.RoutingInfoResponse, error) { + return pbs.NewServerCoordinationServiceClient(ws.cc).RoutingInfo(ctx, req) +} + +func (ws *workerProxyServiceServer) Statistics(ctx context.Context, req *pbs.StatisticsRequest) (*pbs.StatisticsResponse, error) { + return pbs.NewServerCoordinationServiceClient(ws.cc).Statistics(ctx, req) } func (ws *workerProxyServiceServer) ListHcpbWorkers(ctx context.Context, req *pbs.ListHcpbWorkersRequest) (*pbs.ListHcpbWorkersResponse, error) { diff --git a/internal/daemon/worker/worker_test.go b/internal/daemon/worker/worker_test.go index 387d91aa63..a16638702f 100644 --- a/internal/daemon/worker/worker_test.go +++ b/internal/daemon/worker/worker_test.go @@ -371,7 +371,7 @@ func Test_Worker_getSessionTls(t *testing.T) { conf.RawConfig = &config.Config{SharedConfig: &configutil.SharedConfig{DisableMlock: true}} w, err := New(context.Background(), conf) require.NoError(t, err) - w.lastStatusSuccess.Store(&LastStatusInformation{StatusResponse: &services.StatusResponse{}, StatusTime: time.Now(), LastCalculatedUpstreams: nil}) + w.lastStatusSuccess.Store(&LastStatusInformation{StatusResponse: &services.StatusResponse{}, StatusTime: time.Now()}) w.baseContext = context.Background() t.Run("success", func(t *testing.T) { diff --git a/internal/gen/controller/servers/servers.pb.go b/internal/gen/controller/servers/servers.pb.go index c9c6a7f68f..6a11ef5b33 100644 --- a/internal/gen/controller/servers/servers.pb.go +++ b/internal/gen/controller/servers/servers.pb.go @@ -80,7 +80,10 @@ func (x *TagPair) GetValue() string { return "" } -// ServerWorkerStatus is the new message used in place of Server to relay status request info. +// ServerWorkerStatus is a legacy message used by the old expensive Status RPC. +// It can be removed after 0.20.0. +// +// Deprecated: Marked as deprecated in controller/servers/v1/servers.proto. type ServerWorkerStatus struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -230,7 +233,7 @@ var file_controller_servers_v1_servers_proto_rawDesc = []byte{ 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x31, 0x0a, 0x07, 0x54, 0x61, 0x67, 0x50, 0x61, 0x69, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xe9, 0x04, 0x0a, 0x12, 0x53, 0x65, 0x72, 0x76, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xed, 0x04, 0x0a, 0x12, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, @@ -269,12 +272,12 @@ var file_controller_servers_v1_servers_proto_rawDesc = []byte{ 0x27, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x42, 0x47, 0x5a, 0x45, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, - 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, - 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x02, 0x38, 0x01, 0x3a, 0x02, 0x18, 0x01, 0x42, 0x47, 0x5a, 0x45, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, + 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/internal/gen/controller/servers/services/server_coordination_service.pb.go b/internal/gen/controller/servers/services/server_coordination_service.pb.go index 55856a81b8..483603217e 100644 --- a/internal/gen/controller/servers/services/server_coordination_service.pb.go +++ b/internal/gen/controller/servers/services/server_coordination_service.pb.go @@ -11,6 +11,7 @@ package services import ( servers "github.com/hashicorp/boundary/internal/gen/controller/servers" + plugin "github.com/hashicorp/boundary/sdk/pbs/plugin" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -330,8 +331,10 @@ type Connection struct { ConnectionId string `protobuf:"bytes,1,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` Status CONNECTIONSTATUS `protobuf:"varint,2,opt,name=status,proto3,enum=controller.servers.services.v1.CONNECTIONSTATUS" json:"status,omitempty"` - BytesUp int64 `protobuf:"varint,3,opt,name=bytes_up,json=bytesUp,proto3" json:"bytes_up,omitempty" class:"public"` // @gotags: `class:"public"` - BytesDown int64 `protobuf:"varint,4,opt,name=bytes_down,json=bytesDown,proto3" json:"bytes_down,omitempty" class:"public"` // @gotags: `class:"public"` + // Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. + BytesUp int64 `protobuf:"varint,3,opt,name=bytes_up,json=bytesUp,proto3" json:"bytes_up,omitempty" class:"public"` // @gotags: `class:"public"` + // Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. + BytesDown int64 `protobuf:"varint,4,opt,name=bytes_down,json=bytesDown,proto3" json:"bytes_down,omitempty" class:"public"` // @gotags: `class:"public"` } func (x *Connection) Reset() { @@ -380,6 +383,7 @@ func (x *Connection) GetStatus() CONNECTIONSTATUS { return CONNECTIONSTATUS_CONNECTIONSTATUS_UNSPECIFIED } +// Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. func (x *Connection) GetBytesUp() int64 { if x != nil { return x.BytesUp @@ -387,6 +391,7 @@ func (x *Connection) GetBytesUp() int64 { return 0 } +// Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. func (x *Connection) GetBytesDown() int64 { if x != nil { return x.BytesDown @@ -724,44 +729,176 @@ func (x *UpstreamServer) GetAddress() string { return "" } +// ConnectionStatistics contains statistics about a connection. +type ConnectionStatistics struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConnectionId string `protobuf:"bytes,1,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + BytesUp int64 `protobuf:"varint,2,opt,name=bytes_up,json=bytesUp,proto3" json:"bytes_up,omitempty" class:"public"` // @gotags: `class:"public"` + BytesDown int64 `protobuf:"varint,3,opt,name=bytes_down,json=bytesDown,proto3" json:"bytes_down,omitempty" class:"public"` // @gotags: `class:"public"` +} + +func (x *ConnectionStatistics) Reset() { + *x = ConnectionStatistics{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ConnectionStatistics) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ConnectionStatistics) ProtoMessage() {} + +func (x *ConnectionStatistics) ProtoReflect() protoreflect.Message { + mi := &file_controller_servers_services_v1_server_coordination_service_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 ConnectionStatistics.ProtoReflect.Descriptor instead. +func (*ConnectionStatistics) Descriptor() ([]byte, []int) { + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{6} +} + +func (x *ConnectionStatistics) GetConnectionId() string { + if x != nil { + return x.ConnectionId + } + return "" +} + +func (x *ConnectionStatistics) GetBytesUp() int64 { + if x != nil { + return x.BytesUp + } + return 0 +} + +func (x *ConnectionStatistics) GetBytesDown() int64 { + if x != nil { + return x.BytesDown + } + return 0 +} + +// SessionStatistics contains statistics about a session and its connections. +type SessionStatistics struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SessionId string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + Connections []*ConnectionStatistics `protobuf:"bytes,2,rep,name=connections,proto3" json:"connections,omitempty"` +} + +func (x *SessionStatistics) Reset() { + *x = SessionStatistics{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SessionStatistics) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SessionStatistics) ProtoMessage() {} + +func (x *SessionStatistics) ProtoReflect() protoreflect.Message { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[7] + 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 SessionStatistics.ProtoReflect.Descriptor instead. +func (*SessionStatistics) Descriptor() ([]byte, []int) { + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{7} +} + +func (x *SessionStatistics) GetSessionId() string { + if x != nil { + return x.SessionId + } + return "" +} + +func (x *SessionStatistics) GetConnections() []*ConnectionStatistics { + if x != nil { + return x.Connections + } + return nil +} + type StatusRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Jobs which this worker wants to report the status. + // Jobs which this worker wants to report the status of. Can be removed after 0.20.0. + // + // Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. Jobs []*JobStatus `protobuf:"bytes,20,rep,name=jobs,proto3" json:"jobs,omitempty"` // Whether to update tags from the Server block on this RPC. We only need to // do this at startup or (at some point) SIGHUP, so specifying when it's // changed allows us to avoid constant database operations for something that - // won't change very often, if ever. + // won't change very often, if ever. Can be removed after 0.20.0. + // + // Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. UpdateTags bool `protobuf:"varint,30,opt,name=update_tags,json=updateTags,proto3" json:"update_tags,omitempty"` - // Replaces the old worker field: // The worker info. We could use information from the TLS connection but this // is easier and going the other route doesn't provide much benefit -- if you // get access to the key and spoof the connection, you're already compromised. - WorkerStatus *servers.ServerWorkerStatus `protobuf:"bytes,40,opt,name=worker_status,json=workerStatus,proto3" json:"worker_status,omitempty"` - // The worker key identifiers presented by all downstreams connected to this - // worker. - // Deprecated. Should be removed in 0.15.0 at which time - // connected_unmapped_worker_key_identifiers should be used exclusively. + // Can be removed after 0.20.0. // // Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. - ConnectedWorkerKeyIdentifiers []string `protobuf:"bytes,50,rep,name=connected_worker_key_identifiers,json=connectedWorkerKeyIdentifiers,proto3" json:"connected_worker_key_identifiers,omitempty"` + WorkerStatus *servers.ServerWorkerStatus `protobuf:"bytes,40,opt,name=worker_status,json=workerStatus,proto3" json:"worker_status,omitempty"` // The worker key identifiers for downstream workers for which there - // is not a known worker id mapping for them yet. + // is not a known worker id mapping for them yet. Can be removed after 0.20.0. + // + // Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. ConnectedUnmappedWorkerKeyIdentifiers []string `protobuf:"bytes,51,rep,name=connected_unmapped_worker_key_identifiers,json=connectedUnmappedWorkerKeyIdentifiers,proto3" json:"connected_unmapped_worker_key_identifiers,omitempty"` // The worker public ids of all downstreams connected to this worker if known. // While there may be workers with key ids in the connected_worker_key_identifiers // list and their public ids in this list, once the requesting worker is aware - // of the association, it should only populate this field. + // of the association, it should only populate this field. Can be removed after 0.20.0. + // + // Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. ConnectedWorkerPublicIds []string `protobuf:"bytes,55,rep,name=connected_worker_public_ids,json=connectedWorkerPublicIds,proto3" json:"connected_worker_public_ids,omitempty"` + // The key id for this worker, set on the first status. + KeyId string `protobuf:"bytes,60,opt,name=key_id,json=keyId,proto3" json:"key_id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public"` eventstream:"observation"` + // The ID of the worker which made the request. It will be used to identify the worker on + // subsequent status updates. + WorkerId string `protobuf:"bytes,70,opt,name=worker_id,json=workerId,proto3" json:"worker_id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + // The version of Boundary the worker binary is running. + ReleaseVersion string `protobuf:"bytes,80,opt,name=release_version,json=releaseVersion,proto3" json:"release_version,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + // The state of the worker, to indicate if the worker is active or in shutdown. + OperationalState string `protobuf:"bytes,90,opt,name=operational_state,json=operationalState,proto3" json:"operational_state,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` } func (x *StatusRequest) Reset() { *x = StatusRequest{} if protoimpl.UnsafeEnabled { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[6] + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -774,7 +911,7 @@ func (x *StatusRequest) String() string { func (*StatusRequest) ProtoMessage() {} func (x *StatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[6] + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -787,9 +924,10 @@ func (x *StatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusRequest.ProtoReflect.Descriptor instead. func (*StatusRequest) Descriptor() ([]byte, []int) { - return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{6} + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{8} } +// Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. func (x *StatusRequest) GetJobs() []*JobStatus { if x != nil { return x.Jobs @@ -797,6 +935,7 @@ func (x *StatusRequest) GetJobs() []*JobStatus { return nil } +// Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. func (x *StatusRequest) GetUpdateTags() bool { if x != nil { return x.UpdateTags @@ -804,6 +943,7 @@ func (x *StatusRequest) GetUpdateTags() bool { return false } +// Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. func (x *StatusRequest) GetWorkerStatus() *servers.ServerWorkerStatus { if x != nil { return x.WorkerStatus @@ -812,13 +952,6 @@ func (x *StatusRequest) GetWorkerStatus() *servers.ServerWorkerStatus { } // Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. -func (x *StatusRequest) GetConnectedWorkerKeyIdentifiers() []string { - if x != nil { - return x.ConnectedWorkerKeyIdentifiers - } - return nil -} - func (x *StatusRequest) GetConnectedUnmappedWorkerKeyIdentifiers() []string { if x != nil { return x.ConnectedUnmappedWorkerKeyIdentifiers @@ -826,6 +959,7 @@ func (x *StatusRequest) GetConnectedUnmappedWorkerKeyIdentifiers() []string { return nil } +// Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. func (x *StatusRequest) GetConnectedWorkerPublicIds() []string { if x != nil { return x.ConnectedWorkerPublicIds @@ -833,6 +967,34 @@ func (x *StatusRequest) GetConnectedWorkerPublicIds() []string { return nil } +func (x *StatusRequest) GetKeyId() string { + if x != nil { + return x.KeyId + } + return "" +} + +func (x *StatusRequest) GetWorkerId() string { + if x != nil { + return x.WorkerId + } + return "" +} + +func (x *StatusRequest) GetReleaseVersion() string { + if x != nil { + return x.ReleaseVersion + } + return "" +} + +func (x *StatusRequest) GetOperationalState() string { + if x != nil { + return x.OperationalState + } + return "" +} + type JobChangeRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -845,7 +1007,7 @@ type JobChangeRequest struct { func (x *JobChangeRequest) Reset() { *x = JobChangeRequest{} if protoimpl.UnsafeEnabled { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[7] + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -858,7 +1020,7 @@ func (x *JobChangeRequest) String() string { func (*JobChangeRequest) ProtoMessage() {} func (x *JobChangeRequest) ProtoReflect() protoreflect.Message { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[7] + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -871,7 +1033,7 @@ func (x *JobChangeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use JobChangeRequest.ProtoReflect.Descriptor instead. func (*JobChangeRequest) Descriptor() ([]byte, []int) { - return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{7} + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{9} } func (x *JobChangeRequest) GetJob() *Job { @@ -888,58 +1050,6 @@ func (x *JobChangeRequest) GetRequestType() CHANGETYPE { return CHANGETYPE_CHANGETYPE_UNSPECIFIED } -// Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. -type AuthorizedWorkerList struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // the key id of authorized workers - // - // Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. - WorkerKeyIdentifiers []string `protobuf:"bytes,1,rep,name=worker_key_identifiers,json=workerKeyIdentifiers,proto3" json:"worker_key_identifiers,omitempty"` -} - -func (x *AuthorizedWorkerList) Reset() { - *x = AuthorizedWorkerList{} - if protoimpl.UnsafeEnabled { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AuthorizedWorkerList) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AuthorizedWorkerList) ProtoMessage() {} - -func (x *AuthorizedWorkerList) ProtoReflect() protoreflect.Message { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[8] - 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 AuthorizedWorkerList.ProtoReflect.Descriptor instead. -func (*AuthorizedWorkerList) Descriptor() ([]byte, []int) { - return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{8} -} - -// Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. -func (x *AuthorizedWorkerList) GetWorkerKeyIdentifiers() []string { - if x != nil { - return x.WorkerKeyIdentifiers - } - return nil -} - type AuthorizedDownstreamWorkerList struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -956,7 +1066,7 @@ type AuthorizedDownstreamWorkerList struct { func (x *AuthorizedDownstreamWorkerList) Reset() { *x = AuthorizedDownstreamWorkerList{} if protoimpl.UnsafeEnabled { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[9] + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -969,7 +1079,7 @@ func (x *AuthorizedDownstreamWorkerList) String() string { func (*AuthorizedDownstreamWorkerList) ProtoMessage() {} func (x *AuthorizedDownstreamWorkerList) ProtoReflect() protoreflect.Message { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[9] + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -982,7 +1092,7 @@ func (x *AuthorizedDownstreamWorkerList) ProtoReflect() protoreflect.Message { // Deprecated: Use AuthorizedDownstreamWorkerList.ProtoReflect.Descriptor instead. func (*AuthorizedDownstreamWorkerList) Descriptor() ([]byte, []int) { - return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{9} + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{10} } func (x *AuthorizedDownstreamWorkerList) GetUnmappedWorkerKeyIdentifiers() []string { @@ -1005,32 +1115,30 @@ type StatusResponse struct { unknownFields protoimpl.UnknownFields // List of jobs and the expected state changes. For example, this will - // include jobs witch change type of canceled for jobs which are active on a - // worker but should be canceled. This could also contain a request to start a - // job such as a worker -> worker proxy for establishing a session through an - // enclave. + // include jobs which change type of canceled for jobs which are active on a + // worker but should be canceled. Can be removed after 0.20.0. + // + // Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. JobsRequests []*JobChangeRequest `protobuf:"bytes,20,rep,name=jobs_requests,json=jobsRequests,proto3" json:"jobs_requests,omitempty"` // UpstreamServer currently returns the controller address in the StatusResponse. + // Can be removed after 0.20.0. + // + // Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. CalculatedUpstreams []*UpstreamServer `protobuf:"bytes,30,rep,name=calculated_upstreams,json=calculatedUpstreams,proto3" json:"calculated_upstreams,omitempty"` - // The ID of the worker which made the request. The worker can send this value in subsequent requests so the - // controller does not need to do a database lookup for the id using the name field. + // The ID of the worker which made the request. After the initial status request, + // the worker will use this to identify itself. WorkerId string `protobuf:"bytes,40,opt,name=worker_id,json=workerId,proto3" json:"worker_id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` - // Of the worker key identifiers provided in the request, these are the ones - // which are authorized to remain connected. - // This is deprecated. Use authorized_downstream_workers instead. This - // should be removed in version 0.15.0. + // Of the downstream workers in the request, these are the ones + // which are authorized to remain connected. Can be removed after 0.20.0. // // Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. - AuthorizedWorkers *AuthorizedWorkerList `protobuf:"bytes,50,opt,name=authorized_workers,json=authorizedWorkers,proto3" json:"authorized_workers,omitempty"` - // Of the downstream workers in the request, these are the ones - // which are authorized to remain connected. AuthorizedDownstreamWorkers *AuthorizedDownstreamWorkerList `protobuf:"bytes,51,opt,name=authorized_downstream_workers,json=authorizedDownstreamWorkers,proto3" json:"authorized_downstream_workers,omitempty"` } func (x *StatusResponse) Reset() { *x = StatusResponse{} if protoimpl.UnsafeEnabled { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[10] + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1043,7 +1151,7 @@ func (x *StatusResponse) String() string { func (*StatusResponse) ProtoMessage() {} func (x *StatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[10] + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1056,9 +1164,10 @@ func (x *StatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusResponse.ProtoReflect.Descriptor instead. func (*StatusResponse) Descriptor() ([]byte, []int) { - return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{10} + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{11} } +// Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. func (x *StatusResponse) GetJobsRequests() []*JobChangeRequest { if x != nil { return x.JobsRequests @@ -1066,6 +1175,7 @@ func (x *StatusResponse) GetJobsRequests() []*JobChangeRequest { return nil } +// Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. func (x *StatusResponse) GetCalculatedUpstreams() []*UpstreamServer { if x != nil { return x.CalculatedUpstreams @@ -1081,13 +1191,6 @@ func (x *StatusResponse) GetWorkerId() string { } // Deprecated: Marked as deprecated in controller/servers/services/v1/server_coordination_service.proto. -func (x *StatusResponse) GetAuthorizedWorkers() *AuthorizedWorkerList { - if x != nil { - return x.AuthorizedWorkers - } - return nil -} - func (x *StatusResponse) GetAuthorizedDownstreamWorkers() *AuthorizedDownstreamWorkerList { if x != nil { return x.AuthorizedDownstreamWorkers @@ -1110,7 +1213,7 @@ type WorkerInfo struct { func (x *WorkerInfo) Reset() { *x = WorkerInfo{} if protoimpl.UnsafeEnabled { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[11] + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1123,7 +1226,7 @@ func (x *WorkerInfo) String() string { func (*WorkerInfo) ProtoMessage() {} func (x *WorkerInfo) ProtoReflect() protoreflect.Message { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[11] + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1136,7 +1239,7 @@ func (x *WorkerInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerInfo.ProtoReflect.Descriptor instead. func (*WorkerInfo) Descriptor() ([]byte, []int) { - return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{11} + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{12} } func (x *WorkerInfo) GetId() string { @@ -1163,7 +1266,7 @@ type ListHcpbWorkersRequest struct { func (x *ListHcpbWorkersRequest) Reset() { *x = ListHcpbWorkersRequest{} if protoimpl.UnsafeEnabled { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[12] + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1176,7 +1279,7 @@ func (x *ListHcpbWorkersRequest) String() string { func (*ListHcpbWorkersRequest) ProtoMessage() {} func (x *ListHcpbWorkersRequest) ProtoReflect() protoreflect.Message { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[12] + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1189,7 +1292,7 @@ func (x *ListHcpbWorkersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListHcpbWorkersRequest.ProtoReflect.Descriptor instead. func (*ListHcpbWorkersRequest) Descriptor() ([]byte, []int) { - return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{12} + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{13} } // A response containing worker information @@ -1204,7 +1307,7 @@ type ListHcpbWorkersResponse struct { func (x *ListHcpbWorkersResponse) Reset() { *x = ListHcpbWorkersResponse{} if protoimpl.UnsafeEnabled { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[13] + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1217,7 +1320,7 @@ func (x *ListHcpbWorkersResponse) String() string { func (*ListHcpbWorkersResponse) ProtoMessage() {} func (x *ListHcpbWorkersResponse) ProtoReflect() protoreflect.Message { - mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[13] + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1230,7 +1333,7 @@ func (x *ListHcpbWorkersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListHcpbWorkersResponse.ProtoReflect.Descriptor instead. func (*ListHcpbWorkersResponse) Descriptor() ([]byte, []int) { - return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{13} + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{14} } func (x *ListHcpbWorkersResponse) GetWorkers() []*WorkerInfo { @@ -1240,39 +1343,414 @@ func (x *ListHcpbWorkersResponse) GetWorkers() []*WorkerInfo { return nil } -var File_controller_servers_services_v1_server_coordination_service_proto protoreflect.FileDescriptor +type SessionInfoRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -var file_controller_servers_services_v1_server_coordination_service_proto_rawDesc = []byte{ - 0x0a, 0x40, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x76, 0x31, - 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x12, 0x1e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, - 0x76, 0x31, 0x1a, 0x23, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb5, 0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x4f, 0x4e, - 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x75, - 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x79, 0x74, 0x65, 0x73, 0x55, 0x70, - 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x62, 0x79, 0x74, 0x65, 0x73, 0x44, 0x6f, 0x77, 0x6e, 0x22, - 0xa7, 0x02, 0x0a, 0x0e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, - 0x66, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, - 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x4c, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, + // The ID of the worker making the request. + WorkerId string `protobuf:"bytes,1,opt,name=worker_id,json=workerId,proto3" json:"worker_id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + // The sessions which this worker wants to report the status of. + Sessions []*JobStatus `protobuf:"bytes,2,rep,name=sessions,proto3" json:"sessions,omitempty"` +} + +func (x *SessionInfoRequest) Reset() { + *x = SessionInfoRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SessionInfoRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SessionInfoRequest) ProtoMessage() {} + +func (x *SessionInfoRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[15] + 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 SessionInfoRequest.ProtoReflect.Descriptor instead. +func (*SessionInfoRequest) Descriptor() ([]byte, []int) { + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{15} +} + +func (x *SessionInfoRequest) GetWorkerId() string { + if x != nil { + return x.WorkerId + } + return "" +} + +func (x *SessionInfoRequest) GetSessions() []*JobStatus { + if x != nil { + return x.Sessions + } + return nil +} + +type SessionInfoResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // List of sessions and the expected state changes. + SessionChangeRequests []*JobChangeRequest `protobuf:"bytes,1,rep,name=session_change_requests,json=sessionChangeRequests,proto3" json:"session_change_requests,omitempty"` +} + +func (x *SessionInfoResponse) Reset() { + *x = SessionInfoResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SessionInfoResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SessionInfoResponse) ProtoMessage() {} + +func (x *SessionInfoResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[16] + 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 SessionInfoResponse.ProtoReflect.Descriptor instead. +func (*SessionInfoResponse) Descriptor() ([]byte, []int) { + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{16} +} + +func (x *SessionInfoResponse) GetSessionChangeRequests() []*JobChangeRequest { + if x != nil { + return x.SessionChangeRequests + } + return nil +} + +type RoutingInfoRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The ID of the worker making the request. + WorkerId string `protobuf:"bytes,1,opt,name=worker_id,json=workerId,proto3" json:"worker_id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + // Tags read from the workers configuration. Only set if the tags require updating. + Tags []*servers.TagPair `protobuf:"bytes,2,rep,name=tags,proto3" json:"tags,omitempty"` + // Whether the tags should be updated or not. + UpdateTags bool `protobuf:"varint,3,opt,name=update_tags,json=updateTags,proto3" json:"update_tags,omitempty"` + // The worker key identifiers for downstream workers for which there + // is not a known worker id mapping for them yet. + ConnectedUnmappedWorkerKeyIdentifiers []string `protobuf:"bytes,4,rep,name=connected_unmapped_worker_key_identifiers,json=connectedUnmappedWorkerKeyIdentifiers,proto3" json:"connected_unmapped_worker_key_identifiers,omitempty"` + // The worker public ids of all downstreams connected to this worker if known. + // While there may be workers with key ids in the connected_worker_key_identifiers + // list and their public ids in this list, once the requesting worker is aware + // of the association, it should only populate this field. + ConnectedWorkerPublicIds []string `protobuf:"bytes,5,rep,name=connected_worker_public_ids,json=connectedWorkerPublicIds,proto3" json:"connected_worker_public_ids,omitempty"` + // The local_storage_state indicates the state of the local disk space of the worker. + // Possible values are: + // - available: The worker local storage state is at an acceptable state + // - low storage: The worker is below the minimum threshold for local storage + // - critically low storage: The worker local storage state is below the critical minimum threshold for local storage + // - out of storage: The worker is out of local disk space + // - not configured: The worker does not have a local storage path configured + // - unknown: The default local storage state of a worker. Used when the local storage state of a worker is not yet known + LocalStorageState string `protobuf:"bytes,6,opt,name=local_storage_state,json=localStorageState,proto3" json:"local_storage_state,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation" + // StorageBucketCredentialStates is a map where the key is a storage bucket id + // and the value contains the current state of the storage bucket. + StorageBucketCredentialStates map[string]*plugin.StorageBucketCredentialState `protobuf:"bytes,7,rep,name=storage_bucket_credential_states,json=storageBucketCredentialStates,proto3" json:"storage_bucket_credential_states,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` +} + +func (x *RoutingInfoRequest) Reset() { + *x = RoutingInfoRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RoutingInfoRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RoutingInfoRequest) ProtoMessage() {} + +func (x *RoutingInfoRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[17] + 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 RoutingInfoRequest.ProtoReflect.Descriptor instead. +func (*RoutingInfoRequest) Descriptor() ([]byte, []int) { + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{17} +} + +func (x *RoutingInfoRequest) GetWorkerId() string { + if x != nil { + return x.WorkerId + } + return "" +} + +func (x *RoutingInfoRequest) GetTags() []*servers.TagPair { + if x != nil { + return x.Tags + } + return nil +} + +func (x *RoutingInfoRequest) GetUpdateTags() bool { + if x != nil { + return x.UpdateTags + } + return false +} + +func (x *RoutingInfoRequest) GetConnectedUnmappedWorkerKeyIdentifiers() []string { + if x != nil { + return x.ConnectedUnmappedWorkerKeyIdentifiers + } + return nil +} + +func (x *RoutingInfoRequest) GetConnectedWorkerPublicIds() []string { + if x != nil { + return x.ConnectedWorkerPublicIds + } + return nil +} + +func (x *RoutingInfoRequest) GetLocalStorageState() string { + if x != nil { + return x.LocalStorageState + } + return "" +} + +func (x *RoutingInfoRequest) GetStorageBucketCredentialStates() map[string]*plugin.StorageBucketCredentialState { + if x != nil { + return x.StorageBucketCredentialStates + } + return nil +} + +type RoutingInfoResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // UpstreamServer currently returns the controller address in the StatusResponse. + CalculatedUpstreams []*UpstreamServer `protobuf:"bytes,1,rep,name=calculated_upstreams,json=calculatedUpstreams,proto3" json:"calculated_upstreams,omitempty"` + // Of the downstream workers in the request, these are the ones + // which are authorized to remain connected. + AuthorizedDownstreamWorkers *AuthorizedDownstreamWorkerList `protobuf:"bytes,2,opt,name=authorized_downstream_workers,json=authorizedDownstreamWorkers,proto3" json:"authorized_downstream_workers,omitempty"` +} + +func (x *RoutingInfoResponse) Reset() { + *x = RoutingInfoResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RoutingInfoResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RoutingInfoResponse) ProtoMessage() {} + +func (x *RoutingInfoResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[18] + 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 RoutingInfoResponse.ProtoReflect.Descriptor instead. +func (*RoutingInfoResponse) Descriptor() ([]byte, []int) { + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{18} +} + +func (x *RoutingInfoResponse) GetCalculatedUpstreams() []*UpstreamServer { + if x != nil { + return x.CalculatedUpstreams + } + return nil +} + +func (x *RoutingInfoResponse) GetAuthorizedDownstreamWorkers() *AuthorizedDownstreamWorkerList { + if x != nil { + return x.AuthorizedDownstreamWorkers + } + return nil +} + +type StatisticsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The ID of the worker making the request. + WorkerId string `protobuf:"bytes,1,opt,name=worker_id,json=workerId,proto3" json:"worker_id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + // The statistics of the sessions managed by this worker + Sessions []*SessionStatistics `protobuf:"bytes,2,rep,name=sessions,proto3" json:"sessions,omitempty"` +} + +func (x *StatisticsRequest) Reset() { + *x = StatisticsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StatisticsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatisticsRequest) ProtoMessage() {} + +func (x *StatisticsRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[19] + 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 StatisticsRequest.ProtoReflect.Descriptor instead. +func (*StatisticsRequest) Descriptor() ([]byte, []int) { + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{19} +} + +func (x *StatisticsRequest) GetWorkerId() string { + if x != nil { + return x.WorkerId + } + return "" +} + +func (x *StatisticsRequest) GetSessions() []*SessionStatistics { + if x != nil { + return x.Sessions + } + return nil +} + +type StatisticsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *StatisticsResponse) Reset() { + *x = StatisticsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StatisticsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatisticsResponse) ProtoMessage() {} + +func (x *StatisticsResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[20] + 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 StatisticsResponse.ProtoReflect.Descriptor instead. +func (*StatisticsResponse) Descriptor() ([]byte, []int) { + return file_controller_servers_services_v1_server_coordination_service_proto_rawDescGZIP(), []int{20} +} + +var File_controller_servers_services_v1_server_coordination_service_proto protoreflect.FileDescriptor + +var file_controller_servers_services_v1_server_coordination_service_proto_rawDesc = []byte{ + 0x0a, 0x40, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x76, 0x31, + 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x1e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x76, 0x31, 0x1a, 0x23, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x26, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, + 0x76, 0x31, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x6c, 0x75, 0x67, 0x69, + 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0xbd, 0x01, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, + 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, + 0x54, 0x41, 0x54, 0x55, 0x53, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x0a, + 0x08, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, + 0x02, 0x18, 0x01, 0x52, 0x07, 0x62, 0x79, 0x74, 0x65, 0x73, 0x55, 0x70, 0x12, 0x21, 0x0a, 0x0a, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, + 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x62, 0x79, 0x74, 0x65, 0x73, 0x44, 0x6f, 0x77, 0x6e, 0x22, + 0xa7, 0x02, 0x0a, 0x0e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x45, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, + 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x4c, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x61, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, @@ -1328,160 +1806,277 @@ var file_controller_servers_services_v1_server_coordination_service_proto_rawDes 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x52, 0x4f, 0x4c, 0x4c, 0x45, 0x52, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x57, 0x4f, 0x52, 0x4b, 0x45, 0x52, 0x10, 0x02, 0x22, 0xb3, 0x03, 0x0a, 0x0d, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, - 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6f, + 0x50, 0x45, 0x5f, 0x57, 0x4f, 0x52, 0x4b, 0x45, 0x52, 0x10, 0x02, 0x22, 0x75, 0x0a, 0x14, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, + 0x69, 0x63, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x5f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x55, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x64, 0x6f, 0x77, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x62, 0x79, 0x74, 0x65, 0x73, 0x44, 0x6f, + 0x77, 0x6e, 0x22, 0x8a, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x56, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, + 0x63, 0x73, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, + 0xac, 0x04, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x41, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x02, 0x18, 0x01, 0x52, 0x04, + 0x6a, 0x6f, 0x62, 0x73, 0x12, 0x23, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, + 0x61, 0x67, 0x73, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x67, 0x73, 0x12, 0x52, 0x0a, 0x0d, 0x77, 0x6f, 0x72, + 0x6b, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x57, + 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x02, 0x18, 0x01, 0x52, + 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x5c, 0x0a, + 0x29, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x75, 0x6e, 0x6d, 0x61, 0x70, + 0x70, 0x65, 0x64, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x33, 0x20, 0x03, 0x28, 0x09, + 0x42, 0x02, 0x18, 0x01, 0x52, 0x25, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x55, + 0x6e, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4b, 0x65, 0x79, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, 0x41, 0x0a, 0x1b, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, + 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x37, 0x20, 0x03, 0x28, 0x09, + 0x42, 0x02, 0x18, 0x01, 0x52, 0x18, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x57, + 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x73, 0x12, 0x15, + 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x6b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x46, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x50, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x6c, + 0x65, 0x61, 0x73, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x11, 0x6f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x4a, 0x04, + 0x08, 0x32, 0x10, 0x33, 0x52, 0x06, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x20, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x6b, + 0x65, 0x79, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x22, 0x98, + 0x01, 0x0a, 0x10, 0x4a, 0x6f, 0x62, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x12, 0x4d, 0x0a, 0x0c, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x52, 0x0b, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x1e, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x1f, + 0x75, 0x6e, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, + 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x1c, 0x75, 0x6e, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x57, + 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x70, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, + 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x73, 0x22, + 0xa5, 0x03, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x59, 0x0a, 0x0d, 0x6a, 0x6f, 0x62, 0x73, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, + 0x0c, 0x6a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x65, 0x0a, + 0x14, 0x63, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x75, 0x70, 0x73, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x73, 0x18, 0x1e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x12, 0x1f, 0x0a, 0x0b, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x1e, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x67, 0x73, 0x12, 0x4e, 0x0a, - 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x28, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, - 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x4b, 0x0a, - 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, - 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x73, 0x18, 0x32, 0x20, 0x03, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x1d, 0x63, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, 0x58, 0x0a, 0x29, 0x63, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x75, 0x6e, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, - 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x33, 0x20, 0x03, 0x28, 0x09, 0x52, 0x25, 0x63, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, - 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x73, 0x12, 0x3d, 0x0a, 0x1b, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, - 0x64, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, - 0x69, 0x64, 0x73, 0x18, 0x37, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x63, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x49, 0x64, 0x73, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x52, 0x06, 0x77, 0x6f, 0x72, 0x6b, 0x65, - 0x72, 0x22, 0x98, 0x01, 0x0a, 0x10, 0x4a, 0x6f, 0x62, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x12, 0x4d, 0x0a, - 0x0c, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x52, - 0x0b, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x22, 0x54, 0x0a, 0x14, - 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, - 0x4c, 0x69, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x16, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x6b, - 0x65, 0x79, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, - 0x4b, 0x65, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x3a, 0x02, - 0x18, 0x01, 0x22, 0x93, 0x01, 0x0a, 0x1e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, - 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x57, 0x6f, 0x72, 0x6b, 0x65, - 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x1f, 0x75, 0x6e, 0x6d, 0x61, 0x70, 0x70, 0x65, - 0x64, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x1c, - 0x75, 0x6e, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4b, 0x65, - 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x11, - 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x50, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x73, 0x22, 0xe8, 0x03, 0x0a, 0x0e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55, 0x0a, 0x0d, 0x6a, - 0x6f, 0x62, 0x73, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x14, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x02, 0x18, 0x01, 0x52, + 0x13, 0x63, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x55, 0x70, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, + 0x64, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, + 0x64, 0x12, 0x86, 0x01, 0x0a, 0x1d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, + 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x77, 0x6f, 0x72, 0x6b, + 0x65, 0x72, 0x73, 0x18, 0x33, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x57, + 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x1b, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, + 0x4a, 0x04, 0x08, 0x32, 0x10, 0x33, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x73, 0x52, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, + 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x22, 0x36, 0x0a, 0x0a, 0x57, 0x6f, 0x72, 0x6b, 0x65, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, + 0x18, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x63, 0x70, 0x62, 0x57, 0x6f, 0x72, 0x6b, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x5f, 0x0a, 0x17, 0x4c, 0x69, 0x73, + 0x74, 0x48, 0x63, 0x70, 0x62, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x07, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x07, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x22, 0x78, 0x0a, 0x12, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a, + 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x7f, 0x0a, 0x13, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x17, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, + 0x62, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x15, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0xeb, 0x04, 0x0a, 0x12, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, + 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, + 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x04, 0x74, 0x61, 0x67, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x61, 0x67, 0x50, 0x61, 0x69, 0x72, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x1f, 0x0a, + 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x67, 0x73, 0x12, 0x58, + 0x0a, 0x29, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x75, 0x6e, 0x6d, 0x61, + 0x70, 0x70, 0x65, 0x64, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x5f, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x25, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x55, 0x6e, 0x6d, 0x61, + 0x70, 0x70, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, 0x3d, 0x0a, 0x1b, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x63, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x9e, 0x01, 0x0a, 0x20, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x5f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x55, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x4a, 0x6f, 0x62, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x52, 0x0c, 0x6a, 0x6f, 0x62, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x73, 0x12, 0x61, 0x0a, 0x14, 0x63, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, - 0x5f, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x18, 0x1e, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x52, 0x13, 0x63, 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x55, 0x70, 0x73, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, - 0x49, 0x64, 0x12, 0x67, 0x0a, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, - 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, - 0x4c, 0x69, 0x73, 0x74, 0x42, 0x02, 0x18, 0x01, 0x52, 0x11, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x7a, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x12, 0x82, 0x01, 0x0a, 0x1d, - 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x73, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x18, 0x33, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x42, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x1d, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x1a, 0x79, 0x0a, 0x22, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x3d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0xfd, 0x01, 0x0a, 0x13, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x61, 0x0a, 0x14, 0x63, + 0x61, 0x6c, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x13, 0x63, 0x61, 0x6c, 0x63, 0x75, + 0x6c, 0x61, 0x74, 0x65, 0x64, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x82, + 0x01, 0x0a, 0x1d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x64, 0x6f, + 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, + 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x57, 0x6f, 0x72, 0x6b, + 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x1b, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, + 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x57, 0x6f, 0x72, 0x6b, + 0x65, 0x72, 0x73, 0x22, 0x7f, 0x0a, 0x11, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, + 0x6b, 0x65, 0x72, 0x49, 0x64, 0x12, 0x4d, 0x0a, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, + 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x92, 0x01, 0x0a, 0x10, 0x43, + 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, + 0x20, 0x0a, 0x1c, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, + 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x1f, 0x0a, 0x1b, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, + 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x5a, 0x45, 0x44, + 0x10, 0x01, 0x12, 0x1e, 0x0a, 0x1a, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, + 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, + 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, + 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, 0x10, 0x03, 0x2a, + 0x9e, 0x01, 0x0a, 0x0d, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, + 0x53, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, + 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, + 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, + 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x54, + 0x49, 0x56, 0x45, 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, + 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x49, 0x4e, 0x47, + 0x10, 0x03, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, + 0x54, 0x55, 0x53, 0x5f, 0x54, 0x45, 0x52, 0x4d, 0x49, 0x4e, 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, + 0x2a, 0x6d, 0x0a, 0x16, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, + 0x73, 0x73, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x28, 0x0a, 0x24, 0x53, 0x45, + 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x43, 0x45, 0x53, 0x53, 0x49, 0x4e, 0x47, + 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x29, 0x0a, 0x25, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, + 0x50, 0x52, 0x4f, 0x43, 0x45, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, + 0x5f, 0x55, 0x4e, 0x52, 0x45, 0x43, 0x4f, 0x47, 0x4e, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x01, 0x2a, + 0x54, 0x0a, 0x07, 0x4a, 0x4f, 0x42, 0x54, 0x59, 0x50, 0x45, 0x12, 0x17, 0x0a, 0x13, 0x4a, 0x4f, + 0x42, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x4a, 0x4f, 0x42, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, + 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x4a, 0x4f, 0x42, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x4f, 0x4e, 0x49, 0x54, 0x4f, 0x52, 0x5f, 0x53, 0x45, 0x53, 0x53, + 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x2a, 0x45, 0x0a, 0x0a, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, + 0x59, 0x50, 0x45, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x1b, 0x0a, 0x17, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x50, + 0x44, 0x41, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x01, 0x32, 0xf8, 0x04, 0x0a, + 0x19, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x06, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x44, - 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x1b, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x44, - 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, - 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, - 0x65, 0x72, 0x73, 0x22, 0x36, 0x0a, 0x0a, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x4c, - 0x69, 0x73, 0x74, 0x48, 0x63, 0x70, 0x62, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x5f, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x63, 0x70, - 0x62, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x44, 0x0a, 0x07, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x84, 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x63, + 0x70, 0x62, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x12, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x48, + 0x63, 0x70, 0x62, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x77, - 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x2a, 0x92, 0x01, 0x0a, 0x10, 0x43, 0x4f, 0x4e, 0x4e, 0x45, - 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x20, 0x0a, 0x1c, 0x43, - 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1f, 0x0a, - 0x1b, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, - 0x53, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1e, - 0x0a, 0x1a, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, - 0x55, 0x53, 0x5f, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1b, - 0x0a, 0x17, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, - 0x55, 0x53, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x9e, 0x01, 0x0a, 0x0d, - 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x12, 0x1d, 0x0a, - 0x19, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, - 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, - 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, - 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x45, 0x53, 0x53, 0x49, - 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, - 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, - 0x55, 0x53, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x1c, - 0x0a, 0x18, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, - 0x54, 0x45, 0x52, 0x4d, 0x49, 0x4e, 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, 0x2a, 0x6d, 0x0a, 0x16, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, - 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x28, 0x0a, 0x24, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, - 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x43, 0x45, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x52, 0x52, - 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x29, 0x0a, 0x25, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x43, - 0x45, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x52, - 0x45, 0x43, 0x4f, 0x47, 0x4e, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x01, 0x2a, 0x54, 0x0a, 0x07, 0x4a, - 0x4f, 0x42, 0x54, 0x59, 0x50, 0x45, 0x12, 0x17, 0x0a, 0x13, 0x4a, 0x4f, 0x42, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, - 0x13, 0x0a, 0x0f, 0x4a, 0x4f, 0x42, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, - 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x4a, 0x4f, 0x42, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x4d, 0x4f, 0x4e, 0x49, 0x54, 0x4f, 0x52, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x10, - 0x02, 0x2a, 0x45, 0x0a, 0x0a, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x12, - 0x1a, 0x0a, 0x16, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x43, - 0x48, 0x41, 0x4e, 0x47, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, - 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x01, 0x32, 0x8d, 0x02, 0x0a, 0x19, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x69, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x63, 0x70, 0x62, 0x57, 0x6f, 0x72, 0x6b, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x78, 0x0a, 0x0b, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x32, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x84, 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x63, 0x70, 0x62, 0x57, 0x6f, - 0x72, 0x6b, 0x65, 0x72, 0x73, 0x12, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x78, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, + 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x63, 0x70, 0x62, 0x57, - 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x48, 0x63, 0x70, 0x62, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, - 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, - 0x72, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, + 0x6e, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x75, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x12, 0x31, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, + 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -1497,29 +2092,39 @@ func file_controller_servers_services_v1_server_coordination_service_proto_rawDe } var file_controller_servers_services_v1_server_coordination_service_proto_enumTypes = make([]protoimpl.EnumInfo, 6) -var file_controller_servers_services_v1_server_coordination_service_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_controller_servers_services_v1_server_coordination_service_proto_msgTypes = make([]protoimpl.MessageInfo, 22) var file_controller_servers_services_v1_server_coordination_service_proto_goTypes = []any{ - (CONNECTIONSTATUS)(0), // 0: controller.servers.services.v1.CONNECTIONSTATUS - (SESSIONSTATUS)(0), // 1: controller.servers.services.v1.SESSIONSTATUS - (SessionProcessingError)(0), // 2: controller.servers.services.v1.SessionProcessingError - (JOBTYPE)(0), // 3: controller.servers.services.v1.JOBTYPE - (CHANGETYPE)(0), // 4: controller.servers.services.v1.CHANGETYPE - (UpstreamServer_TYPE)(0), // 5: controller.servers.services.v1.UpstreamServer.TYPE - (*Connection)(nil), // 6: controller.servers.services.v1.Connection - (*SessionJobInfo)(nil), // 7: controller.servers.services.v1.SessionJobInfo - (*MonitorSessionJobInfo)(nil), // 8: controller.servers.services.v1.MonitorSessionJobInfo - (*Job)(nil), // 9: controller.servers.services.v1.Job - (*JobStatus)(nil), // 10: controller.servers.services.v1.JobStatus - (*UpstreamServer)(nil), // 11: controller.servers.services.v1.UpstreamServer - (*StatusRequest)(nil), // 12: controller.servers.services.v1.StatusRequest - (*JobChangeRequest)(nil), // 13: controller.servers.services.v1.JobChangeRequest - (*AuthorizedWorkerList)(nil), // 14: controller.servers.services.v1.AuthorizedWorkerList - (*AuthorizedDownstreamWorkerList)(nil), // 15: controller.servers.services.v1.AuthorizedDownstreamWorkerList - (*StatusResponse)(nil), // 16: controller.servers.services.v1.StatusResponse - (*WorkerInfo)(nil), // 17: controller.servers.services.v1.WorkerInfo - (*ListHcpbWorkersRequest)(nil), // 18: controller.servers.services.v1.ListHcpbWorkersRequest - (*ListHcpbWorkersResponse)(nil), // 19: controller.servers.services.v1.ListHcpbWorkersResponse - (*servers.ServerWorkerStatus)(nil), // 20: controller.servers.v1.ServerWorkerStatus + (CONNECTIONSTATUS)(0), // 0: controller.servers.services.v1.CONNECTIONSTATUS + (SESSIONSTATUS)(0), // 1: controller.servers.services.v1.SESSIONSTATUS + (SessionProcessingError)(0), // 2: controller.servers.services.v1.SessionProcessingError + (JOBTYPE)(0), // 3: controller.servers.services.v1.JOBTYPE + (CHANGETYPE)(0), // 4: controller.servers.services.v1.CHANGETYPE + (UpstreamServer_TYPE)(0), // 5: controller.servers.services.v1.UpstreamServer.TYPE + (*Connection)(nil), // 6: controller.servers.services.v1.Connection + (*SessionJobInfo)(nil), // 7: controller.servers.services.v1.SessionJobInfo + (*MonitorSessionJobInfo)(nil), // 8: controller.servers.services.v1.MonitorSessionJobInfo + (*Job)(nil), // 9: controller.servers.services.v1.Job + (*JobStatus)(nil), // 10: controller.servers.services.v1.JobStatus + (*UpstreamServer)(nil), // 11: controller.servers.services.v1.UpstreamServer + (*ConnectionStatistics)(nil), // 12: controller.servers.services.v1.ConnectionStatistics + (*SessionStatistics)(nil), // 13: controller.servers.services.v1.SessionStatistics + (*StatusRequest)(nil), // 14: controller.servers.services.v1.StatusRequest + (*JobChangeRequest)(nil), // 15: controller.servers.services.v1.JobChangeRequest + (*AuthorizedDownstreamWorkerList)(nil), // 16: controller.servers.services.v1.AuthorizedDownstreamWorkerList + (*StatusResponse)(nil), // 17: controller.servers.services.v1.StatusResponse + (*WorkerInfo)(nil), // 18: controller.servers.services.v1.WorkerInfo + (*ListHcpbWorkersRequest)(nil), // 19: controller.servers.services.v1.ListHcpbWorkersRequest + (*ListHcpbWorkersResponse)(nil), // 20: controller.servers.services.v1.ListHcpbWorkersResponse + (*SessionInfoRequest)(nil), // 21: controller.servers.services.v1.SessionInfoRequest + (*SessionInfoResponse)(nil), // 22: controller.servers.services.v1.SessionInfoResponse + (*RoutingInfoRequest)(nil), // 23: controller.servers.services.v1.RoutingInfoRequest + (*RoutingInfoResponse)(nil), // 24: controller.servers.services.v1.RoutingInfoResponse + (*StatisticsRequest)(nil), // 25: controller.servers.services.v1.StatisticsRequest + (*StatisticsResponse)(nil), // 26: controller.servers.services.v1.StatisticsResponse + nil, // 27: controller.servers.services.v1.RoutingInfoRequest.StorageBucketCredentialStatesEntry + (*servers.ServerWorkerStatus)(nil), // 28: controller.servers.v1.ServerWorkerStatus + (*servers.TagPair)(nil), // 29: controller.servers.v1.TagPair + (*plugin.StorageBucketCredentialState)(nil), // 30: plugin.v1.StorageBucketCredentialState } var file_controller_servers_services_v1_server_coordination_service_proto_depIdxs = []int32{ 0, // 0: controller.servers.services.v1.Connection.status:type_name -> controller.servers.services.v1.CONNECTIONSTATUS @@ -1533,24 +2138,38 @@ var file_controller_servers_services_v1_server_coordination_service_proto_depIdx 8, // 8: controller.servers.services.v1.Job.monitor_session_info:type_name -> controller.servers.services.v1.MonitorSessionJobInfo 9, // 9: controller.servers.services.v1.JobStatus.job:type_name -> controller.servers.services.v1.Job 5, // 10: controller.servers.services.v1.UpstreamServer.type:type_name -> controller.servers.services.v1.UpstreamServer.TYPE - 10, // 11: controller.servers.services.v1.StatusRequest.jobs:type_name -> controller.servers.services.v1.JobStatus - 20, // 12: controller.servers.services.v1.StatusRequest.worker_status:type_name -> controller.servers.v1.ServerWorkerStatus - 9, // 13: controller.servers.services.v1.JobChangeRequest.job:type_name -> controller.servers.services.v1.Job - 4, // 14: controller.servers.services.v1.JobChangeRequest.request_type:type_name -> controller.servers.services.v1.CHANGETYPE - 13, // 15: controller.servers.services.v1.StatusResponse.jobs_requests:type_name -> controller.servers.services.v1.JobChangeRequest - 11, // 16: controller.servers.services.v1.StatusResponse.calculated_upstreams:type_name -> controller.servers.services.v1.UpstreamServer - 14, // 17: controller.servers.services.v1.StatusResponse.authorized_workers:type_name -> controller.servers.services.v1.AuthorizedWorkerList - 15, // 18: controller.servers.services.v1.StatusResponse.authorized_downstream_workers:type_name -> controller.servers.services.v1.AuthorizedDownstreamWorkerList - 17, // 19: controller.servers.services.v1.ListHcpbWorkersResponse.workers:type_name -> controller.servers.services.v1.WorkerInfo - 12, // 20: controller.servers.services.v1.ServerCoordinationService.Status:input_type -> controller.servers.services.v1.StatusRequest - 18, // 21: controller.servers.services.v1.ServerCoordinationService.ListHcpbWorkers:input_type -> controller.servers.services.v1.ListHcpbWorkersRequest - 16, // 22: controller.servers.services.v1.ServerCoordinationService.Status:output_type -> controller.servers.services.v1.StatusResponse - 19, // 23: controller.servers.services.v1.ServerCoordinationService.ListHcpbWorkers:output_type -> controller.servers.services.v1.ListHcpbWorkersResponse - 22, // [22:24] is the sub-list for method output_type - 20, // [20:22] is the sub-list for method input_type - 20, // [20:20] is the sub-list for extension type_name - 20, // [20:20] is the sub-list for extension extendee - 0, // [0:20] is the sub-list for field type_name + 12, // 11: controller.servers.services.v1.SessionStatistics.connections:type_name -> controller.servers.services.v1.ConnectionStatistics + 10, // 12: controller.servers.services.v1.StatusRequest.jobs:type_name -> controller.servers.services.v1.JobStatus + 28, // 13: controller.servers.services.v1.StatusRequest.worker_status:type_name -> controller.servers.v1.ServerWorkerStatus + 9, // 14: controller.servers.services.v1.JobChangeRequest.job:type_name -> controller.servers.services.v1.Job + 4, // 15: controller.servers.services.v1.JobChangeRequest.request_type:type_name -> controller.servers.services.v1.CHANGETYPE + 15, // 16: controller.servers.services.v1.StatusResponse.jobs_requests:type_name -> controller.servers.services.v1.JobChangeRequest + 11, // 17: controller.servers.services.v1.StatusResponse.calculated_upstreams:type_name -> controller.servers.services.v1.UpstreamServer + 16, // 18: controller.servers.services.v1.StatusResponse.authorized_downstream_workers:type_name -> controller.servers.services.v1.AuthorizedDownstreamWorkerList + 18, // 19: controller.servers.services.v1.ListHcpbWorkersResponse.workers:type_name -> controller.servers.services.v1.WorkerInfo + 10, // 20: controller.servers.services.v1.SessionInfoRequest.sessions:type_name -> controller.servers.services.v1.JobStatus + 15, // 21: controller.servers.services.v1.SessionInfoResponse.session_change_requests:type_name -> controller.servers.services.v1.JobChangeRequest + 29, // 22: controller.servers.services.v1.RoutingInfoRequest.tags:type_name -> controller.servers.v1.TagPair + 27, // 23: controller.servers.services.v1.RoutingInfoRequest.storage_bucket_credential_states:type_name -> controller.servers.services.v1.RoutingInfoRequest.StorageBucketCredentialStatesEntry + 11, // 24: controller.servers.services.v1.RoutingInfoResponse.calculated_upstreams:type_name -> controller.servers.services.v1.UpstreamServer + 16, // 25: controller.servers.services.v1.RoutingInfoResponse.authorized_downstream_workers:type_name -> controller.servers.services.v1.AuthorizedDownstreamWorkerList + 13, // 26: controller.servers.services.v1.StatisticsRequest.sessions:type_name -> controller.servers.services.v1.SessionStatistics + 30, // 27: controller.servers.services.v1.RoutingInfoRequest.StorageBucketCredentialStatesEntry.value:type_name -> plugin.v1.StorageBucketCredentialState + 14, // 28: controller.servers.services.v1.ServerCoordinationService.Status:input_type -> controller.servers.services.v1.StatusRequest + 19, // 29: controller.servers.services.v1.ServerCoordinationService.ListHcpbWorkers:input_type -> controller.servers.services.v1.ListHcpbWorkersRequest + 21, // 30: controller.servers.services.v1.ServerCoordinationService.SessionInfo:input_type -> controller.servers.services.v1.SessionInfoRequest + 23, // 31: controller.servers.services.v1.ServerCoordinationService.RoutingInfo:input_type -> controller.servers.services.v1.RoutingInfoRequest + 25, // 32: controller.servers.services.v1.ServerCoordinationService.Statistics:input_type -> controller.servers.services.v1.StatisticsRequest + 17, // 33: controller.servers.services.v1.ServerCoordinationService.Status:output_type -> controller.servers.services.v1.StatusResponse + 20, // 34: controller.servers.services.v1.ServerCoordinationService.ListHcpbWorkers:output_type -> controller.servers.services.v1.ListHcpbWorkersResponse + 22, // 35: controller.servers.services.v1.ServerCoordinationService.SessionInfo:output_type -> controller.servers.services.v1.SessionInfoResponse + 24, // 36: controller.servers.services.v1.ServerCoordinationService.RoutingInfo:output_type -> controller.servers.services.v1.RoutingInfoResponse + 26, // 37: controller.servers.services.v1.ServerCoordinationService.Statistics:output_type -> controller.servers.services.v1.StatisticsResponse + 33, // [33:38] is the sub-list for method output_type + 28, // [28:33] is the sub-list for method input_type + 28, // [28:28] is the sub-list for extension type_name + 28, // [28:28] is the sub-list for extension extendee + 0, // [0:28] is the sub-list for field type_name } func init() { file_controller_servers_services_v1_server_coordination_service_proto_init() } @@ -1632,7 +2251,7 @@ func file_controller_servers_services_v1_server_coordination_service_proto_init( } } file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[6].Exporter = func(v any, i int) any { - switch v := v.(*StatusRequest); i { + switch v := v.(*ConnectionStatistics); i { case 0: return &v.state case 1: @@ -1644,7 +2263,7 @@ func file_controller_servers_services_v1_server_coordination_service_proto_init( } } file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[7].Exporter = func(v any, i int) any { - switch v := v.(*JobChangeRequest); i { + switch v := v.(*SessionStatistics); i { case 0: return &v.state case 1: @@ -1656,7 +2275,7 @@ func file_controller_servers_services_v1_server_coordination_service_proto_init( } } file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[8].Exporter = func(v any, i int) any { - switch v := v.(*AuthorizedWorkerList); i { + switch v := v.(*StatusRequest); i { case 0: return &v.state case 1: @@ -1668,7 +2287,7 @@ func file_controller_servers_services_v1_server_coordination_service_proto_init( } } file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[9].Exporter = func(v any, i int) any { - switch v := v.(*AuthorizedDownstreamWorkerList); i { + switch v := v.(*JobChangeRequest); i { case 0: return &v.state case 1: @@ -1680,7 +2299,7 @@ func file_controller_servers_services_v1_server_coordination_service_proto_init( } } file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[10].Exporter = func(v any, i int) any { - switch v := v.(*StatusResponse); i { + switch v := v.(*AuthorizedDownstreamWorkerList); i { case 0: return &v.state case 1: @@ -1692,7 +2311,7 @@ func file_controller_servers_services_v1_server_coordination_service_proto_init( } } file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[11].Exporter = func(v any, i int) any { - switch v := v.(*WorkerInfo); i { + switch v := v.(*StatusResponse); i { case 0: return &v.state case 1: @@ -1704,7 +2323,7 @@ func file_controller_servers_services_v1_server_coordination_service_proto_init( } } file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[12].Exporter = func(v any, i int) any { - switch v := v.(*ListHcpbWorkersRequest); i { + switch v := v.(*WorkerInfo); i { case 0: return &v.state case 1: @@ -1716,6 +2335,18 @@ func file_controller_servers_services_v1_server_coordination_service_proto_init( } } file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[13].Exporter = func(v any, i int) any { + switch v := v.(*ListHcpbWorkersRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[14].Exporter = func(v any, i int) any { switch v := v.(*ListHcpbWorkersResponse); i { case 0: return &v.state @@ -1727,6 +2358,78 @@ func file_controller_servers_services_v1_server_coordination_service_proto_init( return nil } } + file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[15].Exporter = func(v any, i int) any { + switch v := v.(*SessionInfoRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[16].Exporter = func(v any, i int) any { + switch v := v.(*SessionInfoResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[17].Exporter = func(v any, i int) any { + switch v := v.(*RoutingInfoRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[18].Exporter = func(v any, i int) any { + switch v := v.(*RoutingInfoResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[19].Exporter = func(v any, i int) any { + switch v := v.(*StatisticsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[20].Exporter = func(v any, i int) any { + switch v := v.(*StatisticsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_controller_servers_services_v1_server_coordination_service_proto_msgTypes[3].OneofWrappers = []any{ (*Job_SessionInfo)(nil), @@ -1738,7 +2441,7 @@ func file_controller_servers_services_v1_server_coordination_service_proto_init( GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_controller_servers_services_v1_server_coordination_service_proto_rawDesc, NumEnums: 6, - NumMessages: 14, + NumMessages: 22, NumExtensions: 0, NumServices: 1, }, diff --git a/internal/gen/controller/servers/services/server_coordination_service_grpc.pb.go b/internal/gen/controller/servers/services/server_coordination_service_grpc.pb.go index ce1caec4e3..8592aa4fbf 100644 --- a/internal/gen/controller/servers/services/server_coordination_service_grpc.pb.go +++ b/internal/gen/controller/servers/services/server_coordination_service_grpc.pb.go @@ -24,18 +24,36 @@ const _ = grpc.SupportPackageIsVersion7 const ( ServerCoordinationService_Status_FullMethodName = "/controller.servers.services.v1.ServerCoordinationService/Status" ServerCoordinationService_ListHcpbWorkers_FullMethodName = "/controller.servers.services.v1.ServerCoordinationService/ListHcpbWorkers" + ServerCoordinationService_SessionInfo_FullMethodName = "/controller.servers.services.v1.ServerCoordinationService/SessionInfo" + ServerCoordinationService_RoutingInfo_FullMethodName = "/controller.servers.services.v1.ServerCoordinationService/RoutingInfo" + ServerCoordinationService_Statistics_FullMethodName = "/controller.servers.services.v1.ServerCoordinationService/Statistics" ) // ServerCoordinationServiceClient is the client API for ServerCoordinationService 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 ServerCoordinationServiceClient interface { - // Status gets worker status requests which include the ongoing jobs the worker is handling and - // returns the status response which includes the changes the controller would like to make to - // jobs as well as provide a list of the controllers in the system. + // Status is used by the worker to signal to the controller that it is still alive. + // If the worker fails to successfully report its status to the controller for a + // period of time, it will try again later. Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) // Returns the addresses of HCP Boundary workers, if any ListHcpbWorkers(ctx context.Context, in *ListHcpbWorkersRequest, opts ...grpc.CallOption) (*ListHcpbWorkersResponse, error) + // SessionInfo is used by the worker to inform the controller of all the sessions + // it is managing. The controller may inform the worker if any sessions need to be changed. + // If the worker repeatedly fails to successfully report its session info to the controller, + // it will tear down any running sessions. + SessionInfo(ctx context.Context, in *SessionInfoRequest, opts ...grpc.CallOption) (*SessionInfoResponse, error) + // RoutingInfo is used by the worker to inform the controller of information + // required by the controller to make session routing decisions. The controller may + // inform the worker of any downstream workers that should be disconnected. + // If the worker fails to successfully report its route info to the controller, + // it will try again later. + RoutingInfo(ctx context.Context, in *RoutingInfoRequest, opts ...grpc.CallOption) (*RoutingInfoResponse, error) + // Statistics is used by the worker to report non-essential statistics about its + // sessions and connections. If the worker fails to successfully report its + // statistics to the controller, it will try again later. + Statistics(ctx context.Context, in *StatisticsRequest, opts ...grpc.CallOption) (*StatisticsResponse, error) } type serverCoordinationServiceClient struct { @@ -64,16 +82,58 @@ func (c *serverCoordinationServiceClient) ListHcpbWorkers(ctx context.Context, i return out, nil } +func (c *serverCoordinationServiceClient) SessionInfo(ctx context.Context, in *SessionInfoRequest, opts ...grpc.CallOption) (*SessionInfoResponse, error) { + out := new(SessionInfoResponse) + err := c.cc.Invoke(ctx, ServerCoordinationService_SessionInfo_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serverCoordinationServiceClient) RoutingInfo(ctx context.Context, in *RoutingInfoRequest, opts ...grpc.CallOption) (*RoutingInfoResponse, error) { + out := new(RoutingInfoResponse) + err := c.cc.Invoke(ctx, ServerCoordinationService_RoutingInfo_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *serverCoordinationServiceClient) Statistics(ctx context.Context, in *StatisticsRequest, opts ...grpc.CallOption) (*StatisticsResponse, error) { + out := new(StatisticsResponse) + err := c.cc.Invoke(ctx, ServerCoordinationService_Statistics_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ServerCoordinationServiceServer is the server API for ServerCoordinationService service. // All implementations must embed UnimplementedServerCoordinationServiceServer // for forward compatibility type ServerCoordinationServiceServer interface { - // Status gets worker status requests which include the ongoing jobs the worker is handling and - // returns the status response which includes the changes the controller would like to make to - // jobs as well as provide a list of the controllers in the system. + // Status is used by the worker to signal to the controller that it is still alive. + // If the worker fails to successfully report its status to the controller for a + // period of time, it will try again later. Status(context.Context, *StatusRequest) (*StatusResponse, error) // Returns the addresses of HCP Boundary workers, if any ListHcpbWorkers(context.Context, *ListHcpbWorkersRequest) (*ListHcpbWorkersResponse, error) + // SessionInfo is used by the worker to inform the controller of all the sessions + // it is managing. The controller may inform the worker if any sessions need to be changed. + // If the worker repeatedly fails to successfully report its session info to the controller, + // it will tear down any running sessions. + SessionInfo(context.Context, *SessionInfoRequest) (*SessionInfoResponse, error) + // RoutingInfo is used by the worker to inform the controller of information + // required by the controller to make session routing decisions. The controller may + // inform the worker of any downstream workers that should be disconnected. + // If the worker fails to successfully report its route info to the controller, + // it will try again later. + RoutingInfo(context.Context, *RoutingInfoRequest) (*RoutingInfoResponse, error) + // Statistics is used by the worker to report non-essential statistics about its + // sessions and connections. If the worker fails to successfully report its + // statistics to the controller, it will try again later. + Statistics(context.Context, *StatisticsRequest) (*StatisticsResponse, error) mustEmbedUnimplementedServerCoordinationServiceServer() } @@ -87,6 +147,15 @@ func (UnimplementedServerCoordinationServiceServer) Status(context.Context, *Sta func (UnimplementedServerCoordinationServiceServer) ListHcpbWorkers(context.Context, *ListHcpbWorkersRequest) (*ListHcpbWorkersResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListHcpbWorkers not implemented") } +func (UnimplementedServerCoordinationServiceServer) SessionInfo(context.Context, *SessionInfoRequest) (*SessionInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SessionInfo not implemented") +} +func (UnimplementedServerCoordinationServiceServer) RoutingInfo(context.Context, *RoutingInfoRequest) (*RoutingInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RoutingInfo not implemented") +} +func (UnimplementedServerCoordinationServiceServer) Statistics(context.Context, *StatisticsRequest) (*StatisticsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Statistics not implemented") +} func (UnimplementedServerCoordinationServiceServer) mustEmbedUnimplementedServerCoordinationServiceServer() { } @@ -137,6 +206,60 @@ func _ServerCoordinationService_ListHcpbWorkers_Handler(srv interface{}, ctx con return interceptor(ctx, in, info, handler) } +func _ServerCoordinationService_SessionInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SessionInfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ServerCoordinationServiceServer).SessionInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ServerCoordinationService_SessionInfo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ServerCoordinationServiceServer).SessionInfo(ctx, req.(*SessionInfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ServerCoordinationService_RoutingInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RoutingInfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ServerCoordinationServiceServer).RoutingInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ServerCoordinationService_RoutingInfo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ServerCoordinationServiceServer).RoutingInfo(ctx, req.(*RoutingInfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ServerCoordinationService_Statistics_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StatisticsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ServerCoordinationServiceServer).Statistics(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ServerCoordinationService_Statistics_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ServerCoordinationServiceServer).Statistics(ctx, req.(*StatisticsRequest)) + } + return interceptor(ctx, in, info, handler) +} + // ServerCoordinationService_ServiceDesc is the grpc.ServiceDesc for ServerCoordinationService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -152,6 +275,18 @@ var ServerCoordinationService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ListHcpbWorkers", Handler: _ServerCoordinationService_ListHcpbWorkers_Handler, }, + { + MethodName: "SessionInfo", + Handler: _ServerCoordinationService_SessionInfo_Handler, + }, + { + MethodName: "RoutingInfo", + Handler: _ServerCoordinationService_RoutingInfo_Handler, + }, + { + MethodName: "Statistics", + Handler: _ServerCoordinationService_Statistics_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "controller/servers/services/v1/server_coordination_service.proto", diff --git a/internal/proto/controller/servers/services/v1/server_coordination_service.proto b/internal/proto/controller/servers/services/v1/server_coordination_service.proto index 89f215916b..3f2521e253 100644 --- a/internal/proto/controller/servers/services/v1/server_coordination_service.proto +++ b/internal/proto/controller/servers/services/v1/server_coordination_service.proto @@ -6,17 +6,36 @@ syntax = "proto3"; package controller.servers.services.v1; import "controller/servers/v1/servers.proto"; +import "plugin/v1/storage_plugin_service.proto"; option go_package = "github.com/hashicorp/boundary/internal/gen/controller/servers/services;services"; service ServerCoordinationService { - // Status gets worker status requests which include the ongoing jobs the worker is handling and - // returns the status response which includes the changes the controller would like to make to - // jobs as well as provide a list of the controllers in the system. + // Status is used by the worker to signal to the controller that it is still alive. + // If the worker fails to successfully report its status to the controller for a + // period of time, it will try again later. rpc Status(StatusRequest) returns (StatusResponse) {} // Returns the addresses of HCP Boundary workers, if any rpc ListHcpbWorkers(ListHcpbWorkersRequest) returns (ListHcpbWorkersResponse) {} + + // SessionInfo is used by the worker to inform the controller of all the sessions + // it is managing. The controller may inform the worker if any sessions need to be changed. + // If the worker repeatedly fails to successfully report its session info to the controller, + // it will tear down any running sessions. + rpc SessionInfo(SessionInfoRequest) returns (SessionInfoResponse) {} + + // RoutingInfo is used by the worker to inform the controller of information + // required by the controller to make session routing decisions. The controller may + // inform the worker of any downstream workers that should be disconnected. + // If the worker fails to successfully report its route info to the controller, + // it will try again later. + rpc RoutingInfo(RoutingInfoRequest) returns (RoutingInfoResponse) {} + + // Statistics is used by the worker to report non-essential statistics about its + // sessions and connections. If the worker fails to successfully report its + // statistics to the controller, it will try again later. + rpc Statistics(StatisticsRequest) returns (StatisticsResponse) {} } enum CONNECTIONSTATUS { @@ -29,8 +48,8 @@ enum CONNECTIONSTATUS { message Connection { string connection_id = 1; // @gotags: `class:"public" eventstream:"observation"` CONNECTIONSTATUS status = 2; - int64 bytes_up = 3; // @gotags: `class:"public"` - int64 bytes_down = 4; // @gotags: `class:"public"` + int64 bytes_up = 3 [deprecated = true]; // @gotags: `class:"public"` + int64 bytes_down = 4 [deprecated = true]; // @gotags: `class:"public"` } enum SESSIONSTATUS { @@ -94,40 +113,60 @@ message UpstreamServer { string address = 20; // @gotags: `class:"public"` } +// ConnectionStatistics contains statistics about a connection. +message ConnectionStatistics { + string connection_id = 1; // @gotags: `class:"public" eventstream:"observation"` + int64 bytes_up = 2; // @gotags: `class:"public"` + int64 bytes_down = 3; // @gotags: `class:"public"` +} + +// SessionStatistics contains statistics about a session and its connections. +message SessionStatistics { + string session_id = 1; // @gotags: `class:"public" eventstream:"observation"` + repeated ConnectionStatistics connections = 2; +} + message StatusRequest { - reserved 10; - reserved "worker"; + reserved 10, 50; + reserved "worker", "connected_worker_key_identifiers"; - // Jobs which this worker wants to report the status. - repeated JobStatus jobs = 20; + // Jobs which this worker wants to report the status of. Can be removed after 0.20.0. + repeated JobStatus jobs = 20 [deprecated = true]; // Whether to update tags from the Server block on this RPC. We only need to // do this at startup or (at some point) SIGHUP, so specifying when it's // changed allows us to avoid constant database operations for something that - // won't change very often, if ever. - bool update_tags = 30; + // won't change very often, if ever. Can be removed after 0.20.0. + bool update_tags = 30 [deprecated = true]; - // Replaces the old worker field: // The worker info. We could use information from the TLS connection but this // is easier and going the other route doesn't provide much benefit -- if you // get access to the key and spoof the connection, you're already compromised. - servers.v1.ServerWorkerStatus worker_status = 40; - - // The worker key identifiers presented by all downstreams connected to this - // worker. - // Deprecated. Should be removed in 0.15.0 at which time - // connected_unmapped_worker_key_identifiers should be used exclusively. - repeated string connected_worker_key_identifiers = 50 [deprecated = true]; + // Can be removed after 0.20.0. + servers.v1.ServerWorkerStatus worker_status = 40 [deprecated = true]; // The worker key identifiers for downstream workers for which there - // is not a known worker id mapping for them yet. - repeated string connected_unmapped_worker_key_identifiers = 51; + // is not a known worker id mapping for them yet. Can be removed after 0.20.0. + repeated string connected_unmapped_worker_key_identifiers = 51 [deprecated = true]; // The worker public ids of all downstreams connected to this worker if known. // While there may be workers with key ids in the connected_worker_key_identifiers // list and their public ids in this list, once the requesting worker is aware - // of the association, it should only populate this field. - repeated string connected_worker_public_ids = 55; + // of the association, it should only populate this field. Can be removed after 0.20.0. + repeated string connected_worker_public_ids = 55 [deprecated = true]; + + // The key id for this worker, set on the first status. + string key_id = 60; // @gotags: `class:"public"` eventstream:"observation"` + + // The ID of the worker which made the request. It will be used to identify the worker on + // subsequent status updates. + string worker_id = 70; // @gotags: `class:"public" eventstream:"observation"` + + // The version of Boundary the worker binary is running. + string release_version = 80; // @gotags: `class:"public" eventstream:"observation"` + + // The state of the worker, to indicate if the worker is active or in shutdown. + string operational_state = 90; // @gotags: `class:"public" eventstream:"observation"` } enum CHANGETYPE { @@ -142,12 +181,6 @@ message JobChangeRequest { CHANGETYPE request_type = 2; } -message AuthorizedWorkerList { - option deprecated = true; - // the key id of authorized workers - repeated string worker_key_identifiers = 1 [deprecated = true]; -} - message AuthorizedDownstreamWorkerList { // the key id of authorized workers which do not have a worker id known yet // to the requester. @@ -158,32 +191,25 @@ message AuthorizedDownstreamWorkerList { } message StatusResponse { - reserved 10; - reserved "controllers"; + reserved 10, 50; + reserved "controllers", "authorized_workers"; // List of jobs and the expected state changes. For example, this will - // include jobs witch change type of canceled for jobs which are active on a - // worker but should be canceled. This could also contain a request to start a - // job such as a worker -> worker proxy for establishing a session through an - // enclave. - repeated JobChangeRequest jobs_requests = 20; + // include jobs which change type of canceled for jobs which are active on a + // worker but should be canceled. Can be removed after 0.20.0. + repeated JobChangeRequest jobs_requests = 20 [deprecated = true]; // UpstreamServer currently returns the controller address in the StatusResponse. - repeated UpstreamServer calculated_upstreams = 30; + // Can be removed after 0.20.0. + repeated UpstreamServer calculated_upstreams = 30 [deprecated = true]; - // The ID of the worker which made the request. The worker can send this value in subsequent requests so the - // controller does not need to do a database lookup for the id using the name field. + // The ID of the worker which made the request. After the initial status request, + // the worker will use this to identify itself. string worker_id = 40; // @gotags: `class:"public" eventstream:"observation"` - // Of the worker key identifiers provided in the request, these are the ones - // which are authorized to remain connected. - // This is deprecated. Use authorized_downstream_workers instead. This - // should be removed in version 0.15.0. - AuthorizedWorkerList authorized_workers = 50 [deprecated = true]; - // Of the downstream workers in the request, these are the ones - // which are authorized to remain connected. - AuthorizedDownstreamWorkerList authorized_downstream_workers = 51; + // which are authorized to remain connected. Can be removed after 0.20.0. + AuthorizedDownstreamWorkerList authorized_downstream_workers = 51 [deprecated = true]; } // WorkerInfo contains information about workers for the HcpbWorkerResponse message @@ -202,3 +228,70 @@ message ListHcpbWorkersRequest {} message ListHcpbWorkersResponse { repeated WorkerInfo workers = 1; } + +message SessionInfoRequest { + // The ID of the worker making the request. + string worker_id = 1; // @gotags: `class:"public" eventstream:"observation"` + + // The sessions which this worker wants to report the status of. + repeated JobStatus sessions = 2; +} + +message SessionInfoResponse { + // List of sessions and the expected state changes. + repeated JobChangeRequest session_change_requests = 1; +} + +message RoutingInfoRequest { + // The ID of the worker making the request. + string worker_id = 1; // @gotags: `class:"public" eventstream:"observation"` + + // Tags read from the workers configuration. Only set if the tags require updating. + repeated servers.v1.TagPair tags = 2; + + // Whether the tags should be updated or not. + bool update_tags = 3; + + // The worker key identifiers for downstream workers for which there + // is not a known worker id mapping for them yet. + repeated string connected_unmapped_worker_key_identifiers = 4; + + // The worker public ids of all downstreams connected to this worker if known. + // While there may be workers with key ids in the connected_worker_key_identifiers + // list and their public ids in this list, once the requesting worker is aware + // of the association, it should only populate this field. + repeated string connected_worker_public_ids = 5; + + // The local_storage_state indicates the state of the local disk space of the worker. + // Possible values are: + // - available: The worker local storage state is at an acceptable state + // - low storage: The worker is below the minimum threshold for local storage + // - critically low storage: The worker local storage state is below the critical minimum threshold for local storage + // - out of storage: The worker is out of local disk space + // - not configured: The worker does not have a local storage path configured + // - unknown: The default local storage state of a worker. Used when the local storage state of a worker is not yet known + string local_storage_state = 6; // @gotags: `class:"public" eventstream:"observation" + + // StorageBucketCredentialStates is a map where the key is a storage bucket id + // and the value contains the current state of the storage bucket. + map storage_bucket_credential_states = 7; // @gotags: `class:"public" eventstream:"observation"` +} + +message RoutingInfoResponse { + // UpstreamServer currently returns the controller address in the StatusResponse. + repeated UpstreamServer calculated_upstreams = 1; + + // Of the downstream workers in the request, these are the ones + // which are authorized to remain connected. + AuthorizedDownstreamWorkerList authorized_downstream_workers = 2; +} + +message StatisticsRequest { + // The ID of the worker making the request. + string worker_id = 1; // @gotags: `class:"public" eventstream:"observation"` + + // The statistics of the sessions managed by this worker + repeated SessionStatistics sessions = 2; +} + +message StatisticsResponse {} diff --git a/internal/proto/controller/servers/v1/servers.proto b/internal/proto/controller/servers/v1/servers.proto index c04965387e..3c826443c5 100644 --- a/internal/proto/controller/servers/v1/servers.proto +++ b/internal/proto/controller/servers/v1/servers.proto @@ -15,8 +15,11 @@ message TagPair { string value = 2; // @gotags: `class:"public"` } -// ServerWorkerStatus is the new message used in place of Server to relay status request info. +// ServerWorkerStatus is a legacy message used by the old expensive Status RPC. +// It can be removed after 0.20.0. message ServerWorkerStatus { + option deprecated = true; + // Id of the worker. string public_id = 10; // @gotags: `class:"public" eventstream:"observation"` diff --git a/internal/server/repository_worker.go b/internal/server/repository_worker.go index 576313fb6e..d98ae58ee8 100644 --- a/internal/server/repository_worker.go +++ b/internal/server/repository_worker.go @@ -309,18 +309,12 @@ func (r *Repository) UpsertWorkerStatus(ctx context.Context, worker *Worker, opt switch { case worker == nil: return nil, errors.New(ctx, errors.InvalidParameter, op, "worker is nil") - case worker.GetAddress() == "": - return nil, errors.New(ctx, errors.InvalidParameter, op, "worker reported address is empty") case worker.ScopeId == "": return nil, errors.New(ctx, errors.InvalidParameter, op, "scope id is empty") case worker.PublicId != "": return nil, errors.New(ctx, errors.InvalidParameter, op, "worker id is not empty") - case worker.GetName() == "" && opts.withKeyId == "": - return nil, errors.New(ctx, errors.InvalidParameter, op, "worker keyId and reported name are both empty; one is required") - case worker.OperationalState == "": - return nil, errors.New(ctx, errors.InvalidParameter, op, "worker operational state is empty") - case worker.LocalStorageState == "": - return nil, errors.New(ctx, errors.InvalidParameter, op, "worker local storage state is empty") + case opts.withKeyId == "" && opts.withPublicId == "": + return nil, errors.New(ctx, errors.InvalidParameter, op, "worker key id and public id are both empty; one is required") } var workerId string @@ -333,16 +327,6 @@ func (r *Repository) UpsertWorkerStatus(ctx context.Context, worker *Worker, opt if err != nil || workerId == "" { return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error finding worker by keyId")) } - default: - // generating the worker id based off of the scope and name ensures - // that if 2 kms workers are making requests with the same name they - // are treated as the same worker. Allowing this only for kms workers - // also ensures that we maintain the unique name constraint between pki - // workers and kms workers. - workerId, err = NewWorkerIdFromScopeAndName(ctx, worker.GetScopeId(), worker.GetName()) - if err != nil || workerId == "" { - return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error creating a worker id")) - } } var ret *Worker @@ -377,29 +361,6 @@ func (r *Repository) UpsertWorkerStatus(ctx context.Context, worker *Worker, opt default: return errors.New(ctx, errors.MultipleRecords, op, fmt.Sprintf("multiple records found when updating worker with id %q", workerClone.GetPublicId())) } - - case workerClone.GetName() != "": - workerClone.Type = KmsWorkerType.String() - workerCreateConflict := &db.OnConflict{ - Target: db.Columns{"public_id"}, - Action: append(db.SetColumns([]string{"address", "release_version", "operational_state", "local_storage_state"}), - db.SetColumnValues(map[string]any{"last_status_time": "now()"})...), - } - var withRowsAffected int64 - err := w.Create(ctx, workerClone, db.WithOnConflict(workerCreateConflict), db.WithReturnRowsAffected(&withRowsAffected), - // The intent of this WithWhere option is to operate with the OnConflict such that the action - // taken by the OnConflict only applies if the conflict is on a row that is returned by this where - // statement, otherwise it should error out. - db.WithWhere("server_worker.type = 'kms'")) - if err == nil && workerClone.Description != worker.Description { - _, err = w.Update(ctx, workerClone, []string{"description"}, nil) - } - switch { - case err != nil: - return errors.Wrap(ctx, err, op, errors.WithMsg("error creating a worker")) - case withRowsAffected == 0: - return errors.New(ctx, errors.NotUnique, op, "error updating worker") - } } // If we've been told to update tags, we need to clean out old diff --git a/internal/server/rewrapping.go b/internal/server/rewrapping.go index 177da74eaf..69e31909d3 100644 --- a/internal/server/rewrapping.go +++ b/internal/server/rewrapping.go @@ -142,9 +142,6 @@ func workerAuthServerLedActivationTokenRewrapFn(ctx context.Context, dataKeyVers if err != nil { return errors.Wrap(ctx, err, op, errors.WithMsg("failed to fetch kms wrapper for rewrapping")) } - if err != nil { - return errors.Wrap(ctx, err, op, errors.WithMsg("failed to retrieve updated key version id")) - } for _, token := range tokens { if err := token.decrypt(ctx, wrapper); err != nil { return errors.Wrap(ctx, err, op, errors.WithMsg("failed to decrypt activation token")) diff --git a/internal/server/worker.go b/internal/server/worker.go index 307f6343d6..73233ed7c5 100644 --- a/internal/server/worker.go +++ b/internal/server/worker.go @@ -132,8 +132,15 @@ type Worker struct { RemoteStorageStates map[string]*plugin.StorageBucketCredentialState `gorm:"-"` } -// NewWorker returns a new Worker. Valid options are WithName, WithDescription -// WithAddress, and WithWorkerTags. All other options are ignored. This does +// NewWorker returns a new Worker. Valid options are: +// - WithName +// - WithDescription +// - WithAddress +// - WithWorkerTags +// - WithReleaseVersion +// - WithOperationalState +// - WithLocalStorageState +// All other options are ignored. This does // not set any of the worker reported values. func NewWorker(scopeId string, opt ...Option) *Worker { opts := GetOpts(opt...) diff --git a/internal/session/repository_connection.go b/internal/session/repository_connection.go index 339e36dde0..71c529ed49 100644 --- a/internal/session/repository_connection.go +++ b/internal/session/repository_connection.go @@ -84,8 +84,8 @@ func (r *ConnectionRepository) list(ctx context.Context, resources any, where st return nil } -func (r *ConnectionRepository) updateBytesUpBytesDown(ctx context.Context, conns ...*Connection) error { - const op = "session.(ConnectionRepository).updateBytesUpBytesDown" +func (r *ConnectionRepository) UpdateBytesUpBytesDown(ctx context.Context, conns ...*Connection) error { + const op = "session.(ConnectionRepository).UpdateBytesUpBytesDown" if len(conns) == 0 { return nil } diff --git a/internal/session/repository_connection_test.go b/internal/session/repository_connection_test.go index 3a047a9ce4..cc5ea89942 100644 --- a/internal/session/repository_connection_test.go +++ b/internal/session/repository_connection_test.go @@ -544,7 +544,7 @@ func TestUpdateBytesUpDown(t *testing.T) { } // Update bytes up and down. - require.NoError(t, connRepo.updateBytesUpBytesDown(ctx, conns...)) + require.NoError(t, connRepo.UpdateBytesUpBytesDown(ctx, conns...)) // Assert that the bytes up and down values have been persisted. for i := 0; i < len(conns); i++ { @@ -587,7 +587,7 @@ func TestUpdateBytesUpDown(t *testing.T) { conns2[i].BytesUp = rand.Int63() conns2[i].BytesDown = rand.Int63() } - require.NoError(t, connRepo.updateBytesUpBytesDown(ctx, conns2...)) + require.NoError(t, connRepo.UpdateBytesUpBytesDown(ctx, conns2...)) // BytesUp and BytesDown values should be set to the old ones. for i := 0; i < len(conns); i++ { diff --git a/internal/session/service_worker_status_report.go b/internal/session/service_worker_status_report.go index 1a50b915f0..bf55d00a6a 100644 --- a/internal/session/service_worker_status_report.go +++ b/internal/session/service_worker_status_report.go @@ -43,11 +43,6 @@ func WorkerStatusReport(ctx context.Context, repo *Repository, connRepo *Connect } } - err := connRepo.updateBytesUpBytesDown(ctx, reportedConnections...) - if err != nil { - return nil, errors.New(ctx, errors.Internal, op, fmt.Sprintf("failed to update bytes up and down for worker reported connections: %v", err)) - } - notActive, err := repo.CheckIfNotActive(ctx, reportedSessions) if err != nil { return nil, errors.New(ctx, errors.Internal, op, fmt.Sprintf("Error checking session state for worker %s: %v", workerId, err)) diff --git a/internal/tests/cluster/multi_controller_worker_test.go b/internal/tests/cluster/multi_controller_worker_test.go index 80b3c6613f..2e67ed43fb 100644 --- a/internal/tests/cluster/multi_controller_worker_test.go +++ b/internal/tests/cluster/multi_controller_worker_test.go @@ -127,7 +127,7 @@ func TestWorkerAppendInitialUpstreams(t *testing.T) { case <-cancelCtx.Done(): require.FailNow("No worker found after 10 seconds") } - successSent := w1.Worker().LastStatusSuccess() + successSent := w1.Worker().LastRoutingInfoSuccess() if successSent != nil { break } @@ -135,12 +135,12 @@ func TestWorkerAppendInitialUpstreams(t *testing.T) { helper.ExpectWorkers(t, c1, w1) // Upstreams should be equivalent to the controller cluster addr after status updates - assert.Equal(c1.ClusterAddrs(), w1.Worker().LastStatusSuccess().LastCalculatedUpstreams) + assert.Equal(c1.ClusterAddrs(), w1.Worker().LastRoutingInfoSuccess().LastCalculatedUpstreams) // Bring down the controller c1.Shutdown() time.Sleep(3 * time.Second) // Wait a little longer than the grace period // Upstreams should now match initial upstreams - assert.True(strutil.EquivalentSlices(initialUpstreams, w1.Worker().LastStatusSuccess().LastCalculatedUpstreams)) + assert.True(strutil.EquivalentSlices(initialUpstreams, w1.Worker().LastRoutingInfoSuccess().LastCalculatedUpstreams)) } diff --git a/version/feature_manager.go b/version/feature_manager.go index 18c29ee199..9885a628f5 100644 --- a/version/feature_manager.go +++ b/version/feature_manager.go @@ -25,6 +25,7 @@ const ( PluginDelete LocalStorageState StorageBucketCredentialState + MultipleWorkerStatusRpcs ) var featureMap map[Feature]MetadataConstraint @@ -51,14 +52,14 @@ func init() { Add constraints here following this format after adding a Feature to the Feature iota: featureMap[FEATURE] = MetadataConstraint{ MetaInfo: []Metadata{OSS, HCP}, - Constraints: mustNewConstraints(">= 0.1.0"), // This feature exists at 0.1.0 and above + Constraints: gvers.MustConstraints(gvers.NewConstraint(">= 0.1.0")), // This feature exists at 0.1.0 and above } */ featureMap[IncludeStatusInCli] = MetadataConstraint{ - Constraints: mustNewConstraints("< 0.14.0"), + Constraints: gvers.MustConstraints(gvers.NewConstraint("< 0.14.0")), } featureMap[CredentialLibraryVaultSubtype] = MetadataConstraint{ - Constraints: mustNewConstraints("< 0.14.0"), + Constraints: gvers.MustConstraints(gvers.NewConstraint("< 0.14.0")), } // UseTargetIdForHostId supports old CLI clients that are unaware of host-sourceless targets, @@ -66,45 +67,42 @@ func init() { // and the SessionAuthorizationData so the CLI can properly build the ssh command // when calling "boundary connect ssh..." featureMap[UseTargetIdForHostId] = MetadataConstraint{ - Constraints: mustNewConstraints("< 0.14.0"), + Constraints: gvers.MustConstraints(gvers.NewConstraint("< 0.14.0")), } // RequireVersionInWorkerInfo allows us to take action on various workers // based on their version, e.g. to prevent incompatibilities featureMap[RequireVersionInWorkerInfo] = MetadataConstraint{ - Constraints: mustNewConstraints(">= 0.13.0"), + Constraints: gvers.MustConstraints(gvers.NewConstraint(">= 0.13.0")), } featureMap[SshSessionRecording] = MetadataConstraint{ - Constraints: mustNewConstraints(">= 0.13.0"), + Constraints: gvers.MustConstraints(gvers.NewConstraint(">= 0.13.0")), } // Warn until 0.16 about using the now-deprecated id field in grants; after // that disallow it featureMap[SupportIdInGrants] = MetadataConstraint{ - Constraints: mustNewConstraints("< 0.15.0"), + Constraints: gvers.MustConstraints(gvers.NewConstraint("< 0.15.0")), } // PluginDelete supports calling DeleteObjects on the Storage Plugin featureMap[PluginDelete] = MetadataConstraint{ - Constraints: mustNewConstraints(">= 0.15.0"), + Constraints: gvers.MustConstraints(gvers.NewConstraint(">= 0.15.0")), } // Worker supports reporting local storage state featureMap[LocalStorageState] = MetadataConstraint{ - Constraints: mustNewConstraints(">= 0.16.0"), + Constraints: gvers.MustConstraints(gvers.NewConstraint(">= 0.16.0")), } // Worker supports reporting the state of storage bucket credentials featureMap[StorageBucketCredentialState] = MetadataConstraint{ - Constraints: mustNewConstraints(">= 0.17.0"), + Constraints: gvers.MustConstraints(gvers.NewConstraint(">= 0.17.0")), } -} -func mustNewConstraints(v string) gvers.Constraints { - c, err := gvers.NewConstraint(v) - if err != nil { - panic(err) + // Worker uses multiple RPCs to report status + featureMap[MultipleWorkerStatusRpcs] = MetadataConstraint{ + Constraints: gvers.MustConstraints(gvers.NewConstraint(">= 0.19.0")), } - return c } // Check returns a bool indicating if a version meets the constraints