diff --git a/src/cmd/cli/command/compose.go b/src/cmd/cli/command/compose.go index 4aeaade40..99ef56157 100644 --- a/src/cmd/cli/command/compose.go +++ b/src/cmd/cli/command/compose.go @@ -423,6 +423,7 @@ func makeComposeLogsCmd() *cobra.Command { var utc, _ = cmd.Flags().GetBool("utc") var verbose, _ = cmd.Flags().GetBool("verbose") var filter, _ = cmd.Flags().GetString("filter") + var until, _ = cmd.Flags().GetString("until") if !cmd.Flags().Changed("verbose") { verbose = true // default verbose for explicit tail command @@ -432,17 +433,27 @@ func makeComposeLogsCmd() *cobra.Command { os.Setenv("TZ", "") // used by Go's "time" package, see https://pkg.go.dev/time#Location } - ts, err := cli.ParseTimeOrDuration(since, time.Now()) + now := time.Now() + sinceTs, err := cli.ParseTimeOrDuration(since, now) if err != nil { - return fmt.Errorf("invalid duration or time: %w", err) + return fmt.Errorf("invalid 'since' duration or time: %w", err) } + sinceTs = sinceTs.UTC() + untilTs, err := cli.ParseTimeOrDuration(until, now) + if err != nil { + return fmt.Errorf("invalid 'until' duration or time: %w", err) + } + untilTs = untilTs.UTC() - ts = ts.UTC() - sinceStr := "" - if pkg.IsValidTime(ts) { - sinceStr = " since " + ts.Format(time.RFC3339Nano) + " " + rangeStr := "" + if pkg.IsValidTime(sinceTs) { + rangeStr = " since " + sinceTs.Format(time.RFC3339Nano) } - term.Infof("Showing logs%s; press Ctrl+C to stop:", sinceStr) + if pkg.IsValidTime(untilTs) { + rangeStr += " until " + untilTs.Format(time.RFC3339Nano) + } + term.Infof("Showing logs%s; press Ctrl+C to stop:", rangeStr) + services := args if len(name) > 0 { services = append(args, strings.Split(name, ",")...) // backwards compat @@ -465,7 +476,8 @@ func makeComposeLogsCmd() *cobra.Command { LogType: logType, Raw: raw, Services: services, - Since: ts, + Since: sinceTs, + Until: untilTs, Verbose: verbose, } @@ -478,7 +490,8 @@ func makeComposeLogsCmd() *cobra.Command { logsCmd.Flags().Bool("follow", false, "follow log output") // NOTE: -f is already used by --file logsCmd.Flags().MarkHidden("follow") // TODO: implement this logsCmd.Flags().BoolP("raw", "r", false, "show raw (unparsed) logs") - logsCmd.Flags().StringP("since", "S", "", "show logs since duration/time") + logsCmd.Flags().String("since", "", "show logs since duration/time") + logsCmd.Flags().String("until", "", "show logs until duration/time") logsCmd.Flags().Bool("utc", false, "show logs in UTC timezone (ie. TZ=UTC)") logsCmd.Flags().Var(&logType, "type", fmt.Sprintf(`show logs of type; one of %v`, logs.AllLogTypes)) logsCmd.Flags().String("filter", "", "only show logs containing given text; case-insensitive") diff --git a/src/pkg/cli/client/byoc/aws/byoc.go b/src/pkg/cli/client/byoc/aws/byoc.go index 589c2984e..617ea3a1b 100644 --- a/src/pkg/cli/client/byoc/aws/byoc.go +++ b/src/pkg/cli/client/byoc/aws/byoc.go @@ -596,67 +596,89 @@ func (b *ByocAws) CreateUploadURL(ctx context.Context, req *defangv1.UploadURLRe }, nil } -func (b *ByocAws) Query(ctx context.Context, req *defangv1.DebugRequest) error { +func (b *ByocAws) QueryForDebug(ctx context.Context, req *defangv1.DebugRequest) error { + // tailRequest := &defangv1.TailRequest{ + // Etag: req.Etag, + // Project: req.Project, + // Services: req.Services, + // Since: req.Since, + // Until: req.Until, + // } + // The LogStreamNamePrefix filter can only be used with one service name var service string if len(req.Services) == 1 { service = req.Services[0] } - since := b.cdStart // TODO: get start time from req.Etag - if since.IsZero() { - since = time.Now().Add(-time.Hour) // TODO: get start time from req + start := b.cdStart // TODO: get start time from req.Etag + if req.Since.IsValid() { + start = req.Since.AsTime() + } else if start.IsZero() { + start = time.Now().Add(-time.Hour) } - // get stack information + end := time.Now() + if req.Until.IsValid() { + end = req.Until.AsTime() + } + + // get stack information (for log group ARN) err := b.driver.FillOutputs(ctx) if err != nil { return AnnotateAwsError(err) } - const maxQuerySizePerLogGroup = 128 * 1024 // 128KB (to stay well below the 1MB gRPC payload limit) - // Gather logs from the CD task, kaniko, ECS events, and all services + evtsChan, errsChan := ecs.QueryLogGroups(ctx, start, end, b.getLogGroupInputs(req.Etag, req.Project, service, "", logs.LogTypeAll)...) + if evtsChan == nil { + return <-errsChan + } + + const maxQuerySizePerLogGroup = 128 * 1024 // 128KB per LogGroup (to stay well below the 1MB gRPC payload limit) + sb := strings.Builder{} - for _, lgi := range b.getLogGroupInputs(req.Etag, req.Project, service, "", logs.LogTypeAll) { - parseECSEventRecords := strings.HasSuffix(lgi.LogGroupARN, "/ecs") - if err := ecs.Query(ctx, lgi, since, time.Now(), func(logEvents []ecs.LogEvent) error { - for _, event := range logEvents { - msg := term.StripAnsi(*event.Message) - if parseECSEventRecords { - if event, err := ecs.ParseECSEvent([]byte(msg)); err == nil { - // TODO: once we know the AWS deploymentId from TaskStateChangeEvent detail.startedBy, we can do a 2nd query to filter by deploymentId - if event.Etag() != "" && req.Etag != "" && event.Etag() != req.Etag { - continue - } - if event.Service() != "" && len(req.Services) > 0 && !slices.Contains(req.Services, event.Service()) { - continue - } - // This matches the status messages in the Defang Playground Loki logs - sb.WriteString("status=") - sb.WriteString(event.Status()) - sb.WriteByte('\n') +loop: + for { + select { + case event, ok := <-evtsChan: + if !ok { + break loop + } + parseECSEventRecords := strings.HasSuffix(*event.LogGroupIdentifier, "/ecs") + if parseECSEventRecords { + if event, err := ecs.ParseECSEvent([]byte(*event.Message)); err == nil { + // TODO: once we know the AWS deploymentId from TaskStateChangeEvent detail.startedBy, we can do a 2nd query to filter by deploymentId + if event.Etag() != "" && req.Etag != "" && event.Etag() != req.Etag { continue } - } - sb.WriteString(msg) - sb.WriteByte('\n') - if sb.Len() > maxQuerySizePerLogGroup { - return errors.New("query result was truncated") + if event.Service() != "" && len(req.Services) > 0 && !slices.Contains(req.Services, event.Service()) { + continue + } + // This matches the status messages in the Defang Playground Loki logs + sb.WriteString("status=") + sb.WriteString(event.Status()) + sb.WriteByte('\n') + continue } } - return nil - }); err != nil { + msg := term.StripAnsi(*event.Message) + sb.WriteString(msg) + sb.WriteByte('\n') + if sb.Len() > maxQuerySizePerLogGroup { // FIXME: this limit was supposed to be per LogGroup + term.Warn("Query result was truncated") + break loop + } + case err := <-errsChan: term.Warn("CloudWatch query error:", AnnotateAwsError(err)) // continue reading other log groups } } - req.Logs = sb.String() return nil } -func (b *ByocAws) Follow(ctx context.Context, req *defangv1.TailRequest) (client.ServerStream[defangv1.TailResponse], error) { +func (b *ByocAws) QueryLogs(ctx context.Context, req *defangv1.TailRequest) (client.ServerStream[defangv1.TailResponse], error) { // FillOutputs is needed to get the CD task ARN or the LogGroup ARNs if err := b.driver.FillOutputs(ctx); err != nil { return nil, AnnotateAwsError(err) @@ -673,11 +695,11 @@ func (b *ByocAws) Follow(ctx context.Context, req *defangv1.TailRequest) (client // * Etag, service: tail that task/service var err error var taskArn ecs.TaskArn - var eventStream ecs.EventStream + var tailStream ecs.LiveTailStream stopWhenCDTaskDone := false logType := logs.LogType(req.LogType) if etag != "" && !pkg.IsValidRandomID(etag) { // Assume invalid "etag" is a task ID - eventStream, err = b.driver.TailTaskID(ctx, etag) + tailStream, err = b.driver.TailTaskID(ctx, etag) taskArn, _ = b.driver.GetTaskArn(etag) term.Debugf("Tailing task %s", *taskArn) etag = "" // no need to filter by etag @@ -687,7 +709,14 @@ func (b *ByocAws) Follow(ctx context.Context, req *defangv1.TailRequest) (client if len(req.Services) == 1 { service = req.Services[0] } - eventStream, err = ecs.TailLogGroups(ctx, req.Since.AsTime(), b.getLogGroupInputs(etag, req.Project, service, req.Pattern, logType)...) + var start, end time.Time + if req.Since.IsValid() { + start = req.Since.AsTime() + } + if req.Until.IsValid() { + end = req.Until.AsTime() + } + tailStream, err = ecs.QueryAndTailLogGroups(ctx, start, end, b.getLogGroupInputs(etag, req.Project, service, req.Pattern, logType)...) taskArn = b.cdTaskArn } if err != nil { @@ -709,7 +738,7 @@ func (b *ByocAws) Follow(ctx context.Context, req *defangv1.TailRequest) (client }() } - return newByocServerStream(ctx, eventStream, etag, req.GetServices(), b), nil + return newByocServerStream(ctx, tailStream, etag, req.GetServices(), b), nil } func (b *ByocAws) makeLogGroupARN(name string) string { diff --git a/src/pkg/cli/client/byoc/aws/byoc_integration_test.go b/src/pkg/cli/client/byoc/aws/byoc_integration_test.go index 8769ad317..36b3ed213 100644 --- a/src/pkg/cli/client/byoc/aws/byoc_integration_test.go +++ b/src/pkg/cli/client/byoc/aws/byoc_integration_test.go @@ -40,7 +40,7 @@ func TestDeploy(t *testing.T) { func TestTail(t *testing.T) { b := NewByocProvider(ctx, "TestTail") - ss, err := b.Follow(context.Background(), &defangv1.TailRequest{Project: "byoc_integration_test"}) + ss, err := b.QueryLogs(context.Background(), &defangv1.TailRequest{Project: "byoc_integration_test"}) if err != nil { // the only acceptable error is "unauthorized" if connect.CodeOf(err) == connect.CodeUnauthenticated { diff --git a/src/pkg/cli/client/byoc/aws/stream.go b/src/pkg/cli/client/byoc/aws/stream.go index ad5cb7f0e..e97f8fbd0 100644 --- a/src/pkg/cli/client/byoc/aws/stream.go +++ b/src/pkg/cli/client/byoc/aws/stream.go @@ -24,12 +24,12 @@ type byocServerStream struct { etag string response *defangv1.TailResponse services []string - stream ecs.EventStream + stream ecs.LiveTailStream ecsEventsHandler ECSEventHandler } -func newByocServerStream(ctx context.Context, stream ecs.EventStream, etag string, services []string, ecsEventHandler ECSEventHandler) *byocServerStream { +func newByocServerStream(ctx context.Context, stream ecs.LiveTailStream, etag string, services []string, ecsEventHandler ECSEventHandler) *byocServerStream { return &byocServerStream{ ctx: ctx, etag: etag, diff --git a/src/pkg/cli/client/byoc/do/byoc.go b/src/pkg/cli/client/byoc/do/byoc.go index 355bba238..2832d3912 100644 --- a/src/pkg/cli/client/byoc/do/byoc.go +++ b/src/pkg/cli/client/byoc/do/byoc.go @@ -369,7 +369,7 @@ func (b *ByocDo) PutConfig(ctx context.Context, config *defangv1.PutConfigReques return err } -func (b *ByocDo) Follow(ctx context.Context, req *defangv1.TailRequest) (client.ServerStream[defangv1.TailResponse], error) { +func (b *ByocDo) QueryLogs(ctx context.Context, req *defangv1.TailRequest) (client.ServerStream[defangv1.TailResponse], error) { var appID, deploymentID string if req.Etag != "" && req.Etag == b.cdEtag { @@ -598,7 +598,7 @@ func (s *subscribeStream) Close() error { return nil } -func (b *ByocDo) Query(ctx context.Context, req *defangv1.DebugRequest) error { +func (b *ByocDo) QueryForDebug(ctx context.Context, req *defangv1.DebugRequest) error { return client.ErrNotImplemented("AI debugging is not yet supported for DO BYOC") } diff --git a/src/pkg/cli/client/byoc/gcp/byoc.go b/src/pkg/cli/client/byoc/gcp/byoc.go index edd81197f..545ec4e96 100644 --- a/src/pkg/cli/client/byoc/gcp/byoc.go +++ b/src/pkg/cli/client/byoc/gcp/byoc.go @@ -480,7 +480,7 @@ func (b *ByocGcp) Subscribe(ctx context.Context, req *defangv1.SubscribeRequest) return subscribeStream, nil } -func (b *ByocGcp) Follow(ctx context.Context, req *defangv1.TailRequest) (client.ServerStream[defangv1.TailResponse], error) { +func (b *ByocGcp) QueryLogs(ctx context.Context, req *defangv1.TailRequest) (client.ServerStream[defangv1.TailResponse], error) { if b.cdExecution != "" && req.Etag == b.cdExecution { // Only follow CD log, we need to subscribe to cd activities to detect when the job is done subscribeStream, err := NewSubscribeStream(ctx, b.driver) if err != nil { @@ -488,7 +488,7 @@ func (b *ByocGcp) Follow(ctx context.Context, req *defangv1.TailRequest) (client } subscribeStream.AddJobExecutionUpdate(path.Base(b.cdExecution)) var since time.Time - if req.Since != nil { + if req.Since.IsValid() { since = req.Since.AsTime() } subscribeStream.Start(since) @@ -520,10 +520,14 @@ func (b *ByocGcp) Follow(ctx context.Context, req *defangv1.TailRequest) (client } startTime := time.Now() - if req.Since != nil { + if req.Since.IsValid() { startTime = req.Since.AsTime() } - if req.Since != nil || req.Etag != "" { + var endTime time.Time + if req.Until.IsValid() { + endTime = req.Until.AsTime() + } + if req.Since.IsValid() || req.Etag != "" { execName := path.Base(b.cdExecution) if execName == "." { execName = "" @@ -541,6 +545,7 @@ func (b *ByocGcp) Follow(ctx context.Context, req *defangv1.TailRequest) (client logStream.AddServiceLog(req.Project, etag, req.Services) // Service logs } logStream.AddSince(startTime) + logStream.AddUntil(endTime) logStream.AddFilter(req.Pattern) } logStream.Start(startTime) @@ -648,10 +653,13 @@ func (b *ByocGcp) PutConfig(ctx context.Context, req *defangv1.PutConfigRequest) } func (b *ByocGcp) createDeploymentLogQuery(req *defangv1.DebugRequest) string { - var since time.Time - if req.Since != nil { + var since, until time.Time + if req.Since.IsValid() { since = req.Since.AsTime() } + if req.Until.IsValid() { + until = req.Until.AsTime() + } query := NewLogQuery(b.driver.ProjectId) if b.cdExecution != "" { query.AddJobExecutionQuery(path.Base(b.cdExecution)) @@ -662,6 +670,7 @@ func (b *ByocGcp) createDeploymentLogQuery(req *defangv1.DebugRequest) string { query.AddServiceLogQuery(req.Project, req.Etag, req.Services) // Cloudrun service logs query.AddCloudBuildLogQuery(req.Project, req.Etag, req.Services) // CloudBuild logs query.AddSince(since) + query.AddUntil(until) // Service status updates query.AddJobStatusUpdateRequestQuery(req.Project, req.Etag, req.Services) @@ -735,7 +744,7 @@ func (b *ByocGcp) query(ctx context.Context, query string) ([]*loggingpb.LogEntr return entries, nil } -func (b *ByocGcp) Query(ctx context.Context, req *defangv1.DebugRequest) error { +func (b *ByocGcp) QueryForDebug(ctx context.Context, req *defangv1.DebugRequest) error { logEntries, err := b.query(ctx, b.createDeploymentLogQuery(req)) if err != nil { return annotateGcpError(err) diff --git a/src/pkg/cli/client/byoc/gcp/query.go b/src/pkg/cli/client/byoc/gcp/query.go index 4ffe7ebf7..69282ff3e 100644 --- a/src/pkg/cli/client/byoc/gcp/query.go +++ b/src/pkg/cli/client/byoc/gcp/query.go @@ -271,6 +271,13 @@ func (q *Query) AddSince(since time.Time) { q.baseQuery += fmt.Sprintf(` AND (timestamp >= %q)`, since.UTC().Format(time.RFC3339Nano)) } +func (q *Query) AddUntil(until time.Time) { + if until.IsZero() || until.Unix() <= 0 { + return + } + q.baseQuery += fmt.Sprintf(` AND (timestamp <= %q)`, until.UTC().Format(time.RFC3339Nano)) +} + func (q *Query) AddFilter(filter string) { if filter == "" { return diff --git a/src/pkg/cli/client/byoc/gcp/stream.go b/src/pkg/cli/client/byoc/gcp/stream.go index 84d59f078..ef4156587 100644 --- a/src/pkg/cli/client/byoc/gcp/stream.go +++ b/src/pkg/cli/client/byoc/gcp/stream.go @@ -206,6 +206,10 @@ func (s *LogStream) AddSince(start time.Time) { s.query.AddSince(start) } +func (s *LogStream) AddUntil(end time.Time) { + s.query.AddUntil(end) +} + func (s *LogStream) AddFilter(filter string) { s.query.AddFilter(filter) } diff --git a/src/pkg/cli/client/client.go b/src/pkg/cli/client/client.go index 06750916c..87a0782ce 100644 --- a/src/pkg/cli/client/client.go +++ b/src/pkg/cli/client/client.go @@ -9,13 +9,6 @@ import ( composeTypes "github.com/compose-spec/compose-go/v2/types" ) -type ServerStream[Res any] interface { - Close() error - Receive() bool - Msg() *Res - Err() error -} - type ProjectLoader interface { LoadProjectName(context.Context) (string, error) LoadProject(context.Context) (*composeTypes.Project, error) diff --git a/src/pkg/cli/client/playground.go b/src/pkg/cli/client/playground.go index a19d169cd..f5cc06367 100644 --- a/src/pkg/cli/client/playground.go +++ b/src/pkg/cli/client/playground.go @@ -63,7 +63,7 @@ func (g *PlaygroundProvider) Subscribe(ctx context.Context, req *defangv1.Subscr return g.GetController().Subscribe(ctx, connect.NewRequest(req)) } -func (g *PlaygroundProvider) Follow(ctx context.Context, req *defangv1.TailRequest) (ServerStream[defangv1.TailResponse], error) { +func (g *PlaygroundProvider) QueryLogs(ctx context.Context, req *defangv1.TailRequest) (ServerStream[defangv1.TailResponse], error) { return g.GetController().Tail(ctx, connect.NewRequest(req)) } @@ -121,7 +121,7 @@ func (g *PlaygroundProvider) AccountInfo(ctx context.Context) (AccountInfo, erro return PlaygroundAccountInfo{}, nil } -func (g *PlaygroundProvider) Query(ctx context.Context, req *defangv1.DebugRequest) error { +func (g *PlaygroundProvider) QueryForDebug(ctx context.Context, req *defangv1.DebugRequest) error { return nil } diff --git a/src/pkg/cli/client/provider.go b/src/pkg/cli/client/provider.go index b0a51ed7a..47a3a4de2 100644 --- a/src/pkg/cli/client/provider.go +++ b/src/pkg/cli/client/provider.go @@ -119,6 +119,13 @@ type PrepareDomainDelegationResponse struct { DelegationSetId string } +type ServerStream[Res any] interface { + Close() error + Receive() bool + Msg() *Res + Err() error +} + type Provider interface { AccountInfo(context.Context) (AccountInfo, error) BootstrapCommand(context.Context, BootstrapCommandRequest) (types.ETag, error) @@ -130,12 +137,12 @@ type Provider interface { Deploy(context.Context, *defangv1.DeployRequest) (*defangv1.DeployResponse, error) DelayBeforeRetry(context.Context) error Destroy(context.Context, *defangv1.DestroyRequest) (types.ETag, error) - Follow(context.Context, *defangv1.TailRequest) (ServerStream[defangv1.TailResponse], error) + QueryLogs(context.Context, *defangv1.TailRequest) (ServerStream[defangv1.TailResponse], error) GetProjectUpdate(context.Context, string) (*defangv1.ProjectUpdate, error) GetService(context.Context, *defangv1.GetRequest) (*defangv1.ServiceInfo, error) GetServices(context.Context, *defangv1.GetServicesRequest) (*defangv1.GetServicesResponse, error) ListConfig(context.Context, *defangv1.ListConfigsRequest) (*defangv1.Secrets, error) - Query(context.Context, *defangv1.DebugRequest) error + QueryForDebug(context.Context, *defangv1.DebugRequest) error Preview(context.Context, *defangv1.DeployRequest) (*defangv1.DeployResponse, error) PutConfig(context.Context, *defangv1.PutConfigRequest) error RemoteProjectName(context.Context) (string, error) diff --git a/src/pkg/cli/debug.go b/src/pkg/cli/debug.go index 77e8931c2..695d161cb 100644 --- a/src/pkg/cli/debug.go +++ b/src/pkg/cli/debug.go @@ -9,6 +9,7 @@ import ( "time" "github.com/AlecAivazis/survey/v2" + "github.com/DefangLabs/defang/src/pkg" "github.com/DefangLabs/defang/src/pkg/cli/client" "github.com/DefangLabs/defang/src/pkg/cli/compose" "github.com/DefangLabs/defang/src/pkg/term" @@ -35,6 +36,7 @@ type DebugConfig struct { Project *compose.Project Provider client.Provider Since time.Time + Until time.Time } func InteractiveDebugDeployment(ctx context.Context, client client.FabricClient, debugConfig DebugConfig) error { @@ -95,18 +97,22 @@ func DebugDeployment(ctx context.Context, client client.FabricClient, debugConfi return ErrDryRun } - var sinceTime *timestamppb.Timestamp = nil - if !debugConfig.Since.IsZero() { + var sinceTime, untilTime *timestamppb.Timestamp + if pkg.IsValidTime(debugConfig.Since) { sinceTime = timestamppb.New(debugConfig.Since) } + if pkg.IsValidTime(debugConfig.Until) { + untilTime = timestamppb.New(debugConfig.Until) + } req := defangv1.DebugRequest{ Etag: debugConfig.Etag, Files: files, Project: debugConfig.Project.Name, Services: debugConfig.FailedServices, Since: sinceTime, + Until: untilTime, } - err := debugConfig.Provider.Query(ctx, &req) + err := debugConfig.Provider.QueryForDebug(ctx, &req) if err != nil { return err } diff --git a/src/pkg/cli/debug_test.go b/src/pkg/cli/debug_test.go index 33e20f450..41e4e94d6 100644 --- a/src/pkg/cli/debug_test.go +++ b/src/pkg/cli/debug_test.go @@ -41,7 +41,7 @@ type MustHaveProjectNameQueryProvider struct { client.Provider } -func (m MustHaveProjectNameQueryProvider) Query(ctx context.Context, req *defangv1.DebugRequest) error { +func (m MustHaveProjectNameQueryProvider) QueryForDebug(ctx context.Context, req *defangv1.DebugRequest) error { if req.Project == "" { return errors.New("project name is missing") } diff --git a/src/pkg/cli/tail.go b/src/pkg/cli/tail.go index 433dd0f28..4a60985d4 100644 --- a/src/pkg/cli/tail.go +++ b/src/pkg/cli/tail.go @@ -67,20 +67,24 @@ type EndLogConditional struct { type TailDetectStopEventFunc func(services []string, host string, eventlog string) bool type TailOptions struct { - Services []string + EndEventDetectFunc TailDetectStopEventFunc // Deprecated: use Subscribe instead #851 Etag types.ETag - Since time.Time + Filter string + LogType logs.LogType Raw bool - EndEventDetectFunc TailDetectStopEventFunc // Deprecated: use Subscribe instead #851 + Services []string + Since time.Time + Until time.Time Verbose bool - LogType logs.LogType - Filter string } func (to TailOptions) String() string { - cmd := "tail --since=" + to.Since.UTC().Format(time.RFC3339Nano) - if len(to.Services) > 0 { - cmd += " --name=" + strings.Join(to.Services, ",") + cmd := " --since=" + to.Since.UTC().Format(time.RFC3339Nano) + if to.Until.IsZero() { + // No --until implies --follow + cmd += "tail" + cmd + } else { + cmd = "logs" + cmd + " --until=" + to.Until.UTC().Format(time.RFC3339Nano) } if to.Etag != "" { cmd += " --etag=" + to.Etag @@ -98,6 +102,9 @@ func (to TailOptions) String() string { if to.Filter != "" { cmd += fmt.Sprintf(" --filter=%q", to.Filter) } + if len(to.Services) > 0 { + cmd += " " + strings.Join(to.Services, " ") + } return cmd } @@ -208,12 +215,21 @@ func isTransientError(err error) bool { } func tail(ctx context.Context, provider client.Provider, projectName string, options TailOptions) error { - var since *timestamppb.Timestamp + var since, until *timestamppb.Timestamp if pkg.IsValidTime(options.Since) { since = timestamppb.New(options.Since) } else { options.Since = time.Now() // this is used to continue from the last timestamp } + if pkg.IsValidTime(options.Until) { + until = timestamppb.New(options.Until) + // If the user specifies a deadline in the future, we should respect it + if options.Until.After(time.Now()) { + var cancel context.CancelFunc + ctx, cancel = context.WithDeadline(ctx, options.Until) + defer cancel() + } + } tailRequest := &defangv1.TailRequest{ Etag: options.Etag, @@ -221,10 +237,11 @@ func tail(ctx context.Context, provider client.Provider, projectName string, opt Pattern: options.Filter, Project: projectName, Services: options.Services, - Since: since, + Since: since, // this is also used to continue from the last timestamp + Until: until, } - serverStream, err := provider.Follow(ctx, tailRequest) + serverStream, err := provider.QueryLogs(ctx, tailRequest) if err != nil { return err } @@ -304,7 +321,7 @@ func tail(ctx context.Context, provider client.Provider, projectName string, opt } pkg.SleepWithContext(ctx, 1*time.Second) tailRequest.Since = timestamppb.New(options.Since) - serverStream, err = provider.Follow(ctx, tailRequest) + serverStream, err = provider.QueryLogs(ctx, tailRequest) if err != nil { term.Debug("Reconnect failed:", err) return err diff --git a/src/pkg/cli/tail_test.go b/src/pkg/cli/tail_test.go index 2d2f5a95f..ccf17b427 100644 --- a/src/pkg/cli/tail_test.go +++ b/src/pkg/cli/tail_test.go @@ -78,7 +78,7 @@ type mockTailProvider struct { Reqs []*defangv1.TailRequest } -func (m *mockTailProvider) Follow(ctx context.Context, req *defangv1.TailRequest) (client.ServerStream[defangv1.TailResponse], error) { +func (m *mockTailProvider) QueryLogs(ctx context.Context, req *defangv1.TailRequest) (client.ServerStream[defangv1.TailResponse], error) { dup, _ := proto.Clone(req).(*defangv1.TailRequest) m.Reqs = append(m.Reqs, dup) if len(m.ServerStreams) == 0 { diff --git a/src/pkg/clouds/aws/ecs/logs.go b/src/pkg/clouds/aws/ecs/logs.go index 1a4e14fda..2e55ca46c 100644 --- a/src/pkg/clouds/aws/ecs/logs.go +++ b/src/pkg/clouds/aws/ecs/logs.go @@ -2,20 +2,16 @@ package ecs import ( "context" - "errors" "fmt" "io" "strings" "sync" "time" - "github.com/DefangLabs/defang/src/pkg" "github.com/DefangLabs/defang/src/pkg/clouds/aws" "github.com/DefangLabs/defang/src/pkg/clouds/aws/region" "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs" "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs/types" - "github.com/aws/aws-sdk-go-v2/service/ecs" - ecsTypes "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/aws/smithy-go/ptr" ) @@ -26,108 +22,50 @@ import ( // LogStream ("awslogs") PREFIX/CONTAINER/2cba912d5eb14ffd926f6992b054f3bf // LogStream ("awsfirelens") PREFIX/CONTAINER-firelens-2cba912d5eb14ffd926f6992b054f3bf -type LogStreamInfo struct { - Prefix string - Container string - Firelens bool - TaskID string -} - -func GetLogStreamInfo(logStream string) *LogStreamInfo { - parts := strings.Split(logStream, "/") - switch len(parts) { - case 3: - return &LogStreamInfo{ - Prefix: parts[0], - Container: parts[1], - Firelens: false, - TaskID: parts[2], - } - case 2: - firelensParts := strings.Split(parts[1], "-") - if len(firelensParts) != 3 || firelensParts[1] != "firelens" { - return nil - } - return &LogStreamInfo{ - Prefix: parts[0], - Container: firelensParts[0], - Firelens: true, - TaskID: firelensParts[2], - } - default: - return nil - } -} - func getLogGroupIdentifier(arnOrId string) string { return strings.TrimSuffix(arnOrId, ":*") } -func TailLogGroups(ctx context.Context, since time.Time, logGroups ...LogGroupInput) (EventStream, error) { - cs := newCollectionStream(ctx) +func QueryAndTailLogGroups(ctx context.Context, start, end time.Time, logGroups ...LogGroupInput) (LiveTailStream, error) { + ctx, cancel := context.WithCancel(ctx) - type pair struct { - es EventStream - lgi LogGroupInput + e := &eventStream{ + cancel: cancel, + ch: make(chan types.StartLiveTailResponseStream), } - var pairs []pair - var pendingGroups []LogGroupInput - sincePending := since - if !pkg.IsValidTime(since) { - sincePending = time.Now() - } + // We must close the channel when all log groups are done + var wg sync.WaitGroup + var err error for _, lgi := range logGroups { - es, err := TailLogGroup(ctx, lgi) - if err == nil { - pairs = append(pairs, pair{es, lgi}) - continue - } - - var resourceNotFound *types.ResourceNotFoundException - if !errors.As(err, &resourceNotFound) { - return nil, err + var es LiveTailStream + es, err = QueryAndTailLogGroup(ctx, lgi, start, end) + if err != nil { + break // abort if there is any fatal error } - pendingGroups = append(pendingGroups, lgi) + wg.Add(1) + go func() { + defer es.Close() + defer wg.Done() + // FIXME: this should *merge* the events from all log groups + e.err = e.pipeEvents(ctx, es) + }() } - // Start goroutines to wait for the log group to be created for the resource not found log groups - for _, lgi := range pendingGroups { - cs.wg.Add(1) - go func(lgi LogGroupInput) { - defer cs.wg.Done() - ticker := time.NewTicker(time.Second) - defer ticker.Stop() - - for { - select { - case <-cs.ctx.Done(): - return - case <-ticker.C: - es, err := TailLogGroup(cs.ctx, lgi) - if err == nil { - cs.addAndStart(es, sincePending, lgi) - return - } - var resourceNotFound *types.ResourceNotFoundException - if !errors.As(err, &resourceNotFound) { - cs.errCh <- err - return - } - } - } - }(lgi) - } + go func() { + wg.Wait() + close(e.ch) + }() - // Only add and start watching the streams if there were no errors, prevent lingering goroutines - for _, s := range pairs { - cs.addAndStart(s.es, since, s.lgi) + if err != nil { + cancel() // abort any goroutines (caller won't call Close) + return nil, err } - return cs, nil + return e, nil } -// LogGroupInput is like cloudwatchlogs.StartLiveTailInput but with only one loggroup and one logstream prefix. +// LogGroupInput is like cloudwatchlogs.StartLiveTailInput but with only one LogGroup and one LogStream prefix. type LogGroupInput struct { LogGroupARN string LogStreamNames []string @@ -135,7 +73,7 @@ type LogGroupInput struct { LogEventFilterPattern string } -func TailLogGroup(ctx context.Context, input LogGroupInput) (EventStream, error) { +func TailLogGroup(ctx context.Context, input LogGroupInput) (LiveTailStream, error) { var pattern *string if input.LogEventFilterPattern != "" { pattern = &input.LogEventFilterPattern @@ -144,15 +82,53 @@ func TailLogGroup(ctx context.Context, input LogGroupInput) (EventStream, error) if input.LogStreamNamePrefix != "" { prefixes = []string{input.LogStreamNamePrefix} } - return startLiveTail(ctx, &cloudwatchlogs.StartLiveTailInput{ + + slti := &cloudwatchlogs.StartLiveTailInput{ LogGroupIdentifiers: []string{getLogGroupIdentifier(input.LogGroupARN)}, LogStreamNames: input.LogStreamNames, LogStreamNamePrefixes: prefixes, LogEventFilterPattern: pattern, - }) + } + + region := region.FromArn(slti.LogGroupIdentifiers[0]) // must have at least one log group + cw, err := newCloudWatchLogsClient(ctx, region) // assume all log groups are in the same region + if err != nil { + return nil, err + } + + slto, err := cw.StartLiveTail(ctx, slti) + if err != nil { + return nil, err + } + + return slto.GetStream(), nil +} + +func QueryLogGroups(ctx context.Context, start, end time.Time, logGroups ...LogGroupInput) (<-chan LogEvent, <-chan error) { + errsChan := make(chan error) + + // Gather logs from the CD task, kaniko, ECS events, and all services + var evtsChan chan LogEvent + for _, lgi := range logGroups { + lgEvtChan := make(chan LogEvent) + // Start a go routine for each log group + go func(lgi LogGroupInput) { + defer close(errsChan) + if err := QueryLogGroup(ctx, lgi, start, end, func(logEvents []LogEvent) error { + for _, event := range logEvents { + lgEvtChan <- event + } + return nil + }); err != nil { + errsChan <- err + } + }(lgi) + evtsChan = mergeLogEventChan(evtsChan, lgEvtChan) // Merge sort the log events based on timestamp + } + return evtsChan, errsChan } -func Query(ctx context.Context, input LogGroupInput, start, end time.Time, cb func([]LogEvent) error) error { +func QueryLogGroup(ctx context.Context, input LogGroupInput, start, end time.Time, cb func([]LogEvent) error) error { region := region.FromArn(input.LogGroupARN) cw, err := newCloudWatchLogsClient(ctx, region) if err != nil { @@ -210,206 +186,17 @@ func newCloudWatchLogsClient(ctx context.Context, region aws.Region) (*cloudwatc return cloudwatchlogs.NewFromConfig(cfg), nil } -func startLiveTail(ctx context.Context, slti *cloudwatchlogs.StartLiveTailInput) (EventStream, error) { - region := region.FromArn(slti.LogGroupIdentifiers[0]) // must have at least one log group - cw, err := newCloudWatchLogsClient(ctx, region) - if err != nil { - return nil, err - } - - slto, err := cw.StartLiveTail(ctx, slti) - if err != nil { - return nil, err - } - - return slto.GetStream(), nil -} - -// GetTaskStatus returns nil if the task is still running, io.EOF if the task is stopped successfully, or an error if the task failed. -func GetTaskStatus(ctx context.Context, taskArn TaskArn) error { - region := region.FromArn(*taskArn) - cluster, taskID := SplitClusterTask(taskArn) - return getTaskStatus(ctx, region, cluster, taskID) -} - -func isTaskTerminalStatus(status string) bool { - // From https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-lifecycle-explanation.html - switch status { - case "DELETED", "STOPPED", "DEPROVISIONING": - return true - default: - return false // we might still get logs - } -} - -// getTaskStatus returns nil if the task is still running, io.EOF if the task is stopped successfully, or an error if the task failed. -func getTaskStatus(ctx context.Context, region aws.Region, cluster, taskId string) error { - cfg, err := aws.LoadDefaultConfig(ctx, region) - if err != nil { - return err - } - ecsClient := ecs.NewFromConfig(cfg) - - // Use DescribeTasks API to check if the task is still running (same as ecs.NewTasksStoppedWaiter) - ti, _ := ecsClient.DescribeTasks(ctx, &ecs.DescribeTasksInput{ - Cluster: &cluster, - Tasks: []string{taskId}, - }) - if ti == nil || len(ti.Tasks) == 0 { - return nil // task doesn't exist yet; TODO: check the actual error from DescribeTasks - } - task := ti.Tasks[0] - if task.LastStatus == nil || !isTaskTerminalStatus(*task.LastStatus) { - return nil // still running - } - - switch task.StopCode { - default: - return TaskFailure{task.StopCode, *task.StoppedReason} - case ecsTypes.TaskStopCodeEssentialContainerExited: - for _, c := range task.Containers { - if c.ExitCode != nil && *c.ExitCode != 0 { - reason := fmt.Sprintf("%s with code %d", *task.StoppedReason, *c.ExitCode) - return TaskFailure{task.StopCode, reason} - } - } - fallthrough - case "": // TODO: shouldn't happen - return io.EOF // Success - } -} - -func SplitClusterTask(taskArn TaskArn) (string, string) { - if !strings.HasPrefix(*taskArn, "arn:aws:ecs:") { - panic("invalid ECS ARN") - } - parts := strings.Split(*taskArn, "/") - if len(parts) != 3 || !strings.HasSuffix(parts[0], ":task") { - panic("invalid task ARN") - } - return parts[1], parts[2] -} - type LogEvent = types.LiveTailSessionLogEvent -// EventStream is an interface that represents a stream of events from a call to StartLiveTail -type EventStream interface { +// EventStream is a generic interface that represents a stream of events +type EventStream[T any] interface { + Events() <-chan T Close() error - Events() <-chan types.StartLiveTailResponseStream Err() error } -type collectionStream struct { - cancel context.CancelFunc - ch chan types.StartLiveTailResponseStream - outputCh chan types.StartLiveTailResponseStream - ctx context.Context // derived from the context passed to TailLogGroups - errCh chan error - streams []EventStream - - err error - - lock sync.Mutex - wg sync.WaitGroup -} - -func newCollectionStream(ctx context.Context) *collectionStream { - child, cancel := context.WithCancel(ctx) - cs := &collectionStream{ - cancel: cancel, - ch: make(chan types.StartLiveTailResponseStream, 10), // max number of loggroups to query - outputCh: make(chan types.StartLiveTailResponseStream), - ctx: child, - errCh: make(chan error, 1), - } - - go func() { - defer close(cs.outputCh) - for { - select { - case e, ok := <-cs.ch: - // This would make sure the goroutine exits after close is called - if !ok { - return - } - cs.outputCh <- e - case err := <-cs.errCh: - cs.err = err - cs.outputCh <- nil - case <-cs.ctx.Done(): - return - } - } - }() - - return cs -} - -func (c *collectionStream) addAndStart(s EventStream, since time.Time, lgi LogGroupInput) { - c.lock.Lock() - defer c.lock.Unlock() - c.streams = append(c.streams, s) - c.wg.Add(1) - go func() { - defer c.wg.Done() - if pkg.IsValidTime(since) { - // Query the logs between the start time and now - if err := Query(c.ctx, lgi, since, time.Now(), func(events []LogEvent) error { - c.ch <- &types.StartLiveTailResponseStreamMemberSessionUpdate{ - Value: types.LiveTailSessionUpdate{SessionResults: events}, - } - return nil - }); err != nil { - c.errCh <- err // the caller will likely cancel the context - } - } - for { - // Double select to make sure context cancellation is not blocked by either the receive or send - // See: https://stackoverflow.com/questions/60030756/what-does-it-mean-when-one-channel-uses-two-arrows-to-write-to-another-channel - select { - case e := <-s.Events(): // blocking - if err := s.Err(); err != nil { - select { - case c.errCh <- err: - case <-c.ctx.Done(): - } - return - } - select { - case c.ch <- e: - case <-c.ctx.Done(): - return - } - case <-c.ctx.Done(): // blocking - return - } - } - }() -} - -func (c *collectionStream) Close() error { - c.cancel() - c.wg.Wait() // Only close the channels after all goroutines have exited - close(c.ch) - close(c.errCh) - - var errs []error - for _, s := range c.streams { - err := s.Close() - if err != nil { - errs = append(errs, err) - } - } - return errors.Join(errs...) // nil if no errors -} - -func (c *collectionStream) Events() <-chan types.StartLiveTailResponseStream { - return c.outputCh -} - -func (c *collectionStream) Err() error { - return c.err -} +// Deprecated: LiveTailStream is a stream of events from a call to AWS StartLiveTail +type LiveTailStream = EventStream[types.StartLiveTailResponseStream] func GetLogEvents(e types.StartLiveTailResponseStream) ([]LogEvent, error) { switch ev := e.(type) { @@ -425,23 +212,3 @@ func GetLogEvents(e types.StartLiveTailResponseStream) ([]LogEvent, error) { return nil, fmt.Errorf("unexpected event: %T", ev) } } - -// WaitForTask polls the ECS task status. It returns io.EOF if the task is stopped successfully, or an error if the task failed. -func WaitForTask(ctx context.Context, taskArn TaskArn, poll time.Duration) error { - if taskArn == nil { - panic("taskArn is nil") - } - ticker := time.NewTicker(poll) - defer ticker.Stop() - for { - select { - case <-ctx.Done(): - // Handle cancellation - return ctx.Err() - case <-ticker.C: - if err := GetTaskStatus(ctx, taskArn); err != nil { - return err - } - } - } -} diff --git a/src/pkg/clouds/aws/ecs/logs_test.go b/src/pkg/clouds/aws/ecs/logs_test.go index 148348762..5057f5e97 100644 --- a/src/pkg/clouds/aws/ecs/logs_test.go +++ b/src/pkg/clouds/aws/ecs/logs_test.go @@ -1,7 +1,9 @@ package ecs import ( + "context" "testing" + "time" ) func TestLogGroupIdentifier(t *testing.T) { @@ -28,3 +30,21 @@ func TestSplitClusterTask(t *testing.T) { t.Errorf("Expected task ID %q, but got %q", taskArn, taskID) } } + +func TestQueryAndTailLogGroups(t *testing.T) { + e, err := QueryAndTailLogGroups(context.Background(), time.Now(), time.Time{}) + if err != nil { + t.Errorf("Expected no error, but got: %v", err) + } + if e.Err() != nil { + t.Errorf("Expected no error, but got: %v", e.Err()) + } + err = e.Close() + if err != nil { + t.Errorf("Expected no error, but got: %v", err) + } + _, ok := <-e.Events() + if ok { + t.Error("Expected channel to be closed") + } +} diff --git a/src/pkg/clouds/aws/ecs/merge.go b/src/pkg/clouds/aws/ecs/merge.go new file mode 100644 index 000000000..573fe6897 --- /dev/null +++ b/src/pkg/clouds/aws/ecs/merge.go @@ -0,0 +1,39 @@ +package ecs + +// Inspired by https://dev.to/vinaygo/concurrency-merge-sort-using-channels-and-goroutines-in-golang-35f7 +func Mergech[T any](left chan T, right chan T, c chan T, less func(T, T) bool) { + defer close(c) + val, ok := <-left + val2, ok2 := <-right + for ok && ok2 { + if less(val, val2) { + c <- val + val, ok = <-left + } else { + c <- val2 + val2, ok2 = <-right + } + } + for ok { + c <- val + val, ok = <-left + } + for ok2 { + c <- val2 + val2, ok2 = <-right + } +} + +func mergeLogEventChan(left, right chan LogEvent) chan LogEvent { + if left == nil { + return right + } + if right == nil { + return left + } + out := make(chan LogEvent) + go Mergech(left, right, out, func(i1, i2 LogEvent) bool { + return *i1.Timestamp < *i2.Timestamp + }) + return out +} diff --git a/src/pkg/clouds/aws/ecs/status.go b/src/pkg/clouds/aws/ecs/status.go new file mode 100644 index 000000000..c011a2713 --- /dev/null +++ b/src/pkg/clouds/aws/ecs/status.go @@ -0,0 +1,99 @@ +package ecs + +import ( + "context" + "fmt" + "io" + "strings" + "time" + + "github.com/DefangLabs/defang/src/pkg/clouds/aws" + "github.com/DefangLabs/defang/src/pkg/clouds/aws/region" + "github.com/aws/aws-sdk-go-v2/service/ecs" + ecsTypes "github.com/aws/aws-sdk-go-v2/service/ecs/types" +) + +// GetTaskStatus returns nil if the task is still running, io.EOF if the task is stopped successfully, or an error if the task failed. +func GetTaskStatus(ctx context.Context, taskArn TaskArn) error { + region := region.FromArn(*taskArn) + cluster, taskID := SplitClusterTask(taskArn) + return getTaskStatus(ctx, region, cluster, taskID) +} + +func isTaskTerminalStatus(status string) bool { + // From https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-lifecycle-explanation.html + switch status { + case "DELETED", "STOPPED", "DEPROVISIONING": + return true + default: + return false // we might still get logs + } +} + +// getTaskStatus returns nil if the task is still running, io.EOF if the task is stopped successfully, or an error if the task failed. +func getTaskStatus(ctx context.Context, region aws.Region, cluster, taskId string) error { + cfg, err := aws.LoadDefaultConfig(ctx, region) + if err != nil { + return err + } + ecsClient := ecs.NewFromConfig(cfg) + + // Use DescribeTasks API to check if the task is still running (same as ecs.NewTasksStoppedWaiter) + ti, _ := ecsClient.DescribeTasks(ctx, &ecs.DescribeTasksInput{ + Cluster: &cluster, + Tasks: []string{taskId}, + }) + if ti == nil || len(ti.Tasks) == 0 { + return nil // task doesn't exist yet; TODO: check the actual error from DescribeTasks + } + task := ti.Tasks[0] + if task.LastStatus == nil || !isTaskTerminalStatus(*task.LastStatus) { + return nil // still running + } + + switch task.StopCode { + default: + return TaskFailure{task.StopCode, *task.StoppedReason} + case ecsTypes.TaskStopCodeEssentialContainerExited: + for _, c := range task.Containers { + if c.ExitCode != nil && *c.ExitCode != 0 { + reason := fmt.Sprintf("%s with code %d", *task.StoppedReason, *c.ExitCode) + return TaskFailure{task.StopCode, reason} + } + } + fallthrough + case "": // TODO: shouldn't happen + return io.EOF // Success + } +} + +func SplitClusterTask(taskArn TaskArn) (string, string) { + if !strings.HasPrefix(*taskArn, "arn:aws:ecs:") { + panic("invalid ECS ARN") + } + parts := strings.Split(*taskArn, "/") + if len(parts) != 3 || !strings.HasSuffix(parts[0], ":task") { + panic("invalid task ARN") + } + return parts[1], parts[2] +} + +// WaitForTask polls the ECS task status. It returns io.EOF if the task is stopped successfully, or an error if the task failed. +func WaitForTask(ctx context.Context, taskArn TaskArn, poll time.Duration) error { + if taskArn == nil { + panic("taskArn is nil") + } + ticker := time.NewTicker(poll) + defer ticker.Stop() + for { + select { + case <-ctx.Done(): + // Handle cancellation + return ctx.Err() + case <-ticker.C: + if err := GetTaskStatus(ctx, taskArn); err != nil { + return err + } + } + } +} diff --git a/src/pkg/clouds/aws/ecs/stream.go b/src/pkg/clouds/aws/ecs/stream.go new file mode 100644 index 000000000..1ef92730b --- /dev/null +++ b/src/pkg/clouds/aws/ecs/stream.go @@ -0,0 +1,145 @@ +package ecs + +import ( + "context" + "errors" + "time" + + "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs/types" +) + +// QueryAndTailLogGroup queries the log group from the give start time and initiates a Live Tail session. +// This function also handles the case where the log group does not exist yet. +// The caller should call `Close()` on the returned EventStream when done. +func QueryAndTailLogGroup(ctx context.Context, lgi LogGroupInput, start, end time.Time) (LiveTailStream, error) { + ctx, cancel := context.WithCancel(ctx) + + es := &eventStream{ + cancel: cancel, + ch: make(chan types.StartLiveTailResponseStream), + } + + doTail := end.IsZero() + + var tailStream LiveTailStream + if doTail { + // First call TailLogGroup once to check if the log group exists or we have another error + var err error + tailStream, err = TailLogGroup(ctx, lgi) + if err != nil { + var resourceNotFound *types.ResourceNotFoundException + if !errors.As(err, &resourceNotFound) { + return nil, err + } + // Doesn't exist yet, continue to poll for it + } + } + + // Start goroutine to wait for the log group to be created and then tail it + go func() { + defer close(es.ch) + + if doTail { + // If the log group does not exist yet, poll until it does + if tailStream == nil { + var err error + tailStream, err = pollTailLogGroup(ctx, lgi) + if err != nil { + es.err = err + return + } + } + defer tailStream.Close() + } + + if !start.IsZero() { + if end.IsZero() { + end = time.Now() + } + // Query the logs between the start time and now; TODO: could use a single CloudWatch client for all queries in same region + if err := QueryLogGroup(ctx, lgi, start, end, func(events []LogEvent) error { + es.ch <- &types.StartLiveTailResponseStreamMemberSessionUpdate{ + Value: types.LiveTailSessionUpdate{SessionResults: events}, + } + return nil + }); err != nil { + es.err = err + return // the caller will likely cancel the context + } + } + + if doTail { + // Pipe the events from the tail stream to the internal channel + es.err = es.pipeEvents(ctx, tailStream) + } + }() + + return es, nil +} + +// pollTailLogGroup polls the log group and starts the Live Tail session once it's available +func pollTailLogGroup(ctx context.Context, lgi LogGroupInput) (LiveTailStream, error) { + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + var resourceNotFound *types.ResourceNotFoundException + for { + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-ticker.C: + eventStream, err := TailLogGroup(ctx, lgi) + if errors.As(err, &resourceNotFound) { + continue // keep trying + } + return eventStream, err + } + } +} + +// eventStream is an bare implementation of the EventStream interface. +type eventStream struct { + cancel context.CancelFunc + ch chan types.StartLiveTailResponseStream + err error +} + +var _ LiveTailStream = (*eventStream)(nil) + +func (es *eventStream) Close() error { + es.cancel() + return nil +} + +func (es *eventStream) Err() error { + return es.err +} + +func (es *eventStream) Events() <-chan types.StartLiveTailResponseStream { + return es.ch +} + +// pipeEvents copies events from the given EventStream to the internal channel, +// until the context is canceled or an error occurs in the given EventStream. +func (es *eventStream) pipeEvents(ctx context.Context, tailStream LiveTailStream) error { + for { + // Double select to make sure context cancellation is not blocked by either the receive or send + // See: https://stackoverflow.com/questions/60030756/what-does-it-mean-when-one-channel-uses-two-arrows-to-write-to-another-channel + select { + case event := <-tailStream.Events(): // blocking + if err := tailStream.Err(); err != nil { + return err + } + if event == nil { + return nil + } + select { + case es.ch <- event: + case <-ctx.Done(): + return ctx.Err() + } + case <-ctx.Done(): // blocking + return ctx.Err() + } + } +} diff --git a/src/pkg/clouds/aws/ecs/stream_test.go b/src/pkg/clouds/aws/ecs/stream_test.go new file mode 100644 index 000000000..8046a8270 --- /dev/null +++ b/src/pkg/clouds/aws/ecs/stream_test.go @@ -0,0 +1,36 @@ +//go:build integration + +package ecs + +import ( + "context" + "testing" + "time" +) + +func TestPendingStream(t *testing.T) { + if testing.Short() { + t.Skip("skipping slow integration test") + } + + ps, _ := QueryAndTailLogGroup(context.Background(), LogGroupInput{ + LogGroupARN: "arn:aws:logs:us-west-2:532501343364:log-group:/ecs/lio/logss:*", + }, time.Now().Add(-time.Minute), time.Time{}) + + go func() { + time.Sleep(5 * time.Second) + ps.Close() + }() + + if ps.Err() != nil { + t.Errorf("Error: %v", ps.Err()) + } + + for e := range ps.Events() { + if e == nil { + t.Errorf("Error: %v", ps.Err()) + } + println(e) + } + t.Error(ps.Err()) +} diff --git a/src/pkg/clouds/aws/ecs/tail.go b/src/pkg/clouds/aws/ecs/tail.go index 56380863d..40b7f96de 100644 --- a/src/pkg/clouds/aws/ecs/tail.go +++ b/src/pkg/clouds/aws/ecs/tail.go @@ -57,7 +57,7 @@ func (a *AwsEcs) GetTaskArn(taskID string) (TaskArn, error) { return &taskArn, nil } -func (a *AwsEcs) TailTaskID(ctx context.Context, taskID string) (EventStream, error) { +func (a *AwsEcs) TailTaskID(ctx context.Context, taskID string) (LiveTailStream, error) { if taskID == "" { return nil, errors.New("taskID is empty") } diff --git a/src/protos/io/defang/v1/fabric.pb.go b/src/protos/io/defang/v1/fabric.pb.go index c334ef803..7e92f7f6d 100644 --- a/src/protos/io/defang/v1/fabric.pb.go +++ b/src/protos/io/defang/v1/fabric.pb.go @@ -568,6 +568,58 @@ func (SubscriptionTier) EnumDescriptor() ([]byte, []int) { return file_io_defang_v1_fabric_proto_rawDescGZIP(), []int{9} } +type TailRequest_LogType int32 + +const ( + TailRequest_LOG_TYPE_UNSPECIFIED TailRequest_LogType = 0 + TailRequest_LOG_TYPE_CD TailRequest_LogType = 1 + TailRequest_LOG_TYPE_BUILD TailRequest_LogType = 2 + TailRequest_LOG_TYPE_RUN TailRequest_LogType = 4 +) + +// Enum value maps for TailRequest_LogType. +var ( + TailRequest_LogType_name = map[int32]string{ + 0: "LOG_TYPE_UNSPECIFIED", + 1: "LOG_TYPE_CD", + 2: "LOG_TYPE_BUILD", + 4: "LOG_TYPE_RUN", + } + TailRequest_LogType_value = map[string]int32{ + "LOG_TYPE_UNSPECIFIED": 0, + "LOG_TYPE_CD": 1, + "LOG_TYPE_BUILD": 2, + "LOG_TYPE_RUN": 4, + } +) + +func (x TailRequest_LogType) Enum() *TailRequest_LogType { + p := new(TailRequest_LogType) + *p = x + return p +} + +func (x TailRequest_LogType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (TailRequest_LogType) Descriptor() protoreflect.EnumDescriptor { + return file_io_defang_v1_fabric_proto_enumTypes[10].Descriptor() +} + +func (TailRequest_LogType) Type() protoreflect.EnumType { + return &file_io_defang_v1_fabric_proto_enumTypes[10] +} + +func (x TailRequest_LogType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use TailRequest_LogType.Descriptor instead. +func (TailRequest_LogType) EnumDescriptor() ([]byte, []int) { + return file_io_defang_v1_fabric_proto_rawDescGZIP(), []int{43, 0} +} + type GetSelectedProviderRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Project string `protobuf:"bytes,1,opt,name=project,proto3" json:"project,omitempty"` @@ -857,6 +909,7 @@ type DebugRequest struct { Services []string `protobuf:"bytes,5,rep,name=services,proto3" json:"services,omitempty"` TrainingOptOut bool `protobuf:"varint,6,opt,name=training_opt_out,json=trainingOptOut,proto3" json:"training_opt_out,omitempty"` // only valid for Pro users Since *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=since,proto3" json:"since,omitempty"` + Until *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=until,proto3" json:"until,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -940,6 +993,13 @@ func (x *DebugRequest) GetSince() *timestamppb.Timestamp { return nil } +func (x *DebugRequest) GetUntil() *timestamppb.Timestamp { + if x != nil { + return x.Until + } + return nil +} + type DebugResponse struct { state protoimpl.MessageState `protogen:"open.v1"` General string `protobuf:"bytes,1,opt,name=general,proto3" json:"general,omitempty"` @@ -3048,7 +3108,7 @@ type TailRequest struct { Since *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=since,proto3" json:"since,omitempty"` Etag string `protobuf:"bytes,3,opt,name=etag,proto3" json:"etag,omitempty"` Project string `protobuf:"bytes,4,opt,name=project,proto3" json:"project,omitempty"` - LogType uint32 `protobuf:"varint,5,opt,name=log_type,json=logType,proto3" json:"log_type,omitempty"` + LogType uint32 `protobuf:"varint,5,opt,name=log_type,json=logType,proto3" json:"log_type,omitempty"` // bitfield Pattern string `protobuf:"bytes,6,opt,name=pattern,proto3" json:"pattern,omitempty"` Until *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=until,proto3" json:"until,omitempty"` unknownFields protoimpl.UnknownFields @@ -3351,9 +3411,10 @@ type ProjectUpdate struct { Services []*ServiceInfo `protobuf:"bytes,1,rep,name=services,proto3" json:"services,omitempty"` AlbArn string `protobuf:"bytes,2,opt,name=alb_arn,json=albArn,proto3" json:"alb_arn,omitempty"` // Deprecated: Marked as deprecated in io/defang/v1/fabric.proto. - Project string `protobuf:"bytes,3,opt,name=project,proto3" json:"project,omitempty"` // deprecated; use compose.name - Compose []byte `protobuf:"bytes,4,opt,name=compose,proto3" json:"compose,omitempty"` - CdVersion string `protobuf:"bytes,5,opt,name=cd_version,json=cdVersion,proto3" json:"cd_version,omitempty"` + Project string `protobuf:"bytes,3,opt,name=project,proto3" json:"project,omitempty"` // deprecated; use compose.name + Compose []byte `protobuf:"bytes,4,opt,name=compose,proto3" json:"compose,omitempty"` + CdVersion string `protobuf:"bytes,5,opt,name=cd_version,json=cdVersion,proto3" json:"cd_version,omitempty"` + Mode DeploymentMode `protobuf:"varint,6,opt,name=mode,proto3,enum=io.defang.v1.DeploymentMode" json:"mode,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -3424,6 +3485,13 @@ func (x *ProjectUpdate) GetCdVersion() string { return "" } +func (x *ProjectUpdate) GetMode() DeploymentMode { + if x != nil { + return x.Mode + } + return DeploymentMode_MODE_UNSPECIFIED +} + // Deprecated: Marked as deprecated in io/defang/v1/fabric.proto. type ServiceID struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -4969,7 +5037,7 @@ var file_io_defang_v1_fabric_proto_rawDesc = []byte{ 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x25, 0x0a, 0x0f, 0x44, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0xf2, 0x01, 0x0a, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0xa4, 0x02, 0x0a, 0x0c, 0x44, 0x65, 0x62, 0x75, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, @@ -4985,313 +5053,325 @@ var file_io_defang_v1_fabric_proto_rawDesc = []byte{ 0x30, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, - 0x65, 0x22, 0x72, 0x0a, 0x0d, 0x44, 0x65, 0x62, 0x75, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x12, 0x2b, 0x0a, 0x06, - 0x69, 0x73, 0x73, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x69, - 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x73, 0x73, 0x75, - 0x65, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x05, 0x49, 0x73, 0x73, 0x75, 0x65, 0x12, - 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, - 0x18, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x63, 0x6f, 0x64, - 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x18, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x6f, 0x64, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0b, 0x63, 0x6f, 0x64, 0x65, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x22, 0x38, 0x0a, 0x0a, 0x43, 0x6f, 0x64, 0x65, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x22, 0xec, 0x01, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x6e, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x61, 0x6e, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x12, 0x4a, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, - 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, - 0x6f, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x6f, 0x73, 0x12, 0x12, 0x0a, 0x04, - 0x61, 0x72, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x63, 0x68, - 0x1a, 0x3d, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 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, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, - 0x5e, 0x0a, 0x0e, 0x43, 0x61, 0x6e, 0x49, 0x55, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x32, 0x0a, 0x08, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, - 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x22, - 0x44, 0x0a, 0x0f, 0x43, 0x61, 0x6e, 0x49, 0x55, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x64, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x64, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, - 0x03, 0x67, 0x70, 0x75, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x67, 0x70, 0x75, 0x4a, - 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x85, 0x02, 0x0a, 0x0d, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x69, 0x6f, 0x2e, 0x64, - 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x42, 0x02, 0x18, 0x01, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, - 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x02, 0x18, 0x01, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x30, 0x0a, 0x04, - 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x69, 0x6f, 0x2e, - 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x07, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x65, 0x6c, 0x65, - 0x67, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, - 0x6e, 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, - 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x49, 0x64, 0x22, 0x5b, 0x0a, - 0x0e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x35, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0x68, 0x0a, 0x0d, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x61, 0x6d, 0x65, - 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x64, - 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x44, 0x6f, - 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x24, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0x91, 0x01, 0x0a, 0x14, 0x47, - 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6c, - 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, - 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x67, 0x72, 0x65, 0x65, - 0x5f, 0x74, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x67, 0x72, 0x65, - 0x65, 0x54, 0x6f, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, - 0x5f, 0x6f, 0x70, 0x74, 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, - 0x74, 0x72, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x74, 0x4f, 0x75, 0x74, 0x22, 0x34, - 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x22, 0x41, 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, - 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x69, - 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6c, 0x65, - 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x2b, 0x0a, 0x15, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x75, 0x75, 0x69, 0x64, 0x22, 0x2b, 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, - 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, - 0x64, 0x22, 0x44, 0x0a, 0x10, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x52, 0x4c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, - 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x25, 0x0a, 0x11, 0x55, 0x70, 0x6c, 0x6f, 0x61, - 0x64, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, - 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0xc1, - 0x04, 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2f, - 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x15, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x18, 0x0a, - 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x61, 0x74, 0x5f, 0x69, 0x70, 0x73, 0x18, 0x06, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x61, 0x74, 0x49, 0x70, 0x73, 0x12, 0x15, 0x0a, 0x06, - 0x6c, 0x62, 0x5f, 0x69, 0x70, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x62, - 0x49, 0x70, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x66, - 0x71, 0x64, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, - 0x74, 0x65, 0x46, 0x71, 0x64, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x5f, 0x66, 0x71, 0x64, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x46, 0x71, 0x64, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x17, 0x0a, - 0x07, 0x7a, 0x6f, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x7a, 0x6f, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x5f, 0x61, 0x63, - 0x6d, 0x65, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, - 0x73, 0x65, 0x41, 0x63, 0x6d, 0x65, 0x43, 0x65, 0x72, 0x74, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x69, 0x6f, 0x2e, 0x64, - 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1e, 0x0a, 0x0a, - 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0a, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0b, - 0x6c, 0x62, 0x5f, 0x64, 0x6e, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x6c, 0x62, 0x44, 0x6e, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x4a, 0x04, 0x08, 0x0e, - 0x10, 0x0f, 0x22, 0x3d, 0x0a, 0x07, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x12, 0x14, 0x0a, + 0x65, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x75, 0x6e, + 0x74, 0x69, 0x6c, 0x22, 0x72, 0x0a, 0x0d, 0x44, 0x65, 0x62, 0x75, 0x67, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x12, 0x2b, + 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x05, 0x49, 0x73, 0x73, 0x75, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, + 0x79, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x3b, 0x0a, 0x0c, 0x63, + 0x6f, 0x64, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0b, 0x63, 0x6f, 0x64, + 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x22, 0x38, 0x0a, 0x0a, 0x43, 0x6f, 0x64, 0x65, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x22, 0xec, 0x01, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x6e, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6e, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x12, 0x4a, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, + 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x0e, + 0x0a, 0x02, 0x6f, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x6f, 0x73, 0x12, 0x12, + 0x0a, 0x04, 0x61, 0x72, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, + 0x63, 0x68, 0x1a, 0x3d, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 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, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x5e, 0x0a, 0x0e, 0x43, 0x61, 0x6e, 0x49, 0x55, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x32, 0x0a, + 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x16, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x50, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x22, 0x44, 0x0a, 0x0f, 0x43, 0x61, 0x6e, 0x49, 0x55, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x64, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x64, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, + 0x10, 0x0a, 0x03, 0x67, 0x70, 0x75, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x67, 0x70, + 0x75, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x85, 0x02, 0x0a, 0x0d, 0x44, 0x65, 0x70, 0x6c, + 0x6f, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x08, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x69, 0x6f, + 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x42, 0x02, 0x18, 0x01, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x12, 0x1c, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x30, + 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x69, + 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, + 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x65, + 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x49, 0x64, 0x22, + 0x5b, 0x0a, 0x0e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x35, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0x68, 0x0a, 0x0d, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x02, 0x18, - 0x01, 0x22, 0x55, 0x0a, 0x0b, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x02, 0x18, 0x01, 0x22, 0x7a, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x27, 0x0a, + 0x0f, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, + 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x24, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0x91, 0x01, 0x0a, + 0x14, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x12, 0x1a, 0x0a, + 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x67, 0x72, + 0x65, 0x65, 0x5f, 0x74, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x67, + 0x72, 0x65, 0x65, 0x54, 0x6f, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x69, + 0x6e, 0x67, 0x5f, 0x6f, 0x70, 0x74, 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0e, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x4f, 0x70, 0x74, 0x4f, 0x75, 0x74, + 0x22, 0x34, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x41, 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x28, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, + 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, + 0x6c, 0x65, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x2b, 0x0a, 0x15, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, 0x2b, 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, + 0x75, 0x69, 0x64, 0x22, 0x44, 0x0a, 0x10, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x52, 0x4c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, + 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x25, 0x0a, 0x11, 0x55, 0x70, 0x6c, + 0x6f, 0x61, 0x64, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, + 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, + 0x22, 0xc1, 0x04, 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x2f, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, + 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, + 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x6e, 0x61, 0x74, 0x5f, 0x69, 0x70, 0x73, + 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x61, 0x74, 0x49, 0x70, 0x73, 0x12, 0x15, + 0x0a, 0x06, 0x6c, 0x62, 0x5f, 0x69, 0x70, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, + 0x6c, 0x62, 0x49, 0x70, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, + 0x5f, 0x66, 0x71, 0x64, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x69, + 0x76, 0x61, 0x74, 0x65, 0x46, 0x71, 0x64, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x5f, 0x66, 0x71, 0x64, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x46, 0x71, 0x64, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, + 0x61, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, + 0x17, 0x0a, 0x07, 0x7a, 0x6f, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x7a, 0x6f, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x5f, + 0x61, 0x63, 0x6d, 0x65, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0b, 0x75, 0x73, 0x65, 0x41, 0x63, 0x6d, 0x65, 0x43, 0x65, 0x72, 0x74, 0x12, 0x30, 0x0a, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x69, 0x6f, + 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1e, + 0x0a, 0x0a, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x10, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, + 0x0a, 0x0b, 0x6c, 0x62, 0x5f, 0x64, 0x6e, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x11, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x62, 0x44, 0x6e, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x4a, 0x04, + 0x08, 0x0e, 0x10, 0x0f, 0x22, 0x3d, 0x0a, 0x07, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x12, + 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x3a, + 0x02, 0x18, 0x01, 0x22, 0x55, 0x0a, 0x0b, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x2c, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x39, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4b, 0x65, - 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, - 0x84, 0x01, 0x0a, 0x10, 0x50, 0x75, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x02, 0x18, 0x01, 0x22, 0x7a, 0x0a, 0x06, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x2c, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x46, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x07, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, - 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x4b, 0x65, 0x79, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x22, 0x44, - 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, - 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x73, 0x22, 0x49, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x07, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x4b, 0x65, 0x79, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x22, - 0x2e, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, - 0x48, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, - 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4b, 0x65, 0x79, - 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x22, 0xf4, 0x01, 0x0a, 0x0a, 0x44, 0x65, - 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x2e, - 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x38, - 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x36, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x39, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x22, 0x84, 0x01, 0x0a, 0x10, 0x50, 0x75, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x2c, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, + 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x46, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, + 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x4b, 0x65, 0x79, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, + 0x22, 0x44, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, + 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x22, 0x49, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, + 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4b, 0x65, 0x79, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x73, 0x22, 0x2e, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x22, 0x48, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x69, 0x6f, 0x2e, 0x64, + 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4b, + 0x65, 0x79, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x22, 0xf4, 0x01, 0x0a, 0x0a, + 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, + 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x36, 0x0a, 0x06, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x69, 0x6f, 0x2e, + 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0x50, 0x0a, 0x14, 0x50, 0x75, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0a, 0x64, 0x65, + 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, + 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, + 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x32, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, + 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, + 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x55, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, + 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x0b, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x50, 0x0a, 0x14, 0x50, 0x75, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x6c, - 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x69, - 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, - 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x22, 0x32, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x55, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, - 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x3a, 0x0a, 0x0b, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, - 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x52, 0x0b, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xd4, 0x01, - 0x0a, 0x0c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, - 0x0a, 0x06, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x63, - 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x43, - 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x73, 0x73, - 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x73, - 0x73, 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, - 0x65, 0x73, 0x5f, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x65, 0x78, 0x70, - 0x69, 0x72, 0x65, 0x73, 0x49, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x6e, 0x6f, 0x6e, 0x5f, 0x69, - 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6e, 0x6f, 0x6e, 0x49, 0x64, 0x12, - 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x57, 0x0a, 0x0d, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, - 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x22, 0x0a, - 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x22, 0x5f, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, - 0x66, 0x61, 0x62, 0x72, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x61, - 0x62, 0x72, 0x69, 0x63, 0x12, 0x17, 0x0a, 0x07, 0x63, 0x6c, 0x69, 0x5f, 0x6d, 0x69, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6c, 0x69, 0x4d, 0x69, 0x6e, 0x12, 0x1d, 0x0a, - 0x0a, 0x70, 0x75, 0x6c, 0x75, 0x6d, 0x69, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x70, 0x75, 0x6c, 0x75, 0x6d, 0x69, 0x4d, 0x69, 0x6e, 0x4a, 0x04, 0x08, 0x02, - 0x10, 0x03, 0x22, 0xf0, 0x01, 0x0a, 0x0b, 0x54, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x30, - 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x65, 0x74, 0x61, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x19, - 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, - 0x74, 0x65, 0x72, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, - 0x65, 0x72, 0x6e, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, - 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x22, 0xb8, 0x01, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x38, 0x0a, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x6e, 0x74, 0x52, 0x0b, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, + 0xd4, 0x01, 0x0a, 0x0c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, + 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x75, 0x74, + 0x68, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, + 0x73, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x61, 0x73, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x78, 0x70, + 0x69, 0x72, 0x65, 0x73, 0x5f, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x65, + 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x49, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x6e, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6e, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, + 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x57, 0x0a, 0x0d, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, + 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, + 0x22, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x22, 0x5f, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, + 0x0a, 0x06, 0x66, 0x61, 0x62, 0x72, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x66, 0x61, 0x62, 0x72, 0x69, 0x63, 0x12, 0x17, 0x0a, 0x07, 0x63, 0x6c, 0x69, 0x5f, 0x6d, 0x69, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6c, 0x69, 0x4d, 0x69, 0x6e, 0x12, + 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x6c, 0x75, 0x6d, 0x69, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x6c, 0x75, 0x6d, 0x69, 0x4d, 0x69, 0x6e, 0x4a, 0x04, + 0x08, 0x02, 0x10, 0x03, 0x22, 0xcc, 0x02, 0x0a, 0x0b, 0x54, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x12, 0x30, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x12, 0x18, - 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x12, 0x0a, 0x04, - 0x68, 0x6f, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, - 0x22, 0x88, 0x01, 0x0a, 0x0c, 0x54, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x30, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, - 0x69, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, - 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x68, 0x6f, 0x73, 0x74, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xa1, 0x01, 0x0a, 0x13, - 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, - 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, - 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x22, - 0xb6, 0x01, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x69, 0x6e, + 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, + 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x05, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x22, 0x5a, 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x4c, 0x4f, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, + 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, + 0x4c, 0x4f, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x44, 0x10, 0x01, 0x12, 0x12, 0x0a, + 0x0e, 0x4c, 0x4f, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x10, + 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x4f, 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x55, + 0x4e, 0x10, 0x04, 0x22, 0xb8, 0x01, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x12, 0x18, 0x0a, 0x07, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, + 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x22, 0x88, + 0x01, 0x0a, 0x0c, 0x54, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x30, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, + 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, + 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, + 0x74, 0x61, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, + 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, + 0x6f, 0x73, 0x74, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0xa1, 0x01, 0x0a, 0x13, 0x47, 0x65, + 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x6c, 0x62, 0x5f, - 0x61, 0x72, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6c, 0x62, 0x41, 0x72, - 0x6e, 0x12, 0x1c, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, - 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x64, 0x5f, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, - 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3d, 0x0a, 0x09, 0x53, 0x65, 0x72, 0x76, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x22, 0xe8, 0x01, + 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, + 0x35, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x6c, 0x62, 0x5f, 0x61, 0x72, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6c, 0x62, 0x41, 0x72, 0x6e, 0x12, + 0x1c, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x18, 0x0a, + 0x07, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x64, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x64, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x69, 0x6f, 0x2e, 0x64, 0x65, 0x66, 0x61, 0x6e, 0x67, + 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x6f, + 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x3d, 0x0a, 0x09, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, @@ -5781,7 +5861,7 @@ func file_io_defang_v1_fabric_proto_rawDescGZIP() []byte { return file_io_defang_v1_fabric_proto_rawDescData } -var file_io_defang_v1_fabric_proto_enumTypes = make([]protoimpl.EnumInfo, 10) +var file_io_defang_v1_fabric_proto_enumTypes = make([]protoimpl.EnumInfo, 11) var file_io_defang_v1_fabric_proto_msgTypes = make([]protoimpl.MessageInfo, 74) var file_io_defang_v1_fabric_proto_goTypes = []any{ (Provider)(0), // 0: io.defang.v1.Provider @@ -5794,225 +5874,228 @@ var file_io_defang_v1_fabric_proto_goTypes = []any{ (Mode)(0), // 7: io.defang.v1.Mode (Network)(0), // 8: io.defang.v1.Network (SubscriptionTier)(0), // 9: io.defang.v1.SubscriptionTier - (*GetSelectedProviderRequest)(nil), // 10: io.defang.v1.GetSelectedProviderRequest - (*GetSelectedProviderResponse)(nil), // 11: io.defang.v1.GetSelectedProviderResponse - (*SetSelectedProviderRequest)(nil), // 12: io.defang.v1.SetSelectedProviderRequest - (*VerifyDNSSetupRequest)(nil), // 13: io.defang.v1.VerifyDNSSetupRequest - (*DestroyRequest)(nil), // 14: io.defang.v1.DestroyRequest - (*DestroyResponse)(nil), // 15: io.defang.v1.DestroyResponse - (*DebugRequest)(nil), // 16: io.defang.v1.DebugRequest - (*DebugResponse)(nil), // 17: io.defang.v1.DebugResponse - (*Issue)(nil), // 18: io.defang.v1.Issue - (*CodeChange)(nil), // 19: io.defang.v1.CodeChange - (*TrackRequest)(nil), // 20: io.defang.v1.TrackRequest - (*CanIUseRequest)(nil), // 21: io.defang.v1.CanIUseRequest - (*CanIUseResponse)(nil), // 22: io.defang.v1.CanIUseResponse - (*DeployRequest)(nil), // 23: io.defang.v1.DeployRequest - (*DeployResponse)(nil), // 24: io.defang.v1.DeployResponse - (*DeleteRequest)(nil), // 25: io.defang.v1.DeleteRequest - (*DeleteResponse)(nil), // 26: io.defang.v1.DeleteResponse - (*GenerateFilesRequest)(nil), // 27: io.defang.v1.GenerateFilesRequest - (*File)(nil), // 28: io.defang.v1.File - (*GenerateFilesResponse)(nil), // 29: io.defang.v1.GenerateFilesResponse - (*StartGenerateResponse)(nil), // 30: io.defang.v1.StartGenerateResponse - (*GenerateStatusRequest)(nil), // 31: io.defang.v1.GenerateStatusRequest - (*UploadURLRequest)(nil), // 32: io.defang.v1.UploadURLRequest - (*UploadURLResponse)(nil), // 33: io.defang.v1.UploadURLResponse - (*ServiceInfo)(nil), // 34: io.defang.v1.ServiceInfo - (*Secrets)(nil), // 35: io.defang.v1.Secrets - (*SecretValue)(nil), // 36: io.defang.v1.SecretValue - (*Config)(nil), // 37: io.defang.v1.Config - (*ConfigKey)(nil), // 38: io.defang.v1.ConfigKey - (*PutConfigRequest)(nil), // 39: io.defang.v1.PutConfigRequest - (*GetConfigsRequest)(nil), // 40: io.defang.v1.GetConfigsRequest - (*GetConfigsResponse)(nil), // 41: io.defang.v1.GetConfigsResponse - (*DeleteConfigsRequest)(nil), // 42: io.defang.v1.DeleteConfigsRequest - (*ListConfigsRequest)(nil), // 43: io.defang.v1.ListConfigsRequest - (*ListConfigsResponse)(nil), // 44: io.defang.v1.ListConfigsResponse - (*Deployment)(nil), // 45: io.defang.v1.Deployment - (*PutDeploymentRequest)(nil), // 46: io.defang.v1.PutDeploymentRequest - (*ListDeploymentsRequest)(nil), // 47: io.defang.v1.ListDeploymentsRequest - (*ListDeploymentsResponse)(nil), // 48: io.defang.v1.ListDeploymentsResponse - (*TokenRequest)(nil), // 49: io.defang.v1.TokenRequest - (*TokenResponse)(nil), // 50: io.defang.v1.TokenResponse - (*Status)(nil), // 51: io.defang.v1.Status - (*Version)(nil), // 52: io.defang.v1.Version - (*TailRequest)(nil), // 53: io.defang.v1.TailRequest - (*LogEntry)(nil), // 54: io.defang.v1.LogEntry - (*TailResponse)(nil), // 55: io.defang.v1.TailResponse - (*GetServicesResponse)(nil), // 56: io.defang.v1.GetServicesResponse - (*ProjectUpdate)(nil), // 57: io.defang.v1.ProjectUpdate - (*ServiceID)(nil), // 58: io.defang.v1.ServiceID - (*GetRequest)(nil), // 59: io.defang.v1.GetRequest - (*Device)(nil), // 60: io.defang.v1.Device - (*Resource)(nil), // 61: io.defang.v1.Resource - (*Resources)(nil), // 62: io.defang.v1.Resources - (*Deploy)(nil), // 63: io.defang.v1.Deploy - (*Port)(nil), // 64: io.defang.v1.Port - (*Secret)(nil), // 65: io.defang.v1.Secret - (*Build)(nil), // 66: io.defang.v1.Build - (*HealthCheck)(nil), // 67: io.defang.v1.HealthCheck - (*Service)(nil), // 68: io.defang.v1.Service - (*StaticFiles)(nil), // 69: io.defang.v1.StaticFiles - (*Redis)(nil), // 70: io.defang.v1.Redis - (*DeployEvent)(nil), // 71: io.defang.v1.DeployEvent - (*Event)(nil), // 72: io.defang.v1.Event - (*PublishRequest)(nil), // 73: io.defang.v1.PublishRequest - (*SubscribeRequest)(nil), // 74: io.defang.v1.SubscribeRequest - (*SubscribeResponse)(nil), // 75: io.defang.v1.SubscribeResponse - (*GetServicesRequest)(nil), // 76: io.defang.v1.GetServicesRequest - (*DelegateSubdomainZoneRequest)(nil), // 77: io.defang.v1.DelegateSubdomainZoneRequest - (*DelegateSubdomainZoneResponse)(nil), // 78: io.defang.v1.DelegateSubdomainZoneResponse - (*SetOptionsRequest)(nil), // 79: io.defang.v1.SetOptionsRequest - (*WhoAmIResponse)(nil), // 80: io.defang.v1.WhoAmIResponse - nil, // 81: io.defang.v1.TrackRequest.PropertiesEntry - nil, // 82: io.defang.v1.Build.ArgsEntry - nil, // 83: io.defang.v1.Service.EnvironmentEntry - (*timestamppb.Timestamp)(nil), // 84: google.protobuf.Timestamp - (*emptypb.Empty)(nil), // 85: google.protobuf.Empty + (TailRequest_LogType)(0), // 10: io.defang.v1.TailRequest.LogType + (*GetSelectedProviderRequest)(nil), // 11: io.defang.v1.GetSelectedProviderRequest + (*GetSelectedProviderResponse)(nil), // 12: io.defang.v1.GetSelectedProviderResponse + (*SetSelectedProviderRequest)(nil), // 13: io.defang.v1.SetSelectedProviderRequest + (*VerifyDNSSetupRequest)(nil), // 14: io.defang.v1.VerifyDNSSetupRequest + (*DestroyRequest)(nil), // 15: io.defang.v1.DestroyRequest + (*DestroyResponse)(nil), // 16: io.defang.v1.DestroyResponse + (*DebugRequest)(nil), // 17: io.defang.v1.DebugRequest + (*DebugResponse)(nil), // 18: io.defang.v1.DebugResponse + (*Issue)(nil), // 19: io.defang.v1.Issue + (*CodeChange)(nil), // 20: io.defang.v1.CodeChange + (*TrackRequest)(nil), // 21: io.defang.v1.TrackRequest + (*CanIUseRequest)(nil), // 22: io.defang.v1.CanIUseRequest + (*CanIUseResponse)(nil), // 23: io.defang.v1.CanIUseResponse + (*DeployRequest)(nil), // 24: io.defang.v1.DeployRequest + (*DeployResponse)(nil), // 25: io.defang.v1.DeployResponse + (*DeleteRequest)(nil), // 26: io.defang.v1.DeleteRequest + (*DeleteResponse)(nil), // 27: io.defang.v1.DeleteResponse + (*GenerateFilesRequest)(nil), // 28: io.defang.v1.GenerateFilesRequest + (*File)(nil), // 29: io.defang.v1.File + (*GenerateFilesResponse)(nil), // 30: io.defang.v1.GenerateFilesResponse + (*StartGenerateResponse)(nil), // 31: io.defang.v1.StartGenerateResponse + (*GenerateStatusRequest)(nil), // 32: io.defang.v1.GenerateStatusRequest + (*UploadURLRequest)(nil), // 33: io.defang.v1.UploadURLRequest + (*UploadURLResponse)(nil), // 34: io.defang.v1.UploadURLResponse + (*ServiceInfo)(nil), // 35: io.defang.v1.ServiceInfo + (*Secrets)(nil), // 36: io.defang.v1.Secrets + (*SecretValue)(nil), // 37: io.defang.v1.SecretValue + (*Config)(nil), // 38: io.defang.v1.Config + (*ConfigKey)(nil), // 39: io.defang.v1.ConfigKey + (*PutConfigRequest)(nil), // 40: io.defang.v1.PutConfigRequest + (*GetConfigsRequest)(nil), // 41: io.defang.v1.GetConfigsRequest + (*GetConfigsResponse)(nil), // 42: io.defang.v1.GetConfigsResponse + (*DeleteConfigsRequest)(nil), // 43: io.defang.v1.DeleteConfigsRequest + (*ListConfigsRequest)(nil), // 44: io.defang.v1.ListConfigsRequest + (*ListConfigsResponse)(nil), // 45: io.defang.v1.ListConfigsResponse + (*Deployment)(nil), // 46: io.defang.v1.Deployment + (*PutDeploymentRequest)(nil), // 47: io.defang.v1.PutDeploymentRequest + (*ListDeploymentsRequest)(nil), // 48: io.defang.v1.ListDeploymentsRequest + (*ListDeploymentsResponse)(nil), // 49: io.defang.v1.ListDeploymentsResponse + (*TokenRequest)(nil), // 50: io.defang.v1.TokenRequest + (*TokenResponse)(nil), // 51: io.defang.v1.TokenResponse + (*Status)(nil), // 52: io.defang.v1.Status + (*Version)(nil), // 53: io.defang.v1.Version + (*TailRequest)(nil), // 54: io.defang.v1.TailRequest + (*LogEntry)(nil), // 55: io.defang.v1.LogEntry + (*TailResponse)(nil), // 56: io.defang.v1.TailResponse + (*GetServicesResponse)(nil), // 57: io.defang.v1.GetServicesResponse + (*ProjectUpdate)(nil), // 58: io.defang.v1.ProjectUpdate + (*ServiceID)(nil), // 59: io.defang.v1.ServiceID + (*GetRequest)(nil), // 60: io.defang.v1.GetRequest + (*Device)(nil), // 61: io.defang.v1.Device + (*Resource)(nil), // 62: io.defang.v1.Resource + (*Resources)(nil), // 63: io.defang.v1.Resources + (*Deploy)(nil), // 64: io.defang.v1.Deploy + (*Port)(nil), // 65: io.defang.v1.Port + (*Secret)(nil), // 66: io.defang.v1.Secret + (*Build)(nil), // 67: io.defang.v1.Build + (*HealthCheck)(nil), // 68: io.defang.v1.HealthCheck + (*Service)(nil), // 69: io.defang.v1.Service + (*StaticFiles)(nil), // 70: io.defang.v1.StaticFiles + (*Redis)(nil), // 71: io.defang.v1.Redis + (*DeployEvent)(nil), // 72: io.defang.v1.DeployEvent + (*Event)(nil), // 73: io.defang.v1.Event + (*PublishRequest)(nil), // 74: io.defang.v1.PublishRequest + (*SubscribeRequest)(nil), // 75: io.defang.v1.SubscribeRequest + (*SubscribeResponse)(nil), // 76: io.defang.v1.SubscribeResponse + (*GetServicesRequest)(nil), // 77: io.defang.v1.GetServicesRequest + (*DelegateSubdomainZoneRequest)(nil), // 78: io.defang.v1.DelegateSubdomainZoneRequest + (*DelegateSubdomainZoneResponse)(nil), // 79: io.defang.v1.DelegateSubdomainZoneResponse + (*SetOptionsRequest)(nil), // 80: io.defang.v1.SetOptionsRequest + (*WhoAmIResponse)(nil), // 81: io.defang.v1.WhoAmIResponse + nil, // 82: io.defang.v1.TrackRequest.PropertiesEntry + nil, // 83: io.defang.v1.Build.ArgsEntry + nil, // 84: io.defang.v1.Service.EnvironmentEntry + (*timestamppb.Timestamp)(nil), // 85: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 86: google.protobuf.Empty } var file_io_defang_v1_fabric_proto_depIdxs = []int32{ 0, // 0: io.defang.v1.GetSelectedProviderResponse.provider:type_name -> io.defang.v1.Provider 0, // 1: io.defang.v1.SetSelectedProviderRequest.provider:type_name -> io.defang.v1.Provider - 28, // 2: io.defang.v1.DebugRequest.files:type_name -> io.defang.v1.File - 84, // 3: io.defang.v1.DebugRequest.since:type_name -> google.protobuf.Timestamp - 18, // 4: io.defang.v1.DebugResponse.issues:type_name -> io.defang.v1.Issue - 19, // 5: io.defang.v1.Issue.code_changes:type_name -> io.defang.v1.CodeChange - 81, // 6: io.defang.v1.TrackRequest.properties:type_name -> io.defang.v1.TrackRequest.PropertiesEntry - 0, // 7: io.defang.v1.CanIUseRequest.provider:type_name -> io.defang.v1.Provider - 68, // 8: io.defang.v1.DeployRequest.services:type_name -> io.defang.v1.Service - 1, // 9: io.defang.v1.DeployRequest.mode:type_name -> io.defang.v1.DeploymentMode - 34, // 10: io.defang.v1.DeployResponse.services:type_name -> io.defang.v1.ServiceInfo - 28, // 11: io.defang.v1.GenerateFilesResponse.files:type_name -> io.defang.v1.File - 68, // 12: io.defang.v1.ServiceInfo.service:type_name -> io.defang.v1.Service - 84, // 13: io.defang.v1.ServiceInfo.created_at:type_name -> google.protobuf.Timestamp - 84, // 14: io.defang.v1.ServiceInfo.updated_at:type_name -> google.protobuf.Timestamp - 2, // 15: io.defang.v1.ServiceInfo.state:type_name -> io.defang.v1.ServiceState - 3, // 16: io.defang.v1.Config.type:type_name -> io.defang.v1.ConfigType - 3, // 17: io.defang.v1.PutConfigRequest.type:type_name -> io.defang.v1.ConfigType - 38, // 18: io.defang.v1.GetConfigsRequest.configs:type_name -> io.defang.v1.ConfigKey - 37, // 19: io.defang.v1.GetConfigsResponse.configs:type_name -> io.defang.v1.Config - 38, // 20: io.defang.v1.DeleteConfigsRequest.configs:type_name -> io.defang.v1.ConfigKey - 38, // 21: io.defang.v1.ListConfigsResponse.configs:type_name -> io.defang.v1.ConfigKey - 84, // 22: io.defang.v1.Deployment.timestamp:type_name -> google.protobuf.Timestamp - 4, // 23: io.defang.v1.Deployment.action:type_name -> io.defang.v1.DeploymentAction - 45, // 24: io.defang.v1.PutDeploymentRequest.deployment:type_name -> io.defang.v1.Deployment - 45, // 25: io.defang.v1.ListDeploymentsResponse.deployments:type_name -> io.defang.v1.Deployment - 84, // 26: io.defang.v1.TailRequest.since:type_name -> google.protobuf.Timestamp - 84, // 27: io.defang.v1.TailRequest.until:type_name -> google.protobuf.Timestamp - 84, // 28: io.defang.v1.LogEntry.timestamp:type_name -> google.protobuf.Timestamp - 54, // 29: io.defang.v1.TailResponse.entries:type_name -> io.defang.v1.LogEntry - 34, // 30: io.defang.v1.GetServicesResponse.services:type_name -> io.defang.v1.ServiceInfo - 84, // 31: io.defang.v1.GetServicesResponse.expires_at:type_name -> google.protobuf.Timestamp - 34, // 32: io.defang.v1.ProjectUpdate.services:type_name -> io.defang.v1.ServiceInfo - 60, // 33: io.defang.v1.Resource.devices:type_name -> io.defang.v1.Device - 61, // 34: io.defang.v1.Resources.reservations:type_name -> io.defang.v1.Resource - 62, // 35: io.defang.v1.Deploy.resources:type_name -> io.defang.v1.Resources - 6, // 36: io.defang.v1.Port.protocol:type_name -> io.defang.v1.Protocol - 7, // 37: io.defang.v1.Port.mode:type_name -> io.defang.v1.Mode - 82, // 38: io.defang.v1.Build.args:type_name -> io.defang.v1.Build.ArgsEntry - 5, // 39: io.defang.v1.Service.platform:type_name -> io.defang.v1.Platform - 63, // 40: io.defang.v1.Service.deploy:type_name -> io.defang.v1.Deploy - 64, // 41: io.defang.v1.Service.ports:type_name -> io.defang.v1.Port - 83, // 42: io.defang.v1.Service.environment:type_name -> io.defang.v1.Service.EnvironmentEntry - 66, // 43: io.defang.v1.Service.build:type_name -> io.defang.v1.Build - 65, // 44: io.defang.v1.Service.secrets:type_name -> io.defang.v1.Secret - 67, // 45: io.defang.v1.Service.healthcheck:type_name -> io.defang.v1.HealthCheck - 69, // 46: io.defang.v1.Service.static_files:type_name -> io.defang.v1.StaticFiles - 8, // 47: io.defang.v1.Service.networks:type_name -> io.defang.v1.Network - 70, // 48: io.defang.v1.Service.redis:type_name -> io.defang.v1.Redis - 1, // 49: io.defang.v1.DeployEvent.mode:type_name -> io.defang.v1.DeploymentMode - 84, // 50: io.defang.v1.DeployEvent.time:type_name -> google.protobuf.Timestamp - 84, // 51: io.defang.v1.Event.time:type_name -> google.protobuf.Timestamp - 72, // 52: io.defang.v1.PublishRequest.event:type_name -> io.defang.v1.Event - 34, // 53: io.defang.v1.SubscribeResponse.service:type_name -> io.defang.v1.ServiceInfo - 2, // 54: io.defang.v1.SubscribeResponse.state:type_name -> io.defang.v1.ServiceState - 9, // 55: io.defang.v1.WhoAmIResponse.tier:type_name -> io.defang.v1.SubscriptionTier - 85, // 56: io.defang.v1.FabricController.GetStatus:input_type -> google.protobuf.Empty - 85, // 57: io.defang.v1.FabricController.GetVersion:input_type -> google.protobuf.Empty - 49, // 58: io.defang.v1.FabricController.Token:input_type -> io.defang.v1.TokenRequest - 85, // 59: io.defang.v1.FabricController.RevokeToken:input_type -> google.protobuf.Empty - 53, // 60: io.defang.v1.FabricController.Tail:input_type -> io.defang.v1.TailRequest - 68, // 61: io.defang.v1.FabricController.Update:input_type -> io.defang.v1.Service - 23, // 62: io.defang.v1.FabricController.Deploy:input_type -> io.defang.v1.DeployRequest - 59, // 63: io.defang.v1.FabricController.Get:input_type -> io.defang.v1.GetRequest - 25, // 64: io.defang.v1.FabricController.Delete:input_type -> io.defang.v1.DeleteRequest - 14, // 65: io.defang.v1.FabricController.Destroy:input_type -> io.defang.v1.DestroyRequest - 73, // 66: io.defang.v1.FabricController.Publish:input_type -> io.defang.v1.PublishRequest - 74, // 67: io.defang.v1.FabricController.Subscribe:input_type -> io.defang.v1.SubscribeRequest - 76, // 68: io.defang.v1.FabricController.GetServices:input_type -> io.defang.v1.GetServicesRequest - 27, // 69: io.defang.v1.FabricController.GenerateFiles:input_type -> io.defang.v1.GenerateFilesRequest - 27, // 70: io.defang.v1.FabricController.StartGenerate:input_type -> io.defang.v1.GenerateFilesRequest - 31, // 71: io.defang.v1.FabricController.GenerateStatus:input_type -> io.defang.v1.GenerateStatusRequest - 16, // 72: io.defang.v1.FabricController.Debug:input_type -> io.defang.v1.DebugRequest - 85, // 73: io.defang.v1.FabricController.SignEULA:input_type -> google.protobuf.Empty - 85, // 74: io.defang.v1.FabricController.CheckToS:input_type -> google.protobuf.Empty - 39, // 75: io.defang.v1.FabricController.PutSecret:input_type -> io.defang.v1.PutConfigRequest - 35, // 76: io.defang.v1.FabricController.DeleteSecrets:input_type -> io.defang.v1.Secrets - 43, // 77: io.defang.v1.FabricController.ListSecrets:input_type -> io.defang.v1.ListConfigsRequest - 40, // 78: io.defang.v1.FabricController.GetConfigs:input_type -> io.defang.v1.GetConfigsRequest - 39, // 79: io.defang.v1.FabricController.PutConfig:input_type -> io.defang.v1.PutConfigRequest - 42, // 80: io.defang.v1.FabricController.DeleteConfigs:input_type -> io.defang.v1.DeleteConfigsRequest - 43, // 81: io.defang.v1.FabricController.ListConfigs:input_type -> io.defang.v1.ListConfigsRequest - 46, // 82: io.defang.v1.FabricController.PutDeployment:input_type -> io.defang.v1.PutDeploymentRequest - 47, // 83: io.defang.v1.FabricController.ListDeployments:input_type -> io.defang.v1.ListDeploymentsRequest - 32, // 84: io.defang.v1.FabricController.CreateUploadURL:input_type -> io.defang.v1.UploadURLRequest - 77, // 85: io.defang.v1.FabricController.DelegateSubdomainZone:input_type -> io.defang.v1.DelegateSubdomainZoneRequest - 85, // 86: io.defang.v1.FabricController.DeleteSubdomainZone:input_type -> google.protobuf.Empty - 85, // 87: io.defang.v1.FabricController.GetDelegateSubdomainZone:input_type -> google.protobuf.Empty - 79, // 88: io.defang.v1.FabricController.SetOptions:input_type -> io.defang.v1.SetOptionsRequest - 85, // 89: io.defang.v1.FabricController.WhoAmI:input_type -> google.protobuf.Empty - 20, // 90: io.defang.v1.FabricController.Track:input_type -> io.defang.v1.TrackRequest - 85, // 91: io.defang.v1.FabricController.DeleteMe:input_type -> google.protobuf.Empty - 13, // 92: io.defang.v1.FabricController.VerifyDNSSetup:input_type -> io.defang.v1.VerifyDNSSetupRequest - 10, // 93: io.defang.v1.FabricController.GetSelectedProvider:input_type -> io.defang.v1.GetSelectedProviderRequest - 12, // 94: io.defang.v1.FabricController.SetSelectedProvider:input_type -> io.defang.v1.SetSelectedProviderRequest - 21, // 95: io.defang.v1.FabricController.CanIUse:input_type -> io.defang.v1.CanIUseRequest - 51, // 96: io.defang.v1.FabricController.GetStatus:output_type -> io.defang.v1.Status - 52, // 97: io.defang.v1.FabricController.GetVersion:output_type -> io.defang.v1.Version - 50, // 98: io.defang.v1.FabricController.Token:output_type -> io.defang.v1.TokenResponse - 85, // 99: io.defang.v1.FabricController.RevokeToken:output_type -> google.protobuf.Empty - 55, // 100: io.defang.v1.FabricController.Tail:output_type -> io.defang.v1.TailResponse - 34, // 101: io.defang.v1.FabricController.Update:output_type -> io.defang.v1.ServiceInfo - 24, // 102: io.defang.v1.FabricController.Deploy:output_type -> io.defang.v1.DeployResponse - 34, // 103: io.defang.v1.FabricController.Get:output_type -> io.defang.v1.ServiceInfo - 26, // 104: io.defang.v1.FabricController.Delete:output_type -> io.defang.v1.DeleteResponse - 15, // 105: io.defang.v1.FabricController.Destroy:output_type -> io.defang.v1.DestroyResponse - 85, // 106: io.defang.v1.FabricController.Publish:output_type -> google.protobuf.Empty - 75, // 107: io.defang.v1.FabricController.Subscribe:output_type -> io.defang.v1.SubscribeResponse - 56, // 108: io.defang.v1.FabricController.GetServices:output_type -> io.defang.v1.GetServicesResponse - 29, // 109: io.defang.v1.FabricController.GenerateFiles:output_type -> io.defang.v1.GenerateFilesResponse - 30, // 110: io.defang.v1.FabricController.StartGenerate:output_type -> io.defang.v1.StartGenerateResponse - 29, // 111: io.defang.v1.FabricController.GenerateStatus:output_type -> io.defang.v1.GenerateFilesResponse - 17, // 112: io.defang.v1.FabricController.Debug:output_type -> io.defang.v1.DebugResponse - 85, // 113: io.defang.v1.FabricController.SignEULA:output_type -> google.protobuf.Empty - 85, // 114: io.defang.v1.FabricController.CheckToS:output_type -> google.protobuf.Empty - 85, // 115: io.defang.v1.FabricController.PutSecret:output_type -> google.protobuf.Empty - 85, // 116: io.defang.v1.FabricController.DeleteSecrets:output_type -> google.protobuf.Empty - 35, // 117: io.defang.v1.FabricController.ListSecrets:output_type -> io.defang.v1.Secrets - 41, // 118: io.defang.v1.FabricController.GetConfigs:output_type -> io.defang.v1.GetConfigsResponse - 85, // 119: io.defang.v1.FabricController.PutConfig:output_type -> google.protobuf.Empty - 85, // 120: io.defang.v1.FabricController.DeleteConfigs:output_type -> google.protobuf.Empty - 44, // 121: io.defang.v1.FabricController.ListConfigs:output_type -> io.defang.v1.ListConfigsResponse - 85, // 122: io.defang.v1.FabricController.PutDeployment:output_type -> google.protobuf.Empty - 48, // 123: io.defang.v1.FabricController.ListDeployments:output_type -> io.defang.v1.ListDeploymentsResponse - 33, // 124: io.defang.v1.FabricController.CreateUploadURL:output_type -> io.defang.v1.UploadURLResponse - 78, // 125: io.defang.v1.FabricController.DelegateSubdomainZone:output_type -> io.defang.v1.DelegateSubdomainZoneResponse - 85, // 126: io.defang.v1.FabricController.DeleteSubdomainZone:output_type -> google.protobuf.Empty - 78, // 127: io.defang.v1.FabricController.GetDelegateSubdomainZone:output_type -> io.defang.v1.DelegateSubdomainZoneResponse - 85, // 128: io.defang.v1.FabricController.SetOptions:output_type -> google.protobuf.Empty - 80, // 129: io.defang.v1.FabricController.WhoAmI:output_type -> io.defang.v1.WhoAmIResponse - 85, // 130: io.defang.v1.FabricController.Track:output_type -> google.protobuf.Empty - 85, // 131: io.defang.v1.FabricController.DeleteMe:output_type -> google.protobuf.Empty - 85, // 132: io.defang.v1.FabricController.VerifyDNSSetup:output_type -> google.protobuf.Empty - 11, // 133: io.defang.v1.FabricController.GetSelectedProvider:output_type -> io.defang.v1.GetSelectedProviderResponse - 85, // 134: io.defang.v1.FabricController.SetSelectedProvider:output_type -> google.protobuf.Empty - 22, // 135: io.defang.v1.FabricController.CanIUse:output_type -> io.defang.v1.CanIUseResponse - 96, // [96:136] is the sub-list for method output_type - 56, // [56:96] is the sub-list for method input_type - 56, // [56:56] is the sub-list for extension type_name - 56, // [56:56] is the sub-list for extension extendee - 0, // [0:56] is the sub-list for field type_name + 29, // 2: io.defang.v1.DebugRequest.files:type_name -> io.defang.v1.File + 85, // 3: io.defang.v1.DebugRequest.since:type_name -> google.protobuf.Timestamp + 85, // 4: io.defang.v1.DebugRequest.until:type_name -> google.protobuf.Timestamp + 19, // 5: io.defang.v1.DebugResponse.issues:type_name -> io.defang.v1.Issue + 20, // 6: io.defang.v1.Issue.code_changes:type_name -> io.defang.v1.CodeChange + 82, // 7: io.defang.v1.TrackRequest.properties:type_name -> io.defang.v1.TrackRequest.PropertiesEntry + 0, // 8: io.defang.v1.CanIUseRequest.provider:type_name -> io.defang.v1.Provider + 69, // 9: io.defang.v1.DeployRequest.services:type_name -> io.defang.v1.Service + 1, // 10: io.defang.v1.DeployRequest.mode:type_name -> io.defang.v1.DeploymentMode + 35, // 11: io.defang.v1.DeployResponse.services:type_name -> io.defang.v1.ServiceInfo + 29, // 12: io.defang.v1.GenerateFilesResponse.files:type_name -> io.defang.v1.File + 69, // 13: io.defang.v1.ServiceInfo.service:type_name -> io.defang.v1.Service + 85, // 14: io.defang.v1.ServiceInfo.created_at:type_name -> google.protobuf.Timestamp + 85, // 15: io.defang.v1.ServiceInfo.updated_at:type_name -> google.protobuf.Timestamp + 2, // 16: io.defang.v1.ServiceInfo.state:type_name -> io.defang.v1.ServiceState + 3, // 17: io.defang.v1.Config.type:type_name -> io.defang.v1.ConfigType + 3, // 18: io.defang.v1.PutConfigRequest.type:type_name -> io.defang.v1.ConfigType + 39, // 19: io.defang.v1.GetConfigsRequest.configs:type_name -> io.defang.v1.ConfigKey + 38, // 20: io.defang.v1.GetConfigsResponse.configs:type_name -> io.defang.v1.Config + 39, // 21: io.defang.v1.DeleteConfigsRequest.configs:type_name -> io.defang.v1.ConfigKey + 39, // 22: io.defang.v1.ListConfigsResponse.configs:type_name -> io.defang.v1.ConfigKey + 85, // 23: io.defang.v1.Deployment.timestamp:type_name -> google.protobuf.Timestamp + 4, // 24: io.defang.v1.Deployment.action:type_name -> io.defang.v1.DeploymentAction + 46, // 25: io.defang.v1.PutDeploymentRequest.deployment:type_name -> io.defang.v1.Deployment + 46, // 26: io.defang.v1.ListDeploymentsResponse.deployments:type_name -> io.defang.v1.Deployment + 85, // 27: io.defang.v1.TailRequest.since:type_name -> google.protobuf.Timestamp + 85, // 28: io.defang.v1.TailRequest.until:type_name -> google.protobuf.Timestamp + 85, // 29: io.defang.v1.LogEntry.timestamp:type_name -> google.protobuf.Timestamp + 55, // 30: io.defang.v1.TailResponse.entries:type_name -> io.defang.v1.LogEntry + 35, // 31: io.defang.v1.GetServicesResponse.services:type_name -> io.defang.v1.ServiceInfo + 85, // 32: io.defang.v1.GetServicesResponse.expires_at:type_name -> google.protobuf.Timestamp + 35, // 33: io.defang.v1.ProjectUpdate.services:type_name -> io.defang.v1.ServiceInfo + 1, // 34: io.defang.v1.ProjectUpdate.mode:type_name -> io.defang.v1.DeploymentMode + 61, // 35: io.defang.v1.Resource.devices:type_name -> io.defang.v1.Device + 62, // 36: io.defang.v1.Resources.reservations:type_name -> io.defang.v1.Resource + 63, // 37: io.defang.v1.Deploy.resources:type_name -> io.defang.v1.Resources + 6, // 38: io.defang.v1.Port.protocol:type_name -> io.defang.v1.Protocol + 7, // 39: io.defang.v1.Port.mode:type_name -> io.defang.v1.Mode + 83, // 40: io.defang.v1.Build.args:type_name -> io.defang.v1.Build.ArgsEntry + 5, // 41: io.defang.v1.Service.platform:type_name -> io.defang.v1.Platform + 64, // 42: io.defang.v1.Service.deploy:type_name -> io.defang.v1.Deploy + 65, // 43: io.defang.v1.Service.ports:type_name -> io.defang.v1.Port + 84, // 44: io.defang.v1.Service.environment:type_name -> io.defang.v1.Service.EnvironmentEntry + 67, // 45: io.defang.v1.Service.build:type_name -> io.defang.v1.Build + 66, // 46: io.defang.v1.Service.secrets:type_name -> io.defang.v1.Secret + 68, // 47: io.defang.v1.Service.healthcheck:type_name -> io.defang.v1.HealthCheck + 70, // 48: io.defang.v1.Service.static_files:type_name -> io.defang.v1.StaticFiles + 8, // 49: io.defang.v1.Service.networks:type_name -> io.defang.v1.Network + 71, // 50: io.defang.v1.Service.redis:type_name -> io.defang.v1.Redis + 1, // 51: io.defang.v1.DeployEvent.mode:type_name -> io.defang.v1.DeploymentMode + 85, // 52: io.defang.v1.DeployEvent.time:type_name -> google.protobuf.Timestamp + 85, // 53: io.defang.v1.Event.time:type_name -> google.protobuf.Timestamp + 73, // 54: io.defang.v1.PublishRequest.event:type_name -> io.defang.v1.Event + 35, // 55: io.defang.v1.SubscribeResponse.service:type_name -> io.defang.v1.ServiceInfo + 2, // 56: io.defang.v1.SubscribeResponse.state:type_name -> io.defang.v1.ServiceState + 9, // 57: io.defang.v1.WhoAmIResponse.tier:type_name -> io.defang.v1.SubscriptionTier + 86, // 58: io.defang.v1.FabricController.GetStatus:input_type -> google.protobuf.Empty + 86, // 59: io.defang.v1.FabricController.GetVersion:input_type -> google.protobuf.Empty + 50, // 60: io.defang.v1.FabricController.Token:input_type -> io.defang.v1.TokenRequest + 86, // 61: io.defang.v1.FabricController.RevokeToken:input_type -> google.protobuf.Empty + 54, // 62: io.defang.v1.FabricController.Tail:input_type -> io.defang.v1.TailRequest + 69, // 63: io.defang.v1.FabricController.Update:input_type -> io.defang.v1.Service + 24, // 64: io.defang.v1.FabricController.Deploy:input_type -> io.defang.v1.DeployRequest + 60, // 65: io.defang.v1.FabricController.Get:input_type -> io.defang.v1.GetRequest + 26, // 66: io.defang.v1.FabricController.Delete:input_type -> io.defang.v1.DeleteRequest + 15, // 67: io.defang.v1.FabricController.Destroy:input_type -> io.defang.v1.DestroyRequest + 74, // 68: io.defang.v1.FabricController.Publish:input_type -> io.defang.v1.PublishRequest + 75, // 69: io.defang.v1.FabricController.Subscribe:input_type -> io.defang.v1.SubscribeRequest + 77, // 70: io.defang.v1.FabricController.GetServices:input_type -> io.defang.v1.GetServicesRequest + 28, // 71: io.defang.v1.FabricController.GenerateFiles:input_type -> io.defang.v1.GenerateFilesRequest + 28, // 72: io.defang.v1.FabricController.StartGenerate:input_type -> io.defang.v1.GenerateFilesRequest + 32, // 73: io.defang.v1.FabricController.GenerateStatus:input_type -> io.defang.v1.GenerateStatusRequest + 17, // 74: io.defang.v1.FabricController.Debug:input_type -> io.defang.v1.DebugRequest + 86, // 75: io.defang.v1.FabricController.SignEULA:input_type -> google.protobuf.Empty + 86, // 76: io.defang.v1.FabricController.CheckToS:input_type -> google.protobuf.Empty + 40, // 77: io.defang.v1.FabricController.PutSecret:input_type -> io.defang.v1.PutConfigRequest + 36, // 78: io.defang.v1.FabricController.DeleteSecrets:input_type -> io.defang.v1.Secrets + 44, // 79: io.defang.v1.FabricController.ListSecrets:input_type -> io.defang.v1.ListConfigsRequest + 41, // 80: io.defang.v1.FabricController.GetConfigs:input_type -> io.defang.v1.GetConfigsRequest + 40, // 81: io.defang.v1.FabricController.PutConfig:input_type -> io.defang.v1.PutConfigRequest + 43, // 82: io.defang.v1.FabricController.DeleteConfigs:input_type -> io.defang.v1.DeleteConfigsRequest + 44, // 83: io.defang.v1.FabricController.ListConfigs:input_type -> io.defang.v1.ListConfigsRequest + 47, // 84: io.defang.v1.FabricController.PutDeployment:input_type -> io.defang.v1.PutDeploymentRequest + 48, // 85: io.defang.v1.FabricController.ListDeployments:input_type -> io.defang.v1.ListDeploymentsRequest + 33, // 86: io.defang.v1.FabricController.CreateUploadURL:input_type -> io.defang.v1.UploadURLRequest + 78, // 87: io.defang.v1.FabricController.DelegateSubdomainZone:input_type -> io.defang.v1.DelegateSubdomainZoneRequest + 86, // 88: io.defang.v1.FabricController.DeleteSubdomainZone:input_type -> google.protobuf.Empty + 86, // 89: io.defang.v1.FabricController.GetDelegateSubdomainZone:input_type -> google.protobuf.Empty + 80, // 90: io.defang.v1.FabricController.SetOptions:input_type -> io.defang.v1.SetOptionsRequest + 86, // 91: io.defang.v1.FabricController.WhoAmI:input_type -> google.protobuf.Empty + 21, // 92: io.defang.v1.FabricController.Track:input_type -> io.defang.v1.TrackRequest + 86, // 93: io.defang.v1.FabricController.DeleteMe:input_type -> google.protobuf.Empty + 14, // 94: io.defang.v1.FabricController.VerifyDNSSetup:input_type -> io.defang.v1.VerifyDNSSetupRequest + 11, // 95: io.defang.v1.FabricController.GetSelectedProvider:input_type -> io.defang.v1.GetSelectedProviderRequest + 13, // 96: io.defang.v1.FabricController.SetSelectedProvider:input_type -> io.defang.v1.SetSelectedProviderRequest + 22, // 97: io.defang.v1.FabricController.CanIUse:input_type -> io.defang.v1.CanIUseRequest + 52, // 98: io.defang.v1.FabricController.GetStatus:output_type -> io.defang.v1.Status + 53, // 99: io.defang.v1.FabricController.GetVersion:output_type -> io.defang.v1.Version + 51, // 100: io.defang.v1.FabricController.Token:output_type -> io.defang.v1.TokenResponse + 86, // 101: io.defang.v1.FabricController.RevokeToken:output_type -> google.protobuf.Empty + 56, // 102: io.defang.v1.FabricController.Tail:output_type -> io.defang.v1.TailResponse + 35, // 103: io.defang.v1.FabricController.Update:output_type -> io.defang.v1.ServiceInfo + 25, // 104: io.defang.v1.FabricController.Deploy:output_type -> io.defang.v1.DeployResponse + 35, // 105: io.defang.v1.FabricController.Get:output_type -> io.defang.v1.ServiceInfo + 27, // 106: io.defang.v1.FabricController.Delete:output_type -> io.defang.v1.DeleteResponse + 16, // 107: io.defang.v1.FabricController.Destroy:output_type -> io.defang.v1.DestroyResponse + 86, // 108: io.defang.v1.FabricController.Publish:output_type -> google.protobuf.Empty + 76, // 109: io.defang.v1.FabricController.Subscribe:output_type -> io.defang.v1.SubscribeResponse + 57, // 110: io.defang.v1.FabricController.GetServices:output_type -> io.defang.v1.GetServicesResponse + 30, // 111: io.defang.v1.FabricController.GenerateFiles:output_type -> io.defang.v1.GenerateFilesResponse + 31, // 112: io.defang.v1.FabricController.StartGenerate:output_type -> io.defang.v1.StartGenerateResponse + 30, // 113: io.defang.v1.FabricController.GenerateStatus:output_type -> io.defang.v1.GenerateFilesResponse + 18, // 114: io.defang.v1.FabricController.Debug:output_type -> io.defang.v1.DebugResponse + 86, // 115: io.defang.v1.FabricController.SignEULA:output_type -> google.protobuf.Empty + 86, // 116: io.defang.v1.FabricController.CheckToS:output_type -> google.protobuf.Empty + 86, // 117: io.defang.v1.FabricController.PutSecret:output_type -> google.protobuf.Empty + 86, // 118: io.defang.v1.FabricController.DeleteSecrets:output_type -> google.protobuf.Empty + 36, // 119: io.defang.v1.FabricController.ListSecrets:output_type -> io.defang.v1.Secrets + 42, // 120: io.defang.v1.FabricController.GetConfigs:output_type -> io.defang.v1.GetConfigsResponse + 86, // 121: io.defang.v1.FabricController.PutConfig:output_type -> google.protobuf.Empty + 86, // 122: io.defang.v1.FabricController.DeleteConfigs:output_type -> google.protobuf.Empty + 45, // 123: io.defang.v1.FabricController.ListConfigs:output_type -> io.defang.v1.ListConfigsResponse + 86, // 124: io.defang.v1.FabricController.PutDeployment:output_type -> google.protobuf.Empty + 49, // 125: io.defang.v1.FabricController.ListDeployments:output_type -> io.defang.v1.ListDeploymentsResponse + 34, // 126: io.defang.v1.FabricController.CreateUploadURL:output_type -> io.defang.v1.UploadURLResponse + 79, // 127: io.defang.v1.FabricController.DelegateSubdomainZone:output_type -> io.defang.v1.DelegateSubdomainZoneResponse + 86, // 128: io.defang.v1.FabricController.DeleteSubdomainZone:output_type -> google.protobuf.Empty + 79, // 129: io.defang.v1.FabricController.GetDelegateSubdomainZone:output_type -> io.defang.v1.DelegateSubdomainZoneResponse + 86, // 130: io.defang.v1.FabricController.SetOptions:output_type -> google.protobuf.Empty + 81, // 131: io.defang.v1.FabricController.WhoAmI:output_type -> io.defang.v1.WhoAmIResponse + 86, // 132: io.defang.v1.FabricController.Track:output_type -> google.protobuf.Empty + 86, // 133: io.defang.v1.FabricController.DeleteMe:output_type -> google.protobuf.Empty + 86, // 134: io.defang.v1.FabricController.VerifyDNSSetup:output_type -> google.protobuf.Empty + 12, // 135: io.defang.v1.FabricController.GetSelectedProvider:output_type -> io.defang.v1.GetSelectedProviderResponse + 86, // 136: io.defang.v1.FabricController.SetSelectedProvider:output_type -> google.protobuf.Empty + 23, // 137: io.defang.v1.FabricController.CanIUse:output_type -> io.defang.v1.CanIUseResponse + 98, // [98:138] is the sub-list for method output_type + 58, // [58:98] is the sub-list for method input_type + 58, // [58:58] is the sub-list for extension type_name + 58, // [58:58] is the sub-list for extension extendee + 0, // [0:58] is the sub-list for field type_name } func init() { file_io_defang_v1_fabric_proto_init() } @@ -6025,7 +6108,7 @@ func file_io_defang_v1_fabric_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_io_defang_v1_fabric_proto_rawDesc, - NumEnums: 10, + NumEnums: 11, NumMessages: 74, NumExtensions: 0, NumServices: 1, diff --git a/src/protos/io/defang/v1/fabric.proto b/src/protos/io/defang/v1/fabric.proto index af3a49121..6e8135236 100644 --- a/src/protos/io/defang/v1/fabric.proto +++ b/src/protos/io/defang/v1/fabric.proto @@ -167,6 +167,7 @@ message DebugRequest { repeated string services = 5; bool training_opt_out = 6; // only valid for Pro users google.protobuf.Timestamp since = 7; + google.protobuf.Timestamp until = 8; } message DebugResponse { @@ -409,7 +410,13 @@ message TailRequest { google.protobuf.Timestamp since = 2; string etag = 3; string project = 4; - uint32 log_type = 5; + enum LogType { + LOG_TYPE_UNSPECIFIED = 0; + LOG_TYPE_CD = 1; + LOG_TYPE_BUILD = 2; + LOG_TYPE_RUN = 4; + } + uint32 log_type = 5; // bitfield string pattern = 6; google.protobuf.Timestamp until = 7; } @@ -443,6 +450,7 @@ message ProjectUpdate { string project = 3 [ deprecated = true ]; // deprecated; use compose.name bytes compose = 4; string cd_version = 5; + DeploymentMode mode = 6; } enum Platform {