From 79dc05cb665d6541ea2ff1ca16af4119ae6b47d4 Mon Sep 17 00:00:00 2001 From: Pasha Sviderski Date: Tue, 2 Dec 2025 19:50:48 +1000 Subject: [PATCH] feat: service logs command to stream service logs (#196) * chore: fix landing logo shadow * feat: implement service logs command with colored output and strict ordering * revert Makefile * fix after rebase * move logs command under services with root shortcut * simplify server options for streaming logs and CLI flags * refactor ContainerLogs grpc server * update --tail flag * minor docker.proto * refactor client ServiceLogs and ContainerLogs * move ProxyMachinesContext from api to client pkg * minor refactor proto Stream * add api/logs * implement LogMerger * fix LogMerger to correctly use semaphore * increate inflish entries to 100 per stream * send heartbeats * refactor ContainerLogs to synchronise Send of entries and heartbeats to the steram * minor logmerege * remove ContainerName form ServiceLogEntryMetadata * refactor ContainerLogs into docker.Service * detect stalled container logs streams * update logmerger tests * fix comment in test * refactor LogMerger with options * uc logs: format one or multiple services * make LogMerger emit heartbeats, emit entries <= watermark, rewrite tests * update uc logs with new LogMerger * go mod tidy * fix after merge --------- Co-authored-by: Evgenii Orlov --- cmd/uncloud/caddy/config.go | 3 +- cmd/uncloud/machine/rm.go | 2 +- cmd/uncloud/machine/root.go | 2 +- cmd/uncloud/main.go | 3 +- cmd/uncloud/ps.go | 12 +- cmd/uncloud/service/logs.go | 279 ++ cmd/uncloud/service/root.go | 5 +- cmd/uncloud/volume/root.go | 2 +- go.mod | 2 +- go.sum | 4 +- internal/machine/api/pb/docker.pb.go | 3813 +++++++++++---------- internal/machine/api/pb/docker.proto | 100 +- internal/machine/api/pb/docker_grpc.pb.go | 105 +- internal/machine/docker/server.go | 92 + internal/machine/docker/service.go | 105 + pkg/api/client.go | 41 - pkg/api/logs.go | 84 + pkg/api/service.go | 11 + pkg/client/client.go | 39 + pkg/client/image.go | 2 +- pkg/client/logmerger.go | 310 ++ pkg/client/logmerger_test.go | 383 +++ pkg/client/logs.go | 141 + pkg/client/machine.go | 40 +- pkg/client/volume.go | 2 +- 25 files changed, 3657 insertions(+), 1925 deletions(-) create mode 100644 cmd/uncloud/service/logs.go create mode 100644 pkg/api/logs.go create mode 100644 pkg/client/logmerger.go create mode 100644 pkg/client/logmerger_test.go create mode 100644 pkg/client/logs.go diff --git a/cmd/uncloud/caddy/config.go b/cmd/uncloud/caddy/config.go index 356af55b..28d6733d 100644 --- a/cmd/uncloud/caddy/config.go +++ b/cmd/uncloud/caddy/config.go @@ -7,7 +7,6 @@ import ( "github.com/alecthomas/chroma/v2/quick" "github.com/psviderski/uncloud/internal/cli" - "github.com/psviderski/uncloud/pkg/api" "github.com/spf13/cobra" ) @@ -46,7 +45,7 @@ func runConfig(ctx context.Context, uncli *cli.CLI, opts configOptions) error { if opts.machine != "" { // If a specific machine is requested, use it to get the Caddy configuration. - ctx, _, err = api.ProxyMachinesContext(ctx, clusterClient, []string{opts.machine}) + ctx, _, err = clusterClient.ProxyMachinesContext(ctx, []string{opts.machine}) if err != nil { return err } diff --git a/cmd/uncloud/machine/rm.go b/cmd/uncloud/machine/rm.go index a50a9eb7..da4c247e 100644 --- a/cmd/uncloud/machine/rm.go +++ b/cmd/uncloud/machine/rm.go @@ -55,7 +55,7 @@ func remove(ctx context.Context, uncli *cli.CLI, nameOrID string, opts removeOpt defer client.Close() // Verify the machine exists and list all service containers on it including stopped ones. - mctx, machines, err := api.ProxyMachinesContext(ctx, client, []string{nameOrID}) + mctx, machines, err := client.ProxyMachinesContext(ctx, []string{nameOrID}) if err != nil { return err } diff --git a/cmd/uncloud/machine/root.go b/cmd/uncloud/machine/root.go index 16e5b360..6d984075 100644 --- a/cmd/uncloud/machine/root.go +++ b/cmd/uncloud/machine/root.go @@ -8,7 +8,7 @@ func NewRootCommand() *cobra.Command { cmd := &cobra.Command{ Use: "machine", Aliases: []string{"m"}, - Short: "Manage machines in an Uncloud cluster.", + Short: "Manage machines in the cluster.", } cmd.AddCommand( NewAddCommand(), diff --git a/cmd/uncloud/main.go b/cmd/uncloud/main.go index bf65e3d5..ebd07fc7 100644 --- a/cmd/uncloud/main.go +++ b/cmd/uncloud/main.go @@ -108,9 +108,9 @@ func main() { }) cmd.AddCommand( + NewBuildCommand(), NewDeployCommand(), NewDocsCommand(), - NewBuildCommand(), NewImagesCommand(), NewPsCommand(), caddy.NewRootCommand(), @@ -122,6 +122,7 @@ func main() { service.NewExecCommand(), service.NewInspectCommand(), service.NewListCommand(), + service.NewLogsCommand(), service.NewRmCommand(), service.NewRunCommand(), service.NewScaleCommand(), diff --git a/cmd/uncloud/ps.go b/cmd/uncloud/ps.go index ac310ffa..c7032588 100644 --- a/cmd/uncloud/ps.go +++ b/cmd/uncloud/ps.go @@ -12,7 +12,6 @@ import ( "github.com/spf13/cobra" "github.com/psviderski/uncloud/internal/cli" - "github.com/psviderski/uncloud/pkg/api" "github.com/psviderski/uncloud/pkg/client" ) @@ -46,12 +45,14 @@ This command provides a comprehensive overview of all running containers that ar making it easy to see the distribution and status of containers across the cluster.`, RunE: func(cmd *cobra.Command, args []string) error { if opts.sortBy != sortByService && opts.sortBy != sortByMachine && opts.sortBy != sortByHealth { - return fmt.Errorf("invalid value for --sort: %q, must be one of '%s', '%s' or '%s'", opts.sortBy, sortByService, sortByMachine, sortByHealth) + return fmt.Errorf("invalid value for --sort: %q, must be one of '%s', '%s' or '%s'", opts.sortBy, + sortByService, sortByMachine, sortByHealth) } return runPs(cmd, opts) }, } - cmd.Flags().StringVarP(&opts.sortBy, "sort", "s", sortByService, "Sort containers by 'service', 'machine' or 'health'") + cmd.Flags().StringVarP(&opts.sortBy, "sort", "s", sortByService, + "Sort containers by 'service', 'machine' or 'health'") return cmd } @@ -176,7 +177,7 @@ func printContainers(containers []containerInfo) error { } func collectContainers(ctx context.Context, cli *client.Client) ([]containerInfo, error) { - listCtx, machines, err := api.ProxyMachinesContext(ctx, cli, nil) + listCtx, machines, err := cli.ProxyMachinesContext(ctx, nil) if err != nil { return nil, fmt.Errorf("proxy machines context: %w", err) } @@ -206,7 +207,8 @@ func collectContainers(ctx context.Context, cli *client.Client) ([]containerInfo return nil, fmt.Errorf("something went wrong with gRPC proxy: metadata is missing for a machine response") } if msc.Metadata != nil && msc.Metadata.Error != "" { - client.PrintWarning(fmt.Sprintf("failed to list containers on machine %s: %s", machineName, msc.Metadata.Error)) + client.PrintWarning(fmt.Sprintf("failed to list containers on machine %s: %s", machineName, + msc.Metadata.Error)) continue } diff --git a/cmd/uncloud/service/logs.go b/cmd/uncloud/service/logs.go new file mode 100644 index 00000000..0bcc01ba --- /dev/null +++ b/cmd/uncloud/service/logs.go @@ -0,0 +1,279 @@ +package service + +import ( + "context" + "errors" + "fmt" + "os" + "slices" + "strconv" + "strings" + "time" + + "github.com/charmbracelet/lipgloss" + mapset "github.com/deckarep/golang-set/v2" + "github.com/docker/docker/pkg/stringid" + "github.com/psviderski/uncloud/internal/cli" + "github.com/psviderski/uncloud/pkg/api" + "github.com/psviderski/uncloud/pkg/client" + "github.com/spf13/cobra" +) + +type logsOptions struct { + follow bool + tail string + since string + until string +} + +func NewLogsCommand() *cobra.Command { + var options logsOptions + + cmd := &cobra.Command{ + Use: "logs SERVICE [SERVICE...]", + Aliases: []string{"log"}, + Short: "View service logs.", + Long: "View logs from all replicas of the specified service(s) across all machines in the cluster.", + Args: cobra.MinimumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + uncli := cmd.Context().Value("cli").(*cli.CLI) + return streamLogs(cmd.Context(), uncli, args, options) + }, + } + + cmd.Flags().BoolVarP(&options.follow, "follow", "f", false, + "Continually stream new logs.") + cmd.Flags().StringVarP(&options.tail, "tail", "n", "100", + "Show the most recent logs and limit the number of lines shown per replica. Use 'all' to show all logs.") + cmd.Flags().StringVar(&options.since, "since", "", + "Show logs generated on or after the given timestamp. Accepts relative duration, RFC 3339 date, or Unix timestamp.\n"+ + "Examples:\n"+ + " --since 2m30s Relative duration (2 minutes 30 seconds ago)\n"+ + " --since 1h Relative duration (1 hour ago)\n"+ + " --since 2025-11-24 RFC 3339 date only (midnight using local timezone)\n"+ + " --since 2024-05-14T22:50:00 RFC 3339 date/time using local timezone\n"+ + " --since 2024-01-31T10:30:00Z RFC 3339 date/time in UTC\n"+ + " --since 1763953966 Unix timestamp (seconds since January 1, 1970)") + cmd.Flags().StringVar(&options.until, "until", "", + "Show logs generated before the given timestamp. Accepts relative duration, RFC 3339 date, or Unix timestamp.\n"+ + "See --since for examples.") + + return cmd +} + +func streamLogs(ctx context.Context, uncli *cli.CLI, serviceNames []string, opts logsOptions) error { + // Parse tail option. + tail := -1 + if opts.tail != "all" { + tailInt, err := strconv.Atoi(opts.tail) + if err != nil { + return fmt.Errorf("invalid --tail value '%s': %w", opts.tail, err) + } + tail = tailInt + } + + c, err := uncli.ConnectCluster(ctx) + if err != nil { + return fmt.Errorf("connect to cluster: %w", err) + } + defer c.Close() + + logsOpts := api.ServiceLogsOptions{ + Follow: opts.follow, + Tail: tail, + Since: opts.since, + Until: opts.until, + } + + // Collect log streams from all services. + machineIDsSet := mapset.NewSet[string]() + svcStreams := make([]<-chan api.ServiceLogEntry, 0, len(serviceNames)) + for _, serviceName := range serviceNames { + // TODO: set Heartbeats in the opts. + svc, ch, err := c.ServiceLogs(ctx, serviceName, logsOpts) + if err != nil { + return fmt.Errorf("stream logs for service '%s': %w", serviceName, err) + } + svcStreams = append(svcStreams, ch) + + machineIDs := svc.MachineIDs() + machineIDsSet.Append(machineIDs...) + } + + var stream <-chan api.ServiceLogEntry + if len(serviceNames) == 1 { + stream = svcStreams[0] + } else { + // Merge all service streams into a single sorted stream without stall detection as its handled per-service. + merger := client.NewLogMerger(svcStreams, client.LogMergerOptions{}) + stream = merger.Stream() + } + + // Fetch machine names for all machines (machineIDsSet) service containers are running on. + machines, err := c.ListMachines(ctx, &api.MachineFilter{NamesOrIDs: machineIDsSet.ToSlice()}) + if err != nil { + return fmt.Errorf("list machines: %w", err) + } + machineNames := make([]string, 0, len(machines)) + for _, m := range machines { + machineNames = append(machineNames, m.Machine.Name) + } + + formatter := newLogFormatter(machineNames, serviceNames) + + // Print merged logs. + for entry := range stream { + if entry.Err != nil { + formatter.printError(entry) + continue + } + formatter.printEntry(entry) + } + + return nil +} + +// Available colors for machine/service differentiation. +var colorPalette = []lipgloss.Color{ + lipgloss.Color("10"), // Bright green + lipgloss.Color("11"), // Bright yellow + lipgloss.Color("12"), // Bright blue + lipgloss.Color("13"), // Bright magenta + lipgloss.Color("14"), // Bright cyan + lipgloss.Color("2"), // Green + lipgloss.Color("3"), // Yellow + lipgloss.Color("4"), // Blue + lipgloss.Color("5"), // Magenta + lipgloss.Color("6"), // Cyan +} + +// logFormatter handles formatting and printing of log entries with dynamic column alignment. +type logFormatter struct { + machineNames []string + serviceNames []string + + maxMachineWidth int + maxServiceWidth int +} + +func newLogFormatter(machineNames, serviceNames []string) *logFormatter { + slices.Sort(machineNames) + slices.Sort(serviceNames) + + maxMachineWidth := 0 + for _, name := range machineNames { + if len(name) > maxMachineWidth { + maxMachineWidth = len(name) + } + } + + maxServiceWidth := 0 + for _, name := range serviceNames { + if len(name) > maxServiceWidth { + maxServiceWidth = len(name) + } + } + + return &logFormatter{ + machineNames: machineNames, + serviceNames: serviceNames, + maxMachineWidth: maxMachineWidth, + maxServiceWidth: maxServiceWidth, + } +} + +// formatTimestamp formats timestamp using local timezone. +func (f *logFormatter) formatTimestamp(t time.Time) string { + dimStyle := lipgloss.NewStyle().Faint(true) + t = t.In(time.Local) + return dimStyle.Render(t.Format(time.StampMilli)) +} + +func (f *logFormatter) formatMachine(name string) string { + style := lipgloss.NewStyle().Bold(true).PaddingRight(f.maxMachineWidth - len(name)) + + if len(f.serviceNames) == 1 { + // Machine name is coloured for single-service logs. + i := slices.Index(f.machineNames, name) + if i == -1 { + f.machineNames = append(f.machineNames, name) + i = len(f.machineNames) - 1 + } + + style = style.Foreground(colorPalette[i%len(colorPalette)]) + } + + return style.Render(name) +} + +func (f *logFormatter) formatServiceContainer(serviceName, containerID string) string { + styleService := lipgloss.NewStyle().Bold(true).PaddingRight(f.maxServiceWidth - len(serviceName)) + styleContainer := lipgloss.NewStyle().Faint(true) + + if len(f.serviceNames) > 1 { + // Service name is coloured for multi-service logs. + i := slices.Index(f.serviceNames, serviceName) + if i == -1 { + f.serviceNames = append(f.serviceNames, serviceName) + i = len(f.serviceNames) - 1 + } + + styleService = styleService.Foreground(colorPalette[i%len(colorPalette)]) + } + + return styleService.Render(serviceName) + styleContainer.Render("["+containerID[:5]+"]") +} + +// printEntry prints a single log entry with proper formatting. +func (f *logFormatter) printEntry(entry api.ServiceLogEntry) { + if entry.Stream != api.LogStreamStdout && entry.Stream != api.LogStreamStderr { + return + } + + var output strings.Builder + + // Timestamp + output.WriteString(f.formatTimestamp(entry.Timestamp)) + output.WriteString(" ") + + // Machine name + output.WriteString(f.formatMachine(entry.Metadata.MachineName)) + output.WriteString(" ") + + // Service[container_id] + output.WriteString(f.formatServiceContainer(entry.Metadata.ServiceName, entry.Metadata.ContainerID)) + output.WriteString(" ") + + // Message + output.Write(entry.Message) + + // Print to appropriate stream. + if entry.Stream == api.LogStreamStderr { + fmt.Fprint(os.Stderr, output.String()) + } else { + fmt.Print(output.String()) + } +} + +// printError prints an error entry (e.g., stalled stream warning). +func (f *logFormatter) printError(entry api.ServiceLogEntry) { + if entry.Metadata.ContainerID != "" { + msg := fmt.Sprintf("WARNING: log stream from %s[%s] on machine '%s'", + entry.Metadata.ServiceName, + stringid.TruncateID(entry.Metadata.ContainerID), + entry.Metadata.MachineName) + + if errors.Is(entry.Err, api.ErrLogStreamStalled) { + msg += " stopped responding" + } else { + msg += fmt.Sprintf(": %v", entry.Err) + } + + style := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("11")) // Bold bright yellow + fmt.Fprintln(os.Stderr, style.Render(msg)) + } else { + msg := fmt.Sprintf("ERROR: %v", entry.Err) + style := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("9")) // Bold bright red + fmt.Fprintln(os.Stderr, style.Render(msg)) + } +} diff --git a/cmd/uncloud/service/root.go b/cmd/uncloud/service/root.go index 5a33c541..236d66eb 100644 --- a/cmd/uncloud/service/root.go +++ b/cmd/uncloud/service/root.go @@ -8,15 +8,16 @@ func NewRootCommand() *cobra.Command { cmd := &cobra.Command{ Use: "service", Aliases: []string{"svc"}, - Short: "Manage services in an Uncloud cluster.", + Short: "Manage services in the cluster.", } cmd.AddCommand( + NewExecCommand(), NewInspectCommand(), NewListCommand(), + NewLogsCommand(), NewRmCommand(), NewRunCommand(), NewScaleCommand(), - NewExecCommand(), ) return cmd } diff --git a/cmd/uncloud/volume/root.go b/cmd/uncloud/volume/root.go index 1e8f6eea..ca5cf358 100644 --- a/cmd/uncloud/volume/root.go +++ b/cmd/uncloud/volume/root.go @@ -7,7 +7,7 @@ import ( func NewRootCommand() *cobra.Command { cmd := &cobra.Command{ Use: "volume", - Short: "Manage volumes in an Uncloud cluster.", + Short: "Manage volumes in the cluster.", } cmd.AddCommand( NewCreateCommand(), diff --git a/go.mod b/go.mod index fcc5998c..2475639b 100644 --- a/go.mod +++ b/go.mod @@ -150,7 +150,7 @@ require ( github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect - github.com/fatih/color v1.17.0 // indirect + github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsevents v0.2.0 // indirect github.com/fvbommel/sortorder v1.1.0 // indirect diff --git a/go.sum b/go.sum index 46c02d4b..5e2bcbbf 100644 --- a/go.sum +++ b/go.sum @@ -346,8 +346,8 @@ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97 github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= -github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= diff --git a/internal/machine/api/pb/docker.pb.go b/internal/machine/api/pb/docker.pb.go index 35e44621..2905e680 100644 --- a/internal/machine/api/pb/docker.pb.go +++ b/internal/machine/api/pb/docker.pb.go @@ -10,6 +10,7 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" emptypb "google.golang.org/protobuf/types/known/emptypb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" ) @@ -21,6 +22,58 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type ContainerLogEntry_StreamType int32 + +const ( + ContainerLogEntry_UNKNOWN ContainerLogEntry_StreamType = 0 + ContainerLogEntry_STDOUT ContainerLogEntry_StreamType = 1 + ContainerLogEntry_STDERR ContainerLogEntry_StreamType = 2 + ContainerLogEntry_HEARTBEAT ContainerLogEntry_StreamType = 3 +) + +// Enum value maps for ContainerLogEntry_StreamType. +var ( + ContainerLogEntry_StreamType_name = map[int32]string{ + 0: "UNKNOWN", + 1: "STDOUT", + 2: "STDERR", + 3: "HEARTBEAT", + } + ContainerLogEntry_StreamType_value = map[string]int32{ + "UNKNOWN": 0, + "STDOUT": 1, + "STDERR": 2, + "HEARTBEAT": 3, + } +) + +func (x ContainerLogEntry_StreamType) Enum() *ContainerLogEntry_StreamType { + p := new(ContainerLogEntry_StreamType) + *p = x + return p +} + +func (x ContainerLogEntry_StreamType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ContainerLogEntry_StreamType) Descriptor() protoreflect.EnumDescriptor { + return file_internal_machine_api_pb_docker_proto_enumTypes[0].Descriptor() +} + +func (ContainerLogEntry_StreamType) Type() protoreflect.EnumType { + return &file_internal_machine_api_pb_docker_proto_enumTypes[0] +} + +func (x ContainerLogEntry_StreamType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ContainerLogEntry_StreamType.Descriptor instead. +func (ContainerLogEntry_StreamType) EnumDescriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{15, 0} +} + type CreateContainerRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -567,1166 +620,6 @@ func (x *RemoveContainerRequest) GetOptions() []byte { return nil } -type PullImageRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Image string `protobuf:"bytes,1,opt,name=image,proto3" json:"image,omitempty"` - // JSON serialised image.PullOptions. - Options []byte `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` -} - -func (x *PullImageRequest) Reset() { - *x = PullImageRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PullImageRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PullImageRequest) ProtoMessage() {} - -func (x *PullImageRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PullImageRequest.ProtoReflect.Descriptor instead. -func (*PullImageRequest) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{10} -} - -func (x *PullImageRequest) GetImage() string { - if x != nil { - return x.Image - } - return "" -} - -func (x *PullImageRequest) GetOptions() []byte { - if x != nil { - return x.Options - } - return nil -} - -type JSONMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // JSON serialised jsonmessage.JSONMessage. - Message []byte `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` -} - -func (x *JSONMessage) Reset() { - *x = JSONMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *JSONMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*JSONMessage) ProtoMessage() {} - -func (x *JSONMessage) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use JSONMessage.ProtoReflect.Descriptor instead. -func (*JSONMessage) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{11} -} - -func (x *JSONMessage) GetMessage() []byte { - if x != nil { - return x.Message - } - return nil -} - -type InspectImageRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` -} - -func (x *InspectImageRequest) Reset() { - *x = InspectImageRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *InspectImageRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*InspectImageRequest) ProtoMessage() {} - -func (x *InspectImageRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[12] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use InspectImageRequest.ProtoReflect.Descriptor instead. -func (*InspectImageRequest) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{12} -} - -func (x *InspectImageRequest) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -type InspectImageResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Must contain only one repeated messages field to allow broadcasting InspectImage requests to multiple machines. - Messages []*Image `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` -} - -func (x *InspectImageResponse) Reset() { - *x = InspectImageResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *InspectImageResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*InspectImageResponse) ProtoMessage() {} - -func (x *InspectImageResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[13] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use InspectImageResponse.ProtoReflect.Descriptor instead. -func (*InspectImageResponse) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{13} -} - -func (x *InspectImageResponse) GetMessages() []*Image { - if x != nil { - return x.Messages - } - return nil -} - -type Image struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` - // JSON serialised image.InspectResponse. - Image []byte `protobuf:"bytes,2,opt,name=image,proto3" json:"image,omitempty"` -} - -func (x *Image) Reset() { - *x = Image{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[14] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Image) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Image) ProtoMessage() {} - -func (x *Image) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[14] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Image.ProtoReflect.Descriptor instead. -func (*Image) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{14} -} - -func (x *Image) GetMetadata() *Metadata { - if x != nil { - return x.Metadata - } - return nil -} - -func (x *Image) GetImage() []byte { - if x != nil { - return x.Image - } - return nil -} - -type InspectRemoteImageRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` -} - -func (x *InspectRemoteImageRequest) Reset() { - *x = InspectRemoteImageRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[15] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *InspectRemoteImageRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*InspectRemoteImageRequest) ProtoMessage() {} - -func (x *InspectRemoteImageRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[15] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use InspectRemoteImageRequest.ProtoReflect.Descriptor instead. -func (*InspectRemoteImageRequest) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{15} -} - -func (x *InspectRemoteImageRequest) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -type InspectRemoteImageResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Must contain only one repeated messages field to allow broadcasting InspectRemoteImage requests to multiple machines. - Messages []*RemoteImage `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` -} - -func (x *InspectRemoteImageResponse) Reset() { - *x = InspectRemoteImageResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *InspectRemoteImageResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*InspectRemoteImageResponse) ProtoMessage() {} - -func (x *InspectRemoteImageResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[16] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use InspectRemoteImageResponse.ProtoReflect.Descriptor instead. -func (*InspectRemoteImageResponse) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{16} -} - -func (x *InspectRemoteImageResponse) GetMessages() []*RemoteImage { - if x != nil { - return x.Messages - } - return nil -} - -type RemoteImage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` - // Image reference in the canonical form with the digest. - Reference string `protobuf:"bytes,2,opt,name=reference,proto3" json:"reference,omitempty"` - // Raw JSON manifest from the registry. - Manifest []byte `protobuf:"bytes,3,opt,name=manifest,proto3" json:"manifest,omitempty"` -} - -func (x *RemoteImage) Reset() { - *x = RemoteImage{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[17] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RemoteImage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RemoteImage) ProtoMessage() {} - -func (x *RemoteImage) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[17] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RemoteImage.ProtoReflect.Descriptor instead. -func (*RemoteImage) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{17} -} - -func (x *RemoteImage) GetMetadata() *Metadata { - if x != nil { - return x.Metadata - } - return nil -} - -func (x *RemoteImage) GetReference() string { - if x != nil { - return x.Reference - } - return "" -} - -func (x *RemoteImage) GetManifest() []byte { - if x != nil { - return x.Manifest - } - return nil -} - -type ListImagesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // JSON serialised image.ListOptions. - Options []byte `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"` -} - -func (x *ListImagesRequest) Reset() { - *x = ListImagesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListImagesRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListImagesRequest) ProtoMessage() {} - -func (x *ListImagesRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListImagesRequest.ProtoReflect.Descriptor instead. -func (*ListImagesRequest) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{18} -} - -func (x *ListImagesRequest) GetOptions() []byte { - if x != nil { - return x.Options - } - return nil -} - -type ListImagesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Must contain only one repeated messages field to allow broadcasting ListImages requests to multiple machines. - Messages []*MachineImages `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` -} - -func (x *ListImagesResponse) Reset() { - *x = ListImagesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListImagesResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListImagesResponse) ProtoMessage() {} - -func (x *ListImagesResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListImagesResponse.ProtoReflect.Descriptor instead. -func (*ListImagesResponse) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{19} -} - -func (x *ListImagesResponse) GetMessages() []*MachineImages { - if x != nil { - return x.Messages - } - return nil -} - -type MachineImages struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` - // JSON serialised []image.Summary. - Images []byte `protobuf:"bytes,2,opt,name=images,proto3" json:"images,omitempty"` - // True if Docker uses the containerd image store, false if it uses its internal image store. - ContainerdStore bool `protobuf:"varint,3,opt,name=containerd_store,json=containerdStore,proto3" json:"containerd_store,omitempty"` -} - -func (x *MachineImages) Reset() { - *x = MachineImages{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MachineImages) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MachineImages) ProtoMessage() {} - -func (x *MachineImages) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[20] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MachineImages.ProtoReflect.Descriptor instead. -func (*MachineImages) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{20} -} - -func (x *MachineImages) GetMetadata() *Metadata { - if x != nil { - return x.Metadata - } - return nil -} - -func (x *MachineImages) GetImages() []byte { - if x != nil { - return x.Images - } - return nil -} - -func (x *MachineImages) GetContainerdStore() bool { - if x != nil { - return x.ContainerdStore - } - return false -} - -type CreateVolumeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // JSON serialised volume.CreateOptions. - Options []byte `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"` -} - -func (x *CreateVolumeRequest) Reset() { - *x = CreateVolumeRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[21] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CreateVolumeRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CreateVolumeRequest) ProtoMessage() {} - -func (x *CreateVolumeRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[21] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CreateVolumeRequest.ProtoReflect.Descriptor instead. -func (*CreateVolumeRequest) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{21} -} - -func (x *CreateVolumeRequest) GetOptions() []byte { - if x != nil { - return x.Options - } - return nil -} - -type CreateVolumeResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // JSON serialised volume.Volume. - Volume []byte `protobuf:"bytes,1,opt,name=volume,proto3" json:"volume,omitempty"` -} - -func (x *CreateVolumeResponse) Reset() { - *x = CreateVolumeResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[22] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CreateVolumeResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CreateVolumeResponse) ProtoMessage() {} - -func (x *CreateVolumeResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[22] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CreateVolumeResponse.ProtoReflect.Descriptor instead. -func (*CreateVolumeResponse) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{22} -} - -func (x *CreateVolumeResponse) GetVolume() []byte { - if x != nil { - return x.Volume - } - return nil -} - -type ListVolumesRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // JSON serialised volume.ListOptions. - Options []byte `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"` -} - -func (x *ListVolumesRequest) Reset() { - *x = ListVolumesRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[23] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListVolumesRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListVolumesRequest) ProtoMessage() {} - -func (x *ListVolumesRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[23] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListVolumesRequest.ProtoReflect.Descriptor instead. -func (*ListVolumesRequest) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{23} -} - -func (x *ListVolumesRequest) GetOptions() []byte { - if x != nil { - return x.Options - } - return nil -} - -type ListVolumesResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Must contain only one repeated messages field to allow broadcasting ListVolumes requests to multiple machines. - Messages []*MachineVolumes `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` -} - -func (x *ListVolumesResponse) Reset() { - *x = ListVolumesResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[24] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListVolumesResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListVolumesResponse) ProtoMessage() {} - -func (x *ListVolumesResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[24] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListVolumesResponse.ProtoReflect.Descriptor instead. -func (*ListVolumesResponse) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{24} -} - -func (x *ListVolumesResponse) GetMessages() []*MachineVolumes { - if x != nil { - return x.Messages - } - return nil -} - -type MachineVolumes struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` - // JSON serialised volume.ListResponse. - Response []byte `protobuf:"bytes,2,opt,name=response,proto3" json:"response,omitempty"` -} - -func (x *MachineVolumes) Reset() { - *x = MachineVolumes{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[25] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MachineVolumes) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MachineVolumes) ProtoMessage() {} - -func (x *MachineVolumes) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[25] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MachineVolumes.ProtoReflect.Descriptor instead. -func (*MachineVolumes) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{25} -} - -func (x *MachineVolumes) GetMetadata() *Metadata { - if x != nil { - return x.Metadata - } - return nil -} - -func (x *MachineVolumes) GetResponse() []byte { - if x != nil { - return x.Response - } - return nil -} - -type RemoveVolumeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Force bool `protobuf:"varint,2,opt,name=force,proto3" json:"force,omitempty"` -} - -func (x *RemoveVolumeRequest) Reset() { - *x = RemoveVolumeRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[26] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RemoveVolumeRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RemoveVolumeRequest) ProtoMessage() {} - -func (x *RemoveVolumeRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[26] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RemoveVolumeRequest.ProtoReflect.Descriptor instead. -func (*RemoveVolumeRequest) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{26} -} - -func (x *RemoveVolumeRequest) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *RemoveVolumeRequest) GetForce() bool { - if x != nil { - return x.Force - } - return false -} - -type CreateServiceContainerRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ServiceId string `protobuf:"bytes,1,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` - // JSON serialised api.ServiceSpec. - ServiceSpec []byte `protobuf:"bytes,2,opt,name=service_spec,json=serviceSpec,proto3" json:"service_spec,omitempty"` - ContainerName string `protobuf:"bytes,3,opt,name=container_name,json=containerName,proto3" json:"container_name,omitempty"` -} - -func (x *CreateServiceContainerRequest) Reset() { - *x = CreateServiceContainerRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[27] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CreateServiceContainerRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CreateServiceContainerRequest) ProtoMessage() {} - -func (x *CreateServiceContainerRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[27] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CreateServiceContainerRequest.ProtoReflect.Descriptor instead. -func (*CreateServiceContainerRequest) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{27} -} - -func (x *CreateServiceContainerRequest) GetServiceId() string { - if x != nil { - return x.ServiceId - } - return "" -} - -func (x *CreateServiceContainerRequest) GetServiceSpec() []byte { - if x != nil { - return x.ServiceSpec - } - return nil -} - -func (x *CreateServiceContainerRequest) GetContainerName() string { - if x != nil { - return x.ContainerName - } - return "" -} - -type ServiceContainer struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // JSON serialised container.InspectResponse. - Container []byte `protobuf:"bytes,1,opt,name=container,proto3" json:"container,omitempty"` - // JSON serialised api.ServiceSpec. - ServiceSpec []byte `protobuf:"bytes,2,opt,name=service_spec,json=serviceSpec,proto3" json:"service_spec,omitempty"` -} - -func (x *ServiceContainer) Reset() { - *x = ServiceContainer{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[28] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ServiceContainer) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ServiceContainer) ProtoMessage() {} - -func (x *ServiceContainer) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[28] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ServiceContainer.ProtoReflect.Descriptor instead. -func (*ServiceContainer) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{28} -} - -func (x *ServiceContainer) GetContainer() []byte { - if x != nil { - return x.Container - } - return nil -} - -func (x *ServiceContainer) GetServiceSpec() []byte { - if x != nil { - return x.ServiceSpec - } - return nil -} - -type ListServiceContainersRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ServiceId string `protobuf:"bytes,1,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` - // JSON serialised container.ListOptions. - Options []byte `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` -} - -func (x *ListServiceContainersRequest) Reset() { - *x = ListServiceContainersRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[29] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListServiceContainersRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListServiceContainersRequest) ProtoMessage() {} - -func (x *ListServiceContainersRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[29] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListServiceContainersRequest.ProtoReflect.Descriptor instead. -func (*ListServiceContainersRequest) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{29} -} - -func (x *ListServiceContainersRequest) GetServiceId() string { - if x != nil { - return x.ServiceId - } - return "" -} - -func (x *ListServiceContainersRequest) GetOptions() []byte { - if x != nil { - return x.Options - } - return nil -} - -type ListServiceContainersResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Must contain only one repeated messages field to allow broadcasting ListServiceContainers requests - // to multiple machines. - Messages []*MachineServiceContainers `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` -} - -func (x *ListServiceContainersResponse) Reset() { - *x = ListServiceContainersResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[30] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ListServiceContainersResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ListServiceContainersResponse) ProtoMessage() {} - -func (x *ListServiceContainersResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[30] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ListServiceContainersResponse.ProtoReflect.Descriptor instead. -func (*ListServiceContainersResponse) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{30} -} - -func (x *ListServiceContainersResponse) GetMessages() []*MachineServiceContainers { - if x != nil { - return x.Messages - } - return nil -} - -type MachineServiceContainers struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` - Containers []*ServiceContainer `protobuf:"bytes,2,rep,name=containers,proto3" json:"containers,omitempty"` -} - -func (x *MachineServiceContainers) Reset() { - *x = MachineServiceContainers{} - if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[31] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MachineServiceContainers) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MachineServiceContainers) ProtoMessage() {} - -func (x *MachineServiceContainers) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[31] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MachineServiceContainers.ProtoReflect.Descriptor instead. -func (*MachineServiceContainers) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{31} -} - -func (x *MachineServiceContainers) GetMetadata() *Metadata { - if x != nil { - return x.Metadata - } - return nil -} - -func (x *MachineServiceContainers) GetContainers() []*ServiceContainer { - if x != nil { - return x.Containers - } - return nil -} - type ExecContainerRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1743,7 +636,7 @@ type ExecContainerRequest struct { func (x *ExecContainerRequest) Reset() { *x = ExecContainerRequest{} if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[32] + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1756,7 +649,7 @@ func (x *ExecContainerRequest) String() string { func (*ExecContainerRequest) ProtoMessage() {} func (x *ExecContainerRequest) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[32] + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1769,7 +662,7 @@ func (x *ExecContainerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecContainerRequest.ProtoReflect.Descriptor instead. func (*ExecContainerRequest) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{32} + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{10} } func (m *ExecContainerRequest) GetPayload() isExecContainerRequest_Payload { @@ -1839,7 +732,7 @@ type ExecConfig struct { func (x *ExecConfig) Reset() { *x = ExecConfig{} if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[33] + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1852,7 +745,7 @@ func (x *ExecConfig) String() string { func (*ExecConfig) ProtoMessage() {} func (x *ExecConfig) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[33] + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1865,7 +758,7 @@ func (x *ExecConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecConfig.ProtoReflect.Descriptor instead. func (*ExecConfig) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{33} + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{11} } func (x *ExecConfig) GetContainerId() string { @@ -1894,7 +787,7 @@ type ResizeEvent struct { func (x *ResizeEvent) Reset() { *x = ResizeEvent{} if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[34] + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1907,7 +800,7 @@ func (x *ResizeEvent) String() string { func (*ResizeEvent) ProtoMessage() {} func (x *ResizeEvent) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[34] + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1920,7 +813,7 @@ func (x *ResizeEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ResizeEvent.ProtoReflect.Descriptor instead. func (*ResizeEvent) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{34} + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{12} } func (x *ResizeEvent) GetHeight() uint32 { @@ -1954,7 +847,7 @@ type ExecContainerResponse struct { func (x *ExecContainerResponse) Reset() { *x = ExecContainerResponse{} if protoimpl.UnsafeEnabled { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[35] + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1967,7 +860,7 @@ func (x *ExecContainerResponse) String() string { func (*ExecContainerResponse) ProtoMessage() {} func (x *ExecContainerResponse) ProtoReflect() protoreflect.Message { - mi := &file_internal_machine_api_pb_docker_proto_msgTypes[35] + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1980,7 +873,7 @@ func (x *ExecContainerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecContainerResponse.ProtoReflect.Descriptor instead. func (*ExecContainerResponse) Descriptor() ([]byte, []int) { - return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{35} + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{13} } func (m *ExecContainerResponse) GetPayload() isExecContainerResponse_Payload { @@ -2050,6 +943,1310 @@ func (*ExecContainerResponse_Stderr) isExecContainerResponse_Payload() {} func (*ExecContainerResponse_ExitCode) isExecContainerResponse_Payload() {} +type ContainerLogsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ContainerId string `protobuf:"bytes,1,opt,name=container_id,json=containerId,proto3" json:"container_id,omitempty"` + // Options for logs retrieval. + Follow bool `protobuf:"varint,2,opt,name=follow,proto3" json:"follow,omitempty"` + Tail int32 `protobuf:"varint,3,opt,name=tail,proto3" json:"tail,omitempty"` // -1 means all + Since string `protobuf:"bytes,4,opt,name=since,proto3" json:"since,omitempty"` // https://www.rfc-editor.org/rfc/rfc3339.html timestamp or Go duration string + Until string `protobuf:"bytes,5,opt,name=until,proto3" json:"until,omitempty"` // https://www.rfc-editor.org/rfc/rfc3339.html timestamp or Go duration string +} + +func (x *ContainerLogsRequest) Reset() { + *x = ContainerLogsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContainerLogsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContainerLogsRequest) ProtoMessage() {} + +func (x *ContainerLogsRequest) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContainerLogsRequest.ProtoReflect.Descriptor instead. +func (*ContainerLogsRequest) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{14} +} + +func (x *ContainerLogsRequest) GetContainerId() string { + if x != nil { + return x.ContainerId + } + return "" +} + +func (x *ContainerLogsRequest) GetFollow() bool { + if x != nil { + return x.Follow + } + return false +} + +func (x *ContainerLogsRequest) GetTail() int32 { + if x != nil { + return x.Tail + } + return 0 +} + +func (x *ContainerLogsRequest) GetSince() string { + if x != nil { + return x.Since + } + return "" +} + +func (x *ContainerLogsRequest) GetUntil() string { + if x != nil { + return x.Until + } + return "" +} + +type ContainerLogEntry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Stream ContainerLogEntry_StreamType `protobuf:"varint,1,opt,name=stream,proto3,enum=api.ContainerLogEntry_StreamType" json:"stream,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // Log line content. Empty for heartbeat entries. + Message []byte `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *ContainerLogEntry) Reset() { + *x = ContainerLogEntry{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContainerLogEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContainerLogEntry) ProtoMessage() {} + +func (x *ContainerLogEntry) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContainerLogEntry.ProtoReflect.Descriptor instead. +func (*ContainerLogEntry) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{15} +} + +func (x *ContainerLogEntry) GetStream() ContainerLogEntry_StreamType { + if x != nil { + return x.Stream + } + return ContainerLogEntry_UNKNOWN +} + +func (x *ContainerLogEntry) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + +func (x *ContainerLogEntry) GetMessage() []byte { + if x != nil { + return x.Message + } + return nil +} + +type PullImageRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Image string `protobuf:"bytes,1,opt,name=image,proto3" json:"image,omitempty"` + // JSON serialised image.PullOptions. + Options []byte `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` +} + +func (x *PullImageRequest) Reset() { + *x = PullImageRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PullImageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PullImageRequest) ProtoMessage() {} + +func (x *PullImageRequest) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PullImageRequest.ProtoReflect.Descriptor instead. +func (*PullImageRequest) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{16} +} + +func (x *PullImageRequest) GetImage() string { + if x != nil { + return x.Image + } + return "" +} + +func (x *PullImageRequest) GetOptions() []byte { + if x != nil { + return x.Options + } + return nil +} + +type JSONMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // JSON serialised jsonmessage.JSONMessage. + Message []byte `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *JSONMessage) Reset() { + *x = JSONMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *JSONMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*JSONMessage) ProtoMessage() {} + +func (x *JSONMessage) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use JSONMessage.ProtoReflect.Descriptor instead. +func (*JSONMessage) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{17} +} + +func (x *JSONMessage) GetMessage() []byte { + if x != nil { + return x.Message + } + return nil +} + +type InspectImageRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *InspectImageRequest) Reset() { + *x = InspectImageRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InspectImageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InspectImageRequest) ProtoMessage() {} + +func (x *InspectImageRequest) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InspectImageRequest.ProtoReflect.Descriptor instead. +func (*InspectImageRequest) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{18} +} + +func (x *InspectImageRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type InspectImageResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Must contain only one repeated messages field to allow broadcasting InspectImage requests to multiple machines. + Messages []*Image `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` +} + +func (x *InspectImageResponse) Reset() { + *x = InspectImageResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InspectImageResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InspectImageResponse) ProtoMessage() {} + +func (x *InspectImageResponse) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InspectImageResponse.ProtoReflect.Descriptor instead. +func (*InspectImageResponse) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{19} +} + +func (x *InspectImageResponse) GetMessages() []*Image { + if x != nil { + return x.Messages + } + return nil +} + +type Image struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + // JSON serialised image.InspectResponse. + Image []byte `protobuf:"bytes,2,opt,name=image,proto3" json:"image,omitempty"` +} + +func (x *Image) Reset() { + *x = Image{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Image) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Image) ProtoMessage() {} + +func (x *Image) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Image.ProtoReflect.Descriptor instead. +func (*Image) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{20} +} + +func (x *Image) GetMetadata() *Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *Image) GetImage() []byte { + if x != nil { + return x.Image + } + return nil +} + +type InspectRemoteImageRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *InspectRemoteImageRequest) Reset() { + *x = InspectRemoteImageRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InspectRemoteImageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InspectRemoteImageRequest) ProtoMessage() {} + +func (x *InspectRemoteImageRequest) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InspectRemoteImageRequest.ProtoReflect.Descriptor instead. +func (*InspectRemoteImageRequest) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{21} +} + +func (x *InspectRemoteImageRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type InspectRemoteImageResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Must contain only one repeated messages field to allow broadcasting InspectRemoteImage requests to multiple machines. + Messages []*RemoteImage `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` +} + +func (x *InspectRemoteImageResponse) Reset() { + *x = InspectRemoteImageResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InspectRemoteImageResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InspectRemoteImageResponse) ProtoMessage() {} + +func (x *InspectRemoteImageResponse) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InspectRemoteImageResponse.ProtoReflect.Descriptor instead. +func (*InspectRemoteImageResponse) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{22} +} + +func (x *InspectRemoteImageResponse) GetMessages() []*RemoteImage { + if x != nil { + return x.Messages + } + return nil +} + +type RemoteImage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + // Image reference in the canonical form with the digest. + Reference string `protobuf:"bytes,2,opt,name=reference,proto3" json:"reference,omitempty"` + // Raw JSON manifest from the registry. + Manifest []byte `protobuf:"bytes,3,opt,name=manifest,proto3" json:"manifest,omitempty"` +} + +func (x *RemoteImage) Reset() { + *x = RemoteImage{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoteImage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoteImage) ProtoMessage() {} + +func (x *RemoteImage) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoteImage.ProtoReflect.Descriptor instead. +func (*RemoteImage) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{23} +} + +func (x *RemoteImage) GetMetadata() *Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *RemoteImage) GetReference() string { + if x != nil { + return x.Reference + } + return "" +} + +func (x *RemoteImage) GetManifest() []byte { + if x != nil { + return x.Manifest + } + return nil +} + +type ListImagesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // JSON serialised image.ListOptions. + Options []byte `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"` +} + +func (x *ListImagesRequest) Reset() { + *x = ListImagesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListImagesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListImagesRequest) ProtoMessage() {} + +func (x *ListImagesRequest) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListImagesRequest.ProtoReflect.Descriptor instead. +func (*ListImagesRequest) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{24} +} + +func (x *ListImagesRequest) GetOptions() []byte { + if x != nil { + return x.Options + } + return nil +} + +type ListImagesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Must contain only one repeated messages field to allow broadcasting ListImages requests to multiple machines. + Messages []*MachineImages `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` +} + +func (x *ListImagesResponse) Reset() { + *x = ListImagesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListImagesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListImagesResponse) ProtoMessage() {} + +func (x *ListImagesResponse) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListImagesResponse.ProtoReflect.Descriptor instead. +func (*ListImagesResponse) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{25} +} + +func (x *ListImagesResponse) GetMessages() []*MachineImages { + if x != nil { + return x.Messages + } + return nil +} + +type MachineImages struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + // JSON serialised []image.Summary. + Images []byte `protobuf:"bytes,2,opt,name=images,proto3" json:"images,omitempty"` + // True if Docker uses the containerd image store, false if it uses its internal image store. + ContainerdStore bool `protobuf:"varint,3,opt,name=containerd_store,json=containerdStore,proto3" json:"containerd_store,omitempty"` +} + +func (x *MachineImages) Reset() { + *x = MachineImages{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MachineImages) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MachineImages) ProtoMessage() {} + +func (x *MachineImages) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MachineImages.ProtoReflect.Descriptor instead. +func (*MachineImages) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{26} +} + +func (x *MachineImages) GetMetadata() *Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *MachineImages) GetImages() []byte { + if x != nil { + return x.Images + } + return nil +} + +func (x *MachineImages) GetContainerdStore() bool { + if x != nil { + return x.ContainerdStore + } + return false +} + +type CreateVolumeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // JSON serialised volume.CreateOptions. + Options []byte `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"` +} + +func (x *CreateVolumeRequest) Reset() { + *x = CreateVolumeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateVolumeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateVolumeRequest) ProtoMessage() {} + +func (x *CreateVolumeRequest) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateVolumeRequest.ProtoReflect.Descriptor instead. +func (*CreateVolumeRequest) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{27} +} + +func (x *CreateVolumeRequest) GetOptions() []byte { + if x != nil { + return x.Options + } + return nil +} + +type CreateVolumeResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // JSON serialised volume.Volume. + Volume []byte `protobuf:"bytes,1,opt,name=volume,proto3" json:"volume,omitempty"` +} + +func (x *CreateVolumeResponse) Reset() { + *x = CreateVolumeResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateVolumeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateVolumeResponse) ProtoMessage() {} + +func (x *CreateVolumeResponse) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateVolumeResponse.ProtoReflect.Descriptor instead. +func (*CreateVolumeResponse) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{28} +} + +func (x *CreateVolumeResponse) GetVolume() []byte { + if x != nil { + return x.Volume + } + return nil +} + +type ListVolumesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // JSON serialised volume.ListOptions. + Options []byte `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"` +} + +func (x *ListVolumesRequest) Reset() { + *x = ListVolumesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListVolumesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListVolumesRequest) ProtoMessage() {} + +func (x *ListVolumesRequest) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListVolumesRequest.ProtoReflect.Descriptor instead. +func (*ListVolumesRequest) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{29} +} + +func (x *ListVolumesRequest) GetOptions() []byte { + if x != nil { + return x.Options + } + return nil +} + +type ListVolumesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Must contain only one repeated messages field to allow broadcasting ListVolumes requests to multiple machines. + Messages []*MachineVolumes `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` +} + +func (x *ListVolumesResponse) Reset() { + *x = ListVolumesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListVolumesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListVolumesResponse) ProtoMessage() {} + +func (x *ListVolumesResponse) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListVolumesResponse.ProtoReflect.Descriptor instead. +func (*ListVolumesResponse) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{30} +} + +func (x *ListVolumesResponse) GetMessages() []*MachineVolumes { + if x != nil { + return x.Messages + } + return nil +} + +type MachineVolumes struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + // JSON serialised volume.ListResponse. + Response []byte `protobuf:"bytes,2,opt,name=response,proto3" json:"response,omitempty"` +} + +func (x *MachineVolumes) Reset() { + *x = MachineVolumes{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MachineVolumes) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MachineVolumes) ProtoMessage() {} + +func (x *MachineVolumes) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MachineVolumes.ProtoReflect.Descriptor instead. +func (*MachineVolumes) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{31} +} + +func (x *MachineVolumes) GetMetadata() *Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *MachineVolumes) GetResponse() []byte { + if x != nil { + return x.Response + } + return nil +} + +type RemoveVolumeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Force bool `protobuf:"varint,2,opt,name=force,proto3" json:"force,omitempty"` +} + +func (x *RemoveVolumeRequest) Reset() { + *x = RemoveVolumeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoveVolumeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveVolumeRequest) ProtoMessage() {} + +func (x *RemoveVolumeRequest) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveVolumeRequest.ProtoReflect.Descriptor instead. +func (*RemoveVolumeRequest) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{32} +} + +func (x *RemoveVolumeRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *RemoveVolumeRequest) GetForce() bool { + if x != nil { + return x.Force + } + return false +} + +type CreateServiceContainerRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ServiceId string `protobuf:"bytes,1,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + // JSON serialised api.ServiceSpec. + ServiceSpec []byte `protobuf:"bytes,2,opt,name=service_spec,json=serviceSpec,proto3" json:"service_spec,omitempty"` + ContainerName string `protobuf:"bytes,3,opt,name=container_name,json=containerName,proto3" json:"container_name,omitempty"` +} + +func (x *CreateServiceContainerRequest) Reset() { + *x = CreateServiceContainerRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateServiceContainerRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateServiceContainerRequest) ProtoMessage() {} + +func (x *CreateServiceContainerRequest) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateServiceContainerRequest.ProtoReflect.Descriptor instead. +func (*CreateServiceContainerRequest) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{33} +} + +func (x *CreateServiceContainerRequest) GetServiceId() string { + if x != nil { + return x.ServiceId + } + return "" +} + +func (x *CreateServiceContainerRequest) GetServiceSpec() []byte { + if x != nil { + return x.ServiceSpec + } + return nil +} + +func (x *CreateServiceContainerRequest) GetContainerName() string { + if x != nil { + return x.ContainerName + } + return "" +} + +type ServiceContainer struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // JSON serialised container.InspectResponse. + Container []byte `protobuf:"bytes,1,opt,name=container,proto3" json:"container,omitempty"` + // JSON serialised api.ServiceSpec. + ServiceSpec []byte `protobuf:"bytes,2,opt,name=service_spec,json=serviceSpec,proto3" json:"service_spec,omitempty"` +} + +func (x *ServiceContainer) Reset() { + *x = ServiceContainer{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServiceContainer) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServiceContainer) ProtoMessage() {} + +func (x *ServiceContainer) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServiceContainer.ProtoReflect.Descriptor instead. +func (*ServiceContainer) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{34} +} + +func (x *ServiceContainer) GetContainer() []byte { + if x != nil { + return x.Container + } + return nil +} + +func (x *ServiceContainer) GetServiceSpec() []byte { + if x != nil { + return x.ServiceSpec + } + return nil +} + +type ListServiceContainersRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ServiceId string `protobuf:"bytes,1,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + // JSON serialised container.ListOptions. + Options []byte `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` +} + +func (x *ListServiceContainersRequest) Reset() { + *x = ListServiceContainersRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListServiceContainersRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListServiceContainersRequest) ProtoMessage() {} + +func (x *ListServiceContainersRequest) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListServiceContainersRequest.ProtoReflect.Descriptor instead. +func (*ListServiceContainersRequest) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{35} +} + +func (x *ListServiceContainersRequest) GetServiceId() string { + if x != nil { + return x.ServiceId + } + return "" +} + +func (x *ListServiceContainersRequest) GetOptions() []byte { + if x != nil { + return x.Options + } + return nil +} + +type ListServiceContainersResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Must contain only one repeated messages field to allow broadcasting ListServiceContainers requests + // to multiple machines. + Messages []*MachineServiceContainers `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"` +} + +func (x *ListServiceContainersResponse) Reset() { + *x = ListServiceContainersResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListServiceContainersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListServiceContainersResponse) ProtoMessage() {} + +func (x *ListServiceContainersResponse) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListServiceContainersResponse.ProtoReflect.Descriptor instead. +func (*ListServiceContainersResponse) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{36} +} + +func (x *ListServiceContainersResponse) GetMessages() []*MachineServiceContainers { + if x != nil { + return x.Messages + } + return nil +} + +type MachineServiceContainers struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + Containers []*ServiceContainer `protobuf:"bytes,2,rep,name=containers,proto3" json:"containers,omitempty"` +} + +func (x *MachineServiceContainers) Reset() { + *x = MachineServiceContainers{} + if protoimpl.UnsafeEnabled { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MachineServiceContainers) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MachineServiceContainers) ProtoMessage() {} + +func (x *MachineServiceContainers) ProtoReflect() protoreflect.Message { + mi := &file_internal_machine_api_pb_docker_proto_msgTypes[37] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MachineServiceContainers.ProtoReflect.Descriptor instead. +func (*MachineServiceContainers) Descriptor() ([]byte, []int) { + return file_internal_machine_api_pb_docker_proto_rawDescGZIP(), []int{37} +} + +func (x *MachineServiceContainers) GetMetadata() *Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *MachineServiceContainers) GetContainers() []*ServiceContainer { + if x != nil { + return x.Containers + } + return nil +} + var File_internal_machine_api_pb_docker_proto protoreflect.FileDescriptor var file_internal_machine_api_pb_docker_proto_rawDesc = []byte{ @@ -2057,160 +2254,58 @@ var file_internal_machine_api_pb_docker_proto_rawDesc = []byte{ 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x2f, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x61, 0x70, 0x69, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, - 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x24, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, - 0x62, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa8, - 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, - 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x70, 0x6c, 0x61, - 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x35, 0x0a, 0x17, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x29, 0x0a, 0x17, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x36, 0x0a, 0x18, 0x49, - 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x15, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, + 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x24, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x70, 0x62, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0xa8, 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x35, 0x0a, 0x17, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x29, 0x0a, 0x17, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x40, 0x0a, 0x14, 0x53, 0x74, 0x6f, 0x70, 0x43, 0x6f, - 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, - 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x31, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, - 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x4c, 0x0a, 0x16, 0x4c, - 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, - 0x63, 0x68, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, - 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x5e, 0x0a, 0x11, 0x4d, 0x61, 0x63, - 0x68, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x29, - 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, - 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x22, 0x42, 0x0a, 0x16, 0x52, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x42, 0x0a, - 0x10, 0x50, 0x75, 0x6c, 0x6c, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x22, 0x27, 0x0a, 0x0b, 0x4a, 0x53, 0x4f, 0x4e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x25, 0x0a, 0x13, 0x49, 0x6e, - 0x73, 0x70, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x22, 0x3e, 0x0a, 0x14, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x08, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x73, 0x22, 0x48, 0x0a, 0x05, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x08, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x22, 0x2b, 0x0a, 0x19, 0x49, - 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x4a, 0x0a, 0x1a, 0x49, 0x6e, 0x73, 0x70, - 0x65, 0x63, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, - 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x73, 0x22, 0x72, 0x0a, 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x6d, - 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1c, - 0x0a, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, - 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, - 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x22, 0x2d, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, - 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, - 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x44, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x49, - 0x6d, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, - 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x6d, 0x61, - 0x67, 0x65, 0x73, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x7d, 0x0a, - 0x0d, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x12, 0x29, - 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, - 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x6d, 0x61, - 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x69, 0x6d, 0x61, 0x67, 0x65, - 0x73, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x5f, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x63, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x2f, 0x0a, 0x13, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x2e, 0x0a, - 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x22, 0x2e, 0x0a, - 0x12, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x46, 0x0a, - 0x13, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, 0x63, - 0x68, 0x69, 0x6e, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x52, 0x08, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x57, 0x0a, 0x0e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, - 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3b, - 0x0a, 0x13, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22, 0x88, 0x01, 0x0a, 0x1d, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, - 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12, - 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x53, 0x0a, 0x10, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, - 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x22, 0x57, 0x0a, 0x1c, 0x4c, - 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x5a, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, - 0x63, 0x68, 0x69, 0x6e, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, - 0x22, 0x7c, 0x0a, 0x18, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x29, 0x0a, 0x08, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x35, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x22, 0x90, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x36, 0x0a, 0x18, + 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x15, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, + 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x40, 0x0a, 0x14, 0x53, 0x74, 0x6f, 0x70, 0x43, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x31, 0x0a, 0x15, 0x4c, 0x69, 0x73, + 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x4c, 0x0a, 0x16, + 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, + 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, + 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x5e, 0x0a, 0x11, 0x4d, 0x61, + 0x63, 0x68, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, + 0x29, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x22, 0x42, 0x0a, 0x16, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x90, 0x01, 0x0a, 0x14, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, @@ -2237,96 +2332,228 @@ var file_internal_machine_api_pb_docker_proto_rawDesc = []byte{ 0x72, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x12, 0x1d, 0x0a, 0x09, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x08, 0x65, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, - 0x65, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x32, 0xc7, 0x0a, 0x0a, - 0x06, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x12, 0x4c, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x10, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, - 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, - 0x73, 0x70, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, - 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x65, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x91, 0x01, 0x0a, + 0x14, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x6c, + 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, + 0x74, 0x61, 0x69, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x75, 0x6e, + 0x74, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x75, 0x6e, 0x74, 0x69, 0x6c, + 0x22, 0xe4, 0x01, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4c, 0x6f, + 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x39, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, + 0x6d, 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, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x40, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, + 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x44, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, + 0x53, 0x54, 0x44, 0x45, 0x52, 0x52, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x48, 0x45, 0x41, 0x52, + 0x54, 0x42, 0x45, 0x41, 0x54, 0x10, 0x03, 0x22, 0x42, 0x0a, 0x10, 0x50, 0x75, 0x6c, 0x6c, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x69, + 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x27, 0x0a, 0x0b, 0x4a, + 0x53, 0x4f, 0x4e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x25, 0x0a, 0x13, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3e, 0x0a, 0x14, 0x49, + 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6d, 0x61, 0x67, + 0x65, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x48, 0x0a, 0x05, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, + 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x22, 0x2b, 0x0a, 0x19, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, + 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x22, 0x4a, 0x0a, 0x1a, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6d, + 0x6f, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x72, + 0x0a, 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, + 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, + 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, + 0x73, 0x74, 0x22, 0x2d, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0x44, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x52, 0x08, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x7d, 0x0a, 0x0d, 0x4d, 0x61, 0x63, 0x68, 0x69, + 0x6e, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x06, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x64, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x2f, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, + 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x2e, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x06, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x22, 0x2e, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x56, + 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, + 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x46, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x56, + 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, + 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x13, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x56, 0x6f, + 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, + 0x57, 0x0a, 0x0e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, + 0x73, 0x12, 0x29, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, + 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, + 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3b, 0x0a, 0x13, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, + 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22, 0x88, 0x01, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, + 0x22, 0x53, 0x0a, 0x10, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x73, 0x70, + 0x65, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x53, 0x70, 0x65, 0x63, 0x22, 0x57, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x5a, + 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x39, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, + 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x7c, 0x0a, 0x18, 0x4d, 0x61, + 0x63, 0x68, 0x69, 0x6e, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x29, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x12, 0x35, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x0a, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x32, 0x8d, 0x0b, 0x0a, 0x06, 0x44, 0x6f, 0x63, + 0x6b, 0x65, 0x72, 0x12, 0x4c, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x4f, 0x0a, 0x10, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x73, 0x70, + 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, + 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x42, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x70, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x53, 0x74, 0x6f, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x42, 0x0a, 0x0d, - 0x53, 0x74, 0x6f, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x19, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x12, 0x49, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x49, 0x0a, 0x0e, + 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0f, 0x52, - 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1b, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x12, 0x36, 0x0a, 0x09, 0x50, 0x75, 0x6c, 0x6c, 0x49, 0x6d, 0x61, 0x67, 0x65, - 0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x75, 0x6c, 0x6c, 0x49, 0x6d, 0x61, 0x67, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4a, 0x53, - 0x4f, 0x4e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x30, 0x01, 0x12, 0x43, 0x0a, 0x0c, 0x49, - 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x73, 0x70, - 0x65, 0x63, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x55, 0x0a, 0x12, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x74, - 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x73, - 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x73, - 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x49, - 0x6d, 0x61, 0x67, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x6f, 0x6c, - 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x4c, - 0x69, 0x73, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x17, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x6f, - 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, - 0x0c, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x18, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0f, 0x52, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, - 0x5a, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x17, 0x49, - 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, - 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x73, - 0x70, 0x65, 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x5e, 0x0a, 0x15, 0x4c, - 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x73, 0x12, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x16, 0x52, - 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x4a, 0x0a, 0x0d, 0x45, 0x78, - 0x65, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x19, 0x2e, 0x61, 0x70, + 0x4a, 0x0a, 0x0d, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x78, 0x65, - 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x73, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x6b, 0x69, 0x2f, - 0x75, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x44, 0x0a, 0x0d, 0x43, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x19, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x30, + 0x01, 0x12, 0x36, 0x0a, 0x09, 0x50, 0x75, 0x6c, 0x6c, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x15, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x75, 0x6c, 0x6c, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x30, 0x01, 0x12, 0x43, 0x0a, 0x0c, 0x49, 0x6e, 0x73, + 0x70, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, + 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55, + 0x0a, 0x12, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x73, 0x70, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x73, 0x70, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6d, 0x61, + 0x67, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x6f, + 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x4c, 0x69, 0x73, + 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x12, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x6f, 0x6c, 0x75, + 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0c, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x5a, 0x0a, + 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x17, 0x49, 0x6e, 0x73, + 0x70, 0x65, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x49, 0x6e, 0x73, 0x70, 0x65, + 0x63, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x5e, 0x0a, 0x15, 0x4c, 0x69, 0x73, + 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x73, 0x12, 0x21, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x16, 0x52, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x73, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x6b, + 0x69, 0x2f, 0x75, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, + 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2341,104 +2568,113 @@ func file_internal_machine_api_pb_docker_proto_rawDescGZIP() []byte { return file_internal_machine_api_pb_docker_proto_rawDescData } -var file_internal_machine_api_pb_docker_proto_msgTypes = make([]protoimpl.MessageInfo, 36) +var file_internal_machine_api_pb_docker_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_internal_machine_api_pb_docker_proto_msgTypes = make([]protoimpl.MessageInfo, 38) var file_internal_machine_api_pb_docker_proto_goTypes = []any{ - (*CreateContainerRequest)(nil), // 0: api.CreateContainerRequest - (*CreateContainerResponse)(nil), // 1: api.CreateContainerResponse - (*InspectContainerRequest)(nil), // 2: api.InspectContainerRequest - (*InspectContainerResponse)(nil), // 3: api.InspectContainerResponse - (*StartContainerRequest)(nil), // 4: api.StartContainerRequest - (*StopContainerRequest)(nil), // 5: api.StopContainerRequest - (*ListContainersRequest)(nil), // 6: api.ListContainersRequest - (*ListContainersResponse)(nil), // 7: api.ListContainersResponse - (*MachineContainers)(nil), // 8: api.MachineContainers - (*RemoveContainerRequest)(nil), // 9: api.RemoveContainerRequest - (*PullImageRequest)(nil), // 10: api.PullImageRequest - (*JSONMessage)(nil), // 11: api.JSONMessage - (*InspectImageRequest)(nil), // 12: api.InspectImageRequest - (*InspectImageResponse)(nil), // 13: api.InspectImageResponse - (*Image)(nil), // 14: api.Image - (*InspectRemoteImageRequest)(nil), // 15: api.InspectRemoteImageRequest - (*InspectRemoteImageResponse)(nil), // 16: api.InspectRemoteImageResponse - (*RemoteImage)(nil), // 17: api.RemoteImage - (*ListImagesRequest)(nil), // 18: api.ListImagesRequest - (*ListImagesResponse)(nil), // 19: api.ListImagesResponse - (*MachineImages)(nil), // 20: api.MachineImages - (*CreateVolumeRequest)(nil), // 21: api.CreateVolumeRequest - (*CreateVolumeResponse)(nil), // 22: api.CreateVolumeResponse - (*ListVolumesRequest)(nil), // 23: api.ListVolumesRequest - (*ListVolumesResponse)(nil), // 24: api.ListVolumesResponse - (*MachineVolumes)(nil), // 25: api.MachineVolumes - (*RemoveVolumeRequest)(nil), // 26: api.RemoveVolumeRequest - (*CreateServiceContainerRequest)(nil), // 27: api.CreateServiceContainerRequest - (*ServiceContainer)(nil), // 28: api.ServiceContainer - (*ListServiceContainersRequest)(nil), // 29: api.ListServiceContainersRequest - (*ListServiceContainersResponse)(nil), // 30: api.ListServiceContainersResponse - (*MachineServiceContainers)(nil), // 31: api.MachineServiceContainers - (*ExecContainerRequest)(nil), // 32: api.ExecContainerRequest - (*ExecConfig)(nil), // 33: api.ExecConfig - (*ResizeEvent)(nil), // 34: api.ResizeEvent - (*ExecContainerResponse)(nil), // 35: api.ExecContainerResponse - (*Metadata)(nil), // 36: api.Metadata - (*emptypb.Empty)(nil), // 37: google.protobuf.Empty + (ContainerLogEntry_StreamType)(0), // 0: api.ContainerLogEntry.StreamType + (*CreateContainerRequest)(nil), // 1: api.CreateContainerRequest + (*CreateContainerResponse)(nil), // 2: api.CreateContainerResponse + (*InspectContainerRequest)(nil), // 3: api.InspectContainerRequest + (*InspectContainerResponse)(nil), // 4: api.InspectContainerResponse + (*StartContainerRequest)(nil), // 5: api.StartContainerRequest + (*StopContainerRequest)(nil), // 6: api.StopContainerRequest + (*ListContainersRequest)(nil), // 7: api.ListContainersRequest + (*ListContainersResponse)(nil), // 8: api.ListContainersResponse + (*MachineContainers)(nil), // 9: api.MachineContainers + (*RemoveContainerRequest)(nil), // 10: api.RemoveContainerRequest + (*ExecContainerRequest)(nil), // 11: api.ExecContainerRequest + (*ExecConfig)(nil), // 12: api.ExecConfig + (*ResizeEvent)(nil), // 13: api.ResizeEvent + (*ExecContainerResponse)(nil), // 14: api.ExecContainerResponse + (*ContainerLogsRequest)(nil), // 15: api.ContainerLogsRequest + (*ContainerLogEntry)(nil), // 16: api.ContainerLogEntry + (*PullImageRequest)(nil), // 17: api.PullImageRequest + (*JSONMessage)(nil), // 18: api.JSONMessage + (*InspectImageRequest)(nil), // 19: api.InspectImageRequest + (*InspectImageResponse)(nil), // 20: api.InspectImageResponse + (*Image)(nil), // 21: api.Image + (*InspectRemoteImageRequest)(nil), // 22: api.InspectRemoteImageRequest + (*InspectRemoteImageResponse)(nil), // 23: api.InspectRemoteImageResponse + (*RemoteImage)(nil), // 24: api.RemoteImage + (*ListImagesRequest)(nil), // 25: api.ListImagesRequest + (*ListImagesResponse)(nil), // 26: api.ListImagesResponse + (*MachineImages)(nil), // 27: api.MachineImages + (*CreateVolumeRequest)(nil), // 28: api.CreateVolumeRequest + (*CreateVolumeResponse)(nil), // 29: api.CreateVolumeResponse + (*ListVolumesRequest)(nil), // 30: api.ListVolumesRequest + (*ListVolumesResponse)(nil), // 31: api.ListVolumesResponse + (*MachineVolumes)(nil), // 32: api.MachineVolumes + (*RemoveVolumeRequest)(nil), // 33: api.RemoveVolumeRequest + (*CreateServiceContainerRequest)(nil), // 34: api.CreateServiceContainerRequest + (*ServiceContainer)(nil), // 35: api.ServiceContainer + (*ListServiceContainersRequest)(nil), // 36: api.ListServiceContainersRequest + (*ListServiceContainersResponse)(nil), // 37: api.ListServiceContainersResponse + (*MachineServiceContainers)(nil), // 38: api.MachineServiceContainers + (*Metadata)(nil), // 39: api.Metadata + (*timestamppb.Timestamp)(nil), // 40: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 41: google.protobuf.Empty } var file_internal_machine_api_pb_docker_proto_depIdxs = []int32{ - 8, // 0: api.ListContainersResponse.messages:type_name -> api.MachineContainers - 36, // 1: api.MachineContainers.metadata:type_name -> api.Metadata - 14, // 2: api.InspectImageResponse.messages:type_name -> api.Image - 36, // 3: api.Image.metadata:type_name -> api.Metadata - 17, // 4: api.InspectRemoteImageResponse.messages:type_name -> api.RemoteImage - 36, // 5: api.RemoteImage.metadata:type_name -> api.Metadata - 20, // 6: api.ListImagesResponse.messages:type_name -> api.MachineImages - 36, // 7: api.MachineImages.metadata:type_name -> api.Metadata - 25, // 8: api.ListVolumesResponse.messages:type_name -> api.MachineVolumes - 36, // 9: api.MachineVolumes.metadata:type_name -> api.Metadata - 31, // 10: api.ListServiceContainersResponse.messages:type_name -> api.MachineServiceContainers - 36, // 11: api.MachineServiceContainers.metadata:type_name -> api.Metadata - 28, // 12: api.MachineServiceContainers.containers:type_name -> api.ServiceContainer - 33, // 13: api.ExecContainerRequest.config:type_name -> api.ExecConfig - 34, // 14: api.ExecContainerRequest.resize:type_name -> api.ResizeEvent - 0, // 15: api.Docker.CreateContainer:input_type -> api.CreateContainerRequest - 2, // 16: api.Docker.InspectContainer:input_type -> api.InspectContainerRequest - 4, // 17: api.Docker.StartContainer:input_type -> api.StartContainerRequest - 5, // 18: api.Docker.StopContainer:input_type -> api.StopContainerRequest - 6, // 19: api.Docker.ListContainers:input_type -> api.ListContainersRequest - 9, // 20: api.Docker.RemoveContainer:input_type -> api.RemoveContainerRequest - 10, // 21: api.Docker.PullImage:input_type -> api.PullImageRequest - 12, // 22: api.Docker.InspectImage:input_type -> api.InspectImageRequest - 15, // 23: api.Docker.InspectRemoteImage:input_type -> api.InspectRemoteImageRequest - 18, // 24: api.Docker.ListImages:input_type -> api.ListImagesRequest - 21, // 25: api.Docker.CreateVolume:input_type -> api.CreateVolumeRequest - 23, // 26: api.Docker.ListVolumes:input_type -> api.ListVolumesRequest - 26, // 27: api.Docker.RemoveVolume:input_type -> api.RemoveVolumeRequest - 27, // 28: api.Docker.CreateServiceContainer:input_type -> api.CreateServiceContainerRequest - 2, // 29: api.Docker.InspectServiceContainer:input_type -> api.InspectContainerRequest - 29, // 30: api.Docker.ListServiceContainers:input_type -> api.ListServiceContainersRequest - 9, // 31: api.Docker.RemoveServiceContainer:input_type -> api.RemoveContainerRequest - 32, // 32: api.Docker.ExecContainer:input_type -> api.ExecContainerRequest - 1, // 33: api.Docker.CreateContainer:output_type -> api.CreateContainerResponse - 3, // 34: api.Docker.InspectContainer:output_type -> api.InspectContainerResponse - 37, // 35: api.Docker.StartContainer:output_type -> google.protobuf.Empty - 37, // 36: api.Docker.StopContainer:output_type -> google.protobuf.Empty - 7, // 37: api.Docker.ListContainers:output_type -> api.ListContainersResponse - 37, // 38: api.Docker.RemoveContainer:output_type -> google.protobuf.Empty - 11, // 39: api.Docker.PullImage:output_type -> api.JSONMessage - 13, // 40: api.Docker.InspectImage:output_type -> api.InspectImageResponse - 16, // 41: api.Docker.InspectRemoteImage:output_type -> api.InspectRemoteImageResponse - 19, // 42: api.Docker.ListImages:output_type -> api.ListImagesResponse - 22, // 43: api.Docker.CreateVolume:output_type -> api.CreateVolumeResponse - 24, // 44: api.Docker.ListVolumes:output_type -> api.ListVolumesResponse - 37, // 45: api.Docker.RemoveVolume:output_type -> google.protobuf.Empty - 1, // 46: api.Docker.CreateServiceContainer:output_type -> api.CreateContainerResponse - 28, // 47: api.Docker.InspectServiceContainer:output_type -> api.ServiceContainer - 30, // 48: api.Docker.ListServiceContainers:output_type -> api.ListServiceContainersResponse - 37, // 49: api.Docker.RemoveServiceContainer:output_type -> google.protobuf.Empty - 35, // 50: api.Docker.ExecContainer:output_type -> api.ExecContainerResponse - 33, // [33:51] is the sub-list for method output_type - 15, // [15:33] is the sub-list for method input_type - 15, // [15:15] is the sub-list for extension type_name - 15, // [15:15] is the sub-list for extension extendee - 0, // [0:15] is the sub-list for field type_name + 9, // 0: api.ListContainersResponse.messages:type_name -> api.MachineContainers + 39, // 1: api.MachineContainers.metadata:type_name -> api.Metadata + 12, // 2: api.ExecContainerRequest.config:type_name -> api.ExecConfig + 13, // 3: api.ExecContainerRequest.resize:type_name -> api.ResizeEvent + 0, // 4: api.ContainerLogEntry.stream:type_name -> api.ContainerLogEntry.StreamType + 40, // 5: api.ContainerLogEntry.timestamp:type_name -> google.protobuf.Timestamp + 21, // 6: api.InspectImageResponse.messages:type_name -> api.Image + 39, // 7: api.Image.metadata:type_name -> api.Metadata + 24, // 8: api.InspectRemoteImageResponse.messages:type_name -> api.RemoteImage + 39, // 9: api.RemoteImage.metadata:type_name -> api.Metadata + 27, // 10: api.ListImagesResponse.messages:type_name -> api.MachineImages + 39, // 11: api.MachineImages.metadata:type_name -> api.Metadata + 32, // 12: api.ListVolumesResponse.messages:type_name -> api.MachineVolumes + 39, // 13: api.MachineVolumes.metadata:type_name -> api.Metadata + 38, // 14: api.ListServiceContainersResponse.messages:type_name -> api.MachineServiceContainers + 39, // 15: api.MachineServiceContainers.metadata:type_name -> api.Metadata + 35, // 16: api.MachineServiceContainers.containers:type_name -> api.ServiceContainer + 1, // 17: api.Docker.CreateContainer:input_type -> api.CreateContainerRequest + 3, // 18: api.Docker.InspectContainer:input_type -> api.InspectContainerRequest + 5, // 19: api.Docker.StartContainer:input_type -> api.StartContainerRequest + 6, // 20: api.Docker.StopContainer:input_type -> api.StopContainerRequest + 7, // 21: api.Docker.ListContainers:input_type -> api.ListContainersRequest + 10, // 22: api.Docker.RemoveContainer:input_type -> api.RemoveContainerRequest + 11, // 23: api.Docker.ExecContainer:input_type -> api.ExecContainerRequest + 15, // 24: api.Docker.ContainerLogs:input_type -> api.ContainerLogsRequest + 17, // 25: api.Docker.PullImage:input_type -> api.PullImageRequest + 19, // 26: api.Docker.InspectImage:input_type -> api.InspectImageRequest + 22, // 27: api.Docker.InspectRemoteImage:input_type -> api.InspectRemoteImageRequest + 25, // 28: api.Docker.ListImages:input_type -> api.ListImagesRequest + 28, // 29: api.Docker.CreateVolume:input_type -> api.CreateVolumeRequest + 30, // 30: api.Docker.ListVolumes:input_type -> api.ListVolumesRequest + 33, // 31: api.Docker.RemoveVolume:input_type -> api.RemoveVolumeRequest + 34, // 32: api.Docker.CreateServiceContainer:input_type -> api.CreateServiceContainerRequest + 3, // 33: api.Docker.InspectServiceContainer:input_type -> api.InspectContainerRequest + 36, // 34: api.Docker.ListServiceContainers:input_type -> api.ListServiceContainersRequest + 10, // 35: api.Docker.RemoveServiceContainer:input_type -> api.RemoveContainerRequest + 2, // 36: api.Docker.CreateContainer:output_type -> api.CreateContainerResponse + 4, // 37: api.Docker.InspectContainer:output_type -> api.InspectContainerResponse + 41, // 38: api.Docker.StartContainer:output_type -> google.protobuf.Empty + 41, // 39: api.Docker.StopContainer:output_type -> google.protobuf.Empty + 8, // 40: api.Docker.ListContainers:output_type -> api.ListContainersResponse + 41, // 41: api.Docker.RemoveContainer:output_type -> google.protobuf.Empty + 14, // 42: api.Docker.ExecContainer:output_type -> api.ExecContainerResponse + 16, // 43: api.Docker.ContainerLogs:output_type -> api.ContainerLogEntry + 18, // 44: api.Docker.PullImage:output_type -> api.JSONMessage + 20, // 45: api.Docker.InspectImage:output_type -> api.InspectImageResponse + 23, // 46: api.Docker.InspectRemoteImage:output_type -> api.InspectRemoteImageResponse + 26, // 47: api.Docker.ListImages:output_type -> api.ListImagesResponse + 29, // 48: api.Docker.CreateVolume:output_type -> api.CreateVolumeResponse + 31, // 49: api.Docker.ListVolumes:output_type -> api.ListVolumesResponse + 41, // 50: api.Docker.RemoveVolume:output_type -> google.protobuf.Empty + 2, // 51: api.Docker.CreateServiceContainer:output_type -> api.CreateContainerResponse + 35, // 52: api.Docker.InspectServiceContainer:output_type -> api.ServiceContainer + 37, // 53: api.Docker.ListServiceContainers:output_type -> api.ListServiceContainersResponse + 41, // 54: api.Docker.RemoveServiceContainer:output_type -> google.protobuf.Empty + 36, // [36:55] is the sub-list for method output_type + 17, // [17:36] is the sub-list for method input_type + 17, // [17:17] is the sub-list for extension type_name + 17, // [17:17] is the sub-list for extension extendee + 0, // [0:17] is the sub-list for field type_name } func init() { file_internal_machine_api_pb_docker_proto_init() } @@ -2569,270 +2805,6 @@ func file_internal_machine_api_pb_docker_proto_init() { } } file_internal_machine_api_pb_docker_proto_msgTypes[10].Exporter = func(v any, i int) any { - switch v := v.(*PullImageRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[11].Exporter = func(v any, i int) any { - switch v := v.(*JSONMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[12].Exporter = func(v any, i int) any { - switch v := v.(*InspectImageRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[13].Exporter = func(v any, i int) any { - switch v := v.(*InspectImageResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[14].Exporter = func(v any, i int) any { - switch v := v.(*Image); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[15].Exporter = func(v any, i int) any { - switch v := v.(*InspectRemoteImageRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[16].Exporter = func(v any, i int) any { - switch v := v.(*InspectRemoteImageResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[17].Exporter = func(v any, i int) any { - switch v := v.(*RemoteImage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[18].Exporter = func(v any, i int) any { - switch v := v.(*ListImagesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[19].Exporter = func(v any, i int) any { - switch v := v.(*ListImagesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[20].Exporter = func(v any, i int) any { - switch v := v.(*MachineImages); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[21].Exporter = func(v any, i int) any { - switch v := v.(*CreateVolumeRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[22].Exporter = func(v any, i int) any { - switch v := v.(*CreateVolumeResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[23].Exporter = func(v any, i int) any { - switch v := v.(*ListVolumesRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[24].Exporter = func(v any, i int) any { - switch v := v.(*ListVolumesResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[25].Exporter = func(v any, i int) any { - switch v := v.(*MachineVolumes); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[26].Exporter = func(v any, i int) any { - switch v := v.(*RemoveVolumeRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[27].Exporter = func(v any, i int) any { - switch v := v.(*CreateServiceContainerRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[28].Exporter = func(v any, i int) any { - switch v := v.(*ServiceContainer); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[29].Exporter = func(v any, i int) any { - switch v := v.(*ListServiceContainersRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[30].Exporter = func(v any, i int) any { - switch v := v.(*ListServiceContainersResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[31].Exporter = func(v any, i int) any { - switch v := v.(*MachineServiceContainers); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_internal_machine_api_pb_docker_proto_msgTypes[32].Exporter = func(v any, i int) any { switch v := v.(*ExecContainerRequest); i { case 0: return &v.state @@ -2844,7 +2816,7 @@ func file_internal_machine_api_pb_docker_proto_init() { return nil } } - file_internal_machine_api_pb_docker_proto_msgTypes[33].Exporter = func(v any, i int) any { + file_internal_machine_api_pb_docker_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*ExecConfig); i { case 0: return &v.state @@ -2856,7 +2828,7 @@ func file_internal_machine_api_pb_docker_proto_init() { return nil } } - file_internal_machine_api_pb_docker_proto_msgTypes[34].Exporter = func(v any, i int) any { + file_internal_machine_api_pb_docker_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*ResizeEvent); i { case 0: return &v.state @@ -2868,7 +2840,7 @@ func file_internal_machine_api_pb_docker_proto_init() { return nil } } - file_internal_machine_api_pb_docker_proto_msgTypes[35].Exporter = func(v any, i int) any { + file_internal_machine_api_pb_docker_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*ExecContainerResponse); i { case 0: return &v.state @@ -2880,13 +2852,301 @@ func file_internal_machine_api_pb_docker_proto_init() { return nil } } + file_internal_machine_api_pb_docker_proto_msgTypes[14].Exporter = func(v any, i int) any { + switch v := v.(*ContainerLogsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[15].Exporter = func(v any, i int) any { + switch v := v.(*ContainerLogEntry); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[16].Exporter = func(v any, i int) any { + switch v := v.(*PullImageRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[17].Exporter = func(v any, i int) any { + switch v := v.(*JSONMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[18].Exporter = func(v any, i int) any { + switch v := v.(*InspectImageRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[19].Exporter = func(v any, i int) any { + switch v := v.(*InspectImageResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[20].Exporter = func(v any, i int) any { + switch v := v.(*Image); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[21].Exporter = func(v any, i int) any { + switch v := v.(*InspectRemoteImageRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[22].Exporter = func(v any, i int) any { + switch v := v.(*InspectRemoteImageResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[23].Exporter = func(v any, i int) any { + switch v := v.(*RemoteImage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[24].Exporter = func(v any, i int) any { + switch v := v.(*ListImagesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[25].Exporter = func(v any, i int) any { + switch v := v.(*ListImagesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[26].Exporter = func(v any, i int) any { + switch v := v.(*MachineImages); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[27].Exporter = func(v any, i int) any { + switch v := v.(*CreateVolumeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[28].Exporter = func(v any, i int) any { + switch v := v.(*CreateVolumeResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[29].Exporter = func(v any, i int) any { + switch v := v.(*ListVolumesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[30].Exporter = func(v any, i int) any { + switch v := v.(*ListVolumesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[31].Exporter = func(v any, i int) any { + switch v := v.(*MachineVolumes); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[32].Exporter = func(v any, i int) any { + switch v := v.(*RemoveVolumeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[33].Exporter = func(v any, i int) any { + switch v := v.(*CreateServiceContainerRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[34].Exporter = func(v any, i int) any { + switch v := v.(*ServiceContainer); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[35].Exporter = func(v any, i int) any { + switch v := v.(*ListServiceContainersRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[36].Exporter = func(v any, i int) any { + switch v := v.(*ListServiceContainersResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_internal_machine_api_pb_docker_proto_msgTypes[37].Exporter = func(v any, i int) any { + switch v := v.(*MachineServiceContainers); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } - file_internal_machine_api_pb_docker_proto_msgTypes[32].OneofWrappers = []any{ + file_internal_machine_api_pb_docker_proto_msgTypes[10].OneofWrappers = []any{ (*ExecContainerRequest_Config)(nil), (*ExecContainerRequest_Stdin)(nil), (*ExecContainerRequest_Resize)(nil), } - file_internal_machine_api_pb_docker_proto_msgTypes[35].OneofWrappers = []any{ + file_internal_machine_api_pb_docker_proto_msgTypes[13].OneofWrappers = []any{ (*ExecContainerResponse_ExecId)(nil), (*ExecContainerResponse_Stdout)(nil), (*ExecContainerResponse_Stderr)(nil), @@ -2897,13 +3157,14 @@ func file_internal_machine_api_pb_docker_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_internal_machine_api_pb_docker_proto_rawDesc, - NumEnums: 0, - NumMessages: 36, + NumEnums: 1, + NumMessages: 38, NumExtensions: 0, NumServices: 1, }, GoTypes: file_internal_machine_api_pb_docker_proto_goTypes, DependencyIndexes: file_internal_machine_api_pb_docker_proto_depIdxs, + EnumInfos: file_internal_machine_api_pb_docker_proto_enumTypes, MessageInfos: file_internal_machine_api_pb_docker_proto_msgTypes, }.Build() File_internal_machine_api_pb_docker_proto = out.File diff --git a/internal/machine/api/pb/docker.proto b/internal/machine/api/pb/docker.proto index aa6b609a..4f4370db 100644 --- a/internal/machine/api/pb/docker.proto +++ b/internal/machine/api/pb/docker.proto @@ -5,6 +5,7 @@ package api; option go_package = "github.com/psviderski/uncloud/internal/machine/api/pb"; import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; import "internal/machine/api/pb/common.proto"; service Docker { @@ -15,6 +16,9 @@ service Docker { rpc ListContainers(ListContainersRequest) returns (ListContainersResponse); rpc RemoveContainer(RemoveContainerRequest) returns (google.protobuf.Empty); + rpc ExecContainer(stream ExecContainerRequest) returns (stream ExecContainerResponse); + rpc ContainerLogs(ContainerLogsRequest) returns (stream ContainerLogEntry); + rpc PullImage(PullImageRequest) returns (stream JSONMessage); rpc InspectImage(InspectImageRequest) returns (InspectImageResponse); // InspectRemoteImage returns the image metadata for an image in a remote registry using the machine's @@ -30,8 +34,6 @@ service Docker { rpc InspectServiceContainer(InspectContainerRequest) returns (ServiceContainer); rpc ListServiceContainers(ListServiceContainersRequest) returns (ListServiceContainersResponse); rpc RemoveServiceContainer(RemoveContainerRequest) returns (google.protobuf.Empty); - - rpc ExecContainer(stream ExecContainerRequest) returns (stream ExecContainerResponse); } message CreateContainerRequest { @@ -94,6 +96,64 @@ message RemoveContainerRequest { bytes options = 2; } +message ExecContainerRequest { + oneof payload { + // Initial configuration for the exec session. Must be sent as the first message. + ExecConfig config = 1; + // Raw stdin data to be written to the exec process. + bytes stdin = 2; + // TTY resize event (only used when TTY is enabled). + ResizeEvent resize = 3; + } +} + +message ExecConfig { + // Container ID to execute the command in. + string container_id = 1; + // JSON serialised ExecOptions + bytes options = 2; +} + +message ResizeEvent { + uint32 height = 1; + uint32 width = 2; +} + +message ExecContainerResponse { + oneof payload { + // Exec instance ID returned after creating the exec. + string exec_id = 1; + // Raw stdout data from the exec process. + bytes stdout = 2; + // Raw stderr data from the exec process (only when TTY is disabled). + bytes stderr = 3; + // Exit code of the exec process. Sent as the final message. + int32 exit_code = 4; + } +} + +message ContainerLogsRequest { + string container_id = 1; + // Options for logs retrieval. + bool follow = 2; + int32 tail = 3; // -1 means all + string since = 4; // https://www.rfc-editor.org/rfc/rfc3339.html timestamp or Go duration string + string until = 5; // https://www.rfc-editor.org/rfc/rfc3339.html timestamp or Go duration string +} + +message ContainerLogEntry { + enum StreamType { + UNKNOWN = 0; + STDOUT = 1; + STDERR = 2; + HEARTBEAT = 3; + } + StreamType stream = 1; + google.protobuf.Timestamp timestamp = 2; + // Log line content. Empty for heartbeat entries. + bytes message = 3; +} + message PullImageRequest { string image = 1; // JSON serialised image.PullOptions. @@ -216,39 +276,3 @@ message MachineServiceContainers { Metadata metadata = 1; repeated ServiceContainer containers = 2; } - -message ExecContainerRequest { - oneof payload { - // Initial configuration for the exec session. Must be sent as the first message. - ExecConfig config = 1; - // Raw stdin data to be written to the exec process. - bytes stdin = 2; - // TTY resize event (only used when TTY is enabled). - ResizeEvent resize = 3; - } -} - -message ExecConfig { - // Container ID to execute the command in. - string container_id = 1; - // JSON serialised ExecOptions - bytes options = 2; -} - -message ResizeEvent { - uint32 height = 1; - uint32 width = 2; -} - -message ExecContainerResponse { - oneof payload { - // Exec instance ID returned after creating the exec. - string exec_id = 1; - // Raw stdout data from the exec process. - bytes stdout = 2; - // Raw stderr data from the exec process (only when TTY is disabled). - bytes stderr = 3; - // Exit code of the exec process. Sent as the final message. - int32 exit_code = 4; - } -} diff --git a/internal/machine/api/pb/docker_grpc.pb.go b/internal/machine/api/pb/docker_grpc.pb.go index 27024d57..4362b5b6 100644 --- a/internal/machine/api/pb/docker_grpc.pb.go +++ b/internal/machine/api/pb/docker_grpc.pb.go @@ -26,6 +26,8 @@ const ( Docker_StopContainer_FullMethodName = "/api.Docker/StopContainer" Docker_ListContainers_FullMethodName = "/api.Docker/ListContainers" Docker_RemoveContainer_FullMethodName = "/api.Docker/RemoveContainer" + Docker_ExecContainer_FullMethodName = "/api.Docker/ExecContainer" + Docker_ContainerLogs_FullMethodName = "/api.Docker/ContainerLogs" Docker_PullImage_FullMethodName = "/api.Docker/PullImage" Docker_InspectImage_FullMethodName = "/api.Docker/InspectImage" Docker_InspectRemoteImage_FullMethodName = "/api.Docker/InspectRemoteImage" @@ -37,7 +39,6 @@ const ( Docker_InspectServiceContainer_FullMethodName = "/api.Docker/InspectServiceContainer" Docker_ListServiceContainers_FullMethodName = "/api.Docker/ListServiceContainers" Docker_RemoveServiceContainer_FullMethodName = "/api.Docker/RemoveServiceContainer" - Docker_ExecContainer_FullMethodName = "/api.Docker/ExecContainer" ) // DockerClient is the client API for Docker service. @@ -50,6 +51,8 @@ type DockerClient interface { StopContainer(ctx context.Context, in *StopContainerRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) ListContainers(ctx context.Context, in *ListContainersRequest, opts ...grpc.CallOption) (*ListContainersResponse, error) RemoveContainer(ctx context.Context, in *RemoveContainerRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + ExecContainer(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[ExecContainerRequest, ExecContainerResponse], error) + ContainerLogs(ctx context.Context, in *ContainerLogsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ContainerLogEntry], error) PullImage(ctx context.Context, in *PullImageRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[JSONMessage], error) InspectImage(ctx context.Context, in *InspectImageRequest, opts ...grpc.CallOption) (*InspectImageResponse, error) // InspectRemoteImage returns the image metadata for an image in a remote registry using the machine's @@ -63,7 +66,6 @@ type DockerClient interface { InspectServiceContainer(ctx context.Context, in *InspectContainerRequest, opts ...grpc.CallOption) (*ServiceContainer, error) ListServiceContainers(ctx context.Context, in *ListServiceContainersRequest, opts ...grpc.CallOption) (*ListServiceContainersResponse, error) RemoveServiceContainer(ctx context.Context, in *RemoveContainerRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) - ExecContainer(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[ExecContainerRequest, ExecContainerResponse], error) } type dockerClient struct { @@ -134,9 +136,41 @@ func (c *dockerClient) RemoveContainer(ctx context.Context, in *RemoveContainerR return out, nil } +func (c *dockerClient) ExecContainer(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[ExecContainerRequest, ExecContainerResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &Docker_ServiceDesc.Streams[0], Docker_ExecContainer_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[ExecContainerRequest, ExecContainerResponse]{ClientStream: stream} + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type Docker_ExecContainerClient = grpc.BidiStreamingClient[ExecContainerRequest, ExecContainerResponse] + +func (c *dockerClient) ContainerLogs(ctx context.Context, in *ContainerLogsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ContainerLogEntry], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &Docker_ServiceDesc.Streams[1], Docker_ContainerLogs_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[ContainerLogsRequest, ContainerLogEntry]{ClientStream: stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type Docker_ContainerLogsClient = grpc.ServerStreamingClient[ContainerLogEntry] + func (c *dockerClient) PullImage(ctx context.Context, in *PullImageRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[JSONMessage], error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - stream, err := c.cc.NewStream(ctx, &Docker_ServiceDesc.Streams[0], Docker_PullImage_FullMethodName, cOpts...) + stream, err := c.cc.NewStream(ctx, &Docker_ServiceDesc.Streams[2], Docker_PullImage_FullMethodName, cOpts...) if err != nil { return nil, err } @@ -253,19 +287,6 @@ func (c *dockerClient) RemoveServiceContainer(ctx context.Context, in *RemoveCon return out, nil } -func (c *dockerClient) ExecContainer(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[ExecContainerRequest, ExecContainerResponse], error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - stream, err := c.cc.NewStream(ctx, &Docker_ServiceDesc.Streams[1], Docker_ExecContainer_FullMethodName, cOpts...) - if err != nil { - return nil, err - } - x := &grpc.GenericClientStream[ExecContainerRequest, ExecContainerResponse]{ClientStream: stream} - return x, nil -} - -// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. -type Docker_ExecContainerClient = grpc.BidiStreamingClient[ExecContainerRequest, ExecContainerResponse] - // DockerServer is the server API for Docker service. // All implementations must embed UnimplementedDockerServer // for forward compatibility. @@ -276,6 +297,8 @@ type DockerServer interface { StopContainer(context.Context, *StopContainerRequest) (*emptypb.Empty, error) ListContainers(context.Context, *ListContainersRequest) (*ListContainersResponse, error) RemoveContainer(context.Context, *RemoveContainerRequest) (*emptypb.Empty, error) + ExecContainer(grpc.BidiStreamingServer[ExecContainerRequest, ExecContainerResponse]) error + ContainerLogs(*ContainerLogsRequest, grpc.ServerStreamingServer[ContainerLogEntry]) error PullImage(*PullImageRequest, grpc.ServerStreamingServer[JSONMessage]) error InspectImage(context.Context, *InspectImageRequest) (*InspectImageResponse, error) // InspectRemoteImage returns the image metadata for an image in a remote registry using the machine's @@ -289,7 +312,6 @@ type DockerServer interface { InspectServiceContainer(context.Context, *InspectContainerRequest) (*ServiceContainer, error) ListServiceContainers(context.Context, *ListServiceContainersRequest) (*ListServiceContainersResponse, error) RemoveServiceContainer(context.Context, *RemoveContainerRequest) (*emptypb.Empty, error) - ExecContainer(grpc.BidiStreamingServer[ExecContainerRequest, ExecContainerResponse]) error mustEmbedUnimplementedDockerServer() } @@ -318,6 +340,12 @@ func (UnimplementedDockerServer) ListContainers(context.Context, *ListContainers func (UnimplementedDockerServer) RemoveContainer(context.Context, *RemoveContainerRequest) (*emptypb.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method RemoveContainer not implemented") } +func (UnimplementedDockerServer) ExecContainer(grpc.BidiStreamingServer[ExecContainerRequest, ExecContainerResponse]) error { + return status.Errorf(codes.Unimplemented, "method ExecContainer not implemented") +} +func (UnimplementedDockerServer) ContainerLogs(*ContainerLogsRequest, grpc.ServerStreamingServer[ContainerLogEntry]) error { + return status.Errorf(codes.Unimplemented, "method ContainerLogs not implemented") +} func (UnimplementedDockerServer) PullImage(*PullImageRequest, grpc.ServerStreamingServer[JSONMessage]) error { return status.Errorf(codes.Unimplemented, "method PullImage not implemented") } @@ -351,9 +379,6 @@ func (UnimplementedDockerServer) ListServiceContainers(context.Context, *ListSer func (UnimplementedDockerServer) RemoveServiceContainer(context.Context, *RemoveContainerRequest) (*emptypb.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method RemoveServiceContainer not implemented") } -func (UnimplementedDockerServer) ExecContainer(grpc.BidiStreamingServer[ExecContainerRequest, ExecContainerResponse]) error { - return status.Errorf(codes.Unimplemented, "method ExecContainer not implemented") -} func (UnimplementedDockerServer) mustEmbedUnimplementedDockerServer() {} func (UnimplementedDockerServer) testEmbeddedByValue() {} @@ -483,6 +508,24 @@ func _Docker_RemoveContainer_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _Docker_ExecContainer_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(DockerServer).ExecContainer(&grpc.GenericServerStream[ExecContainerRequest, ExecContainerResponse]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type Docker_ExecContainerServer = grpc.BidiStreamingServer[ExecContainerRequest, ExecContainerResponse] + +func _Docker_ContainerLogs_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(ContainerLogsRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(DockerServer).ContainerLogs(m, &grpc.GenericServerStream[ContainerLogsRequest, ContainerLogEntry]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type Docker_ContainerLogsServer = grpc.ServerStreamingServer[ContainerLogEntry] + func _Docker_PullImage_Handler(srv interface{}, stream grpc.ServerStream) error { m := new(PullImageRequest) if err := stream.RecvMsg(m); err != nil { @@ -674,13 +717,6 @@ func _Docker_RemoveServiceContainer_Handler(srv interface{}, ctx context.Context return interceptor(ctx, in, info, handler) } -func _Docker_ExecContainer_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(DockerServer).ExecContainer(&grpc.GenericServerStream[ExecContainerRequest, ExecContainerResponse]{ServerStream: stream}) -} - -// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. -type Docker_ExecContainerServer = grpc.BidiStreamingServer[ExecContainerRequest, ExecContainerResponse] - // Docker_ServiceDesc is the grpc.ServiceDesc for Docker service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -754,17 +790,22 @@ var Docker_ServiceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{ - { - StreamName: "PullImage", - Handler: _Docker_PullImage_Handler, - ServerStreams: true, - }, { StreamName: "ExecContainer", Handler: _Docker_ExecContainer_Handler, ServerStreams: true, ClientStreams: true, }, + { + StreamName: "ContainerLogs", + Handler: _Docker_ContainerLogs_Handler, + ServerStreams: true, + }, + { + StreamName: "PullImage", + Handler: _Docker_PullImage_Handler, + ServerStreams: true, + }, }, Metadata: "internal/machine/api/pb/docker.proto", } diff --git a/internal/machine/docker/server.go b/internal/machine/docker/server.go index db45a923..7787d3ae 100644 --- a/internal/machine/docker/server.go +++ b/internal/machine/docker/server.go @@ -47,6 +47,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/timestamppb" ) var fullDockerIDRegex = regexp.MustCompile(`^[a-f0-9]{64}$`) @@ -1015,6 +1016,97 @@ func (s *Server) RemoveServiceContainer(ctx context.Context, req *pb.RemoveConta return resp, nil } +// logsHeartbeatInterval is the interval at which heartbeat entries are sent when there are no logs to stream. +const logsHeartbeatInterval = 200 * time.Millisecond + +// ContainerLogs streams logs from a container. +func (s *Server) ContainerLogs( + req *pb.ContainerLogsRequest, stream grpc.ServerStreamingServer[pb.ContainerLogEntry], +) error { + // Stream context is cancelled when the client has disconnected or the stream has ended. + ctx := stream.Context() + + opts := ContainerLogsOptions{ + ContainerID: req.ContainerId, + Follow: req.Follow, + Tail: int(req.Tail), + Since: req.Since, + Until: req.Until, + } + + logsCh, err := s.service.ContainerLogs(ctx, opts) + if err != nil { + if errdefs.IsNotFound(err) { + return status.Error(codes.NotFound, err.Error()) + } + return status.Errorf(codes.Internal, "get container logs: %v", err) + } + + log := slog.With("container_id", req.ContainerId, "stream_id", fmt.Sprintf("%p", stream)[2:]) + log.Debug("Starting container logs streaming.", + "follow", req.Follow, "tail", req.Tail, "since", req.Since, "until", req.Until) + + // Heartbeats are needed only when following logs to let the client know when there are no new log entries + // to allow it to advance the watermark of last received log timestamp. + var heartbeatCh <-chan time.Time + if req.Follow { + heartbeatTicker := time.NewTicker(logsHeartbeatInterval) + defer heartbeatTicker.Stop() + heartbeatCh = heartbeatTicker.C + } + + started := time.Now() + lastSent := time.Time{} + + for { + select { + case entry, ok := <-logsCh: + if !ok { + // Channel closed, no more log entries. + return nil + } + + if entry.Err != nil { + return status.Error(codes.Internal, entry.Err.Error()) + } + + pbEntry := &pb.ContainerLogEntry{ + Stream: api.LogStreamTypeToProto(entry.Stream), + Timestamp: timestamppb.New(entry.Timestamp), + Message: entry.Message, + } + if err = stream.Send(pbEntry); err != nil { + return status.Errorf(codes.Internal, "send log entry: %v", err) + } + lastSent = entry.Timestamp + + case now := <-heartbeatCh: + // Only send heartbeat if no log entries have been sent since the last heartbeat interval or + // if no log entries have been sent at all for at least a heartbeat interval since starting. + if now.Sub(lastSent) < logsHeartbeatInterval || + (lastSent.IsZero() && now.Sub(started) < logsHeartbeatInterval) { + continue + } + + // Use the timestamp one heartbeat in the past to be conservative. This reduces the chance of sending + // a timestamp that is greater than a log entry currently being parsed but not yet sent, which would + // cause the client to incorrectly believe it has received all logs up to that point. + heartbeat := &pb.ContainerLogEntry{ + Stream: pb.ContainerLogEntry_HEARTBEAT, + Timestamp: timestamppb.New(now.Add(-logsHeartbeatInterval)), + } + if err = stream.Send(heartbeat); err != nil { + return status.Errorf(codes.Internal, "send log stream heartbeat: %v", err) + } + lastSent = heartbeat.Timestamp.AsTime() + log.Debug("Sent log stream heartbeat.", "timestamp", lastSent) + + case <-ctx.Done(): + return status.Error(codes.Canceled, ctx.Err().Error()) + } + } +} + // receiveExecConfig receives and validates the initial exec configuration from the stream. func (s *Server) receiveExecConfig(stream pb.Docker_ExecContainerServer) (*pb.ExecConfig, api.ExecOptions, error) { req, err := stream.Recv() diff --git a/internal/machine/docker/service.go b/internal/machine/docker/service.go index f9189327..c77bb18a 100644 --- a/internal/machine/docker/service.go +++ b/internal/machine/docker/service.go @@ -1,18 +1,22 @@ package docker import ( + "bytes" "context" "database/sql" "encoding/json" "errors" "fmt" "log/slog" + "strconv" "strings" + "time" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/image" "github.com/docker/docker/client" + "github.com/docker/docker/pkg/stdcopy" "github.com/jmoiron/sqlx" "github.com/psviderski/uncloud/pkg/api" "google.golang.org/grpc/codes" @@ -150,3 +154,104 @@ func (s *Service) ListImages(ctx context.Context, opts image.ListOptions) (Image return imagesResp, nil } + +// ContainerLogsOptions specifies parameters for ContainerLogs. +type ContainerLogsOptions struct { + ContainerID string + Follow bool + Tail int + Since string + Until string +} + +// ContainerLogs streams logs from a container and returns demultiplexed entries via a channel. +// The channel is closed when streaming completes or context is cancelled. +func (s *Service) ContainerLogs(ctx context.Context, opts ContainerLogsOptions) (<-chan api.ContainerLogEntry, error) { + dockerOpts := container.LogsOptions{ + ShowStdout: true, + ShowStderr: true, + Follow: opts.Follow, + Tail: strconv.FormatInt(int64(opts.Tail), 10), + Since: opts.Since, + Until: opts.Until, + Timestamps: true, + } + + reader, err := s.Client.ContainerLogs(ctx, opts.ContainerID, dockerOpts) + if err != nil { + return nil, err + } + + outCh := make(chan api.ContainerLogEntry) + stdoutWriter := &logsChannelWriter{ctx: ctx, ch: outCh, isStderr: false} + stderrWriter := &logsChannelWriter{ctx: ctx, ch: outCh, isStderr: true} + + // Wrap the context in a cancellable one to unblock the second goroutine below when StdCopy completes. + ctx, cancel := context.WithCancel(ctx) + + // Run StdCopy in a goroutine to be able to handle context cancellation. + go func() { + defer close(outCh) + defer cancel() + + // StdCopy is blocking and will return when the reader is closed in another goroutine below or on error. + if _, err := stdcopy.StdCopy(stdoutWriter, stderrWriter, reader); err != nil { + // Send error as the last entry. + select { + case outCh <- api.ContainerLogEntry{Err: fmt.Errorf("demultiplex container logs: %w", err)}: + case <-ctx.Done(): + } + } + }() + + // Close the reader when the context is done to cancel StdCopy if it's still running. + go func() { + <-ctx.Done() + reader.Close() + }() + + return outCh, nil +} + +// logsChannelWriter is a writer for stdcopy.StdCopy that sends demultiplexed container logs to a channel. +type logsChannelWriter struct { + ctx context.Context + ch chan<- api.ContainerLogEntry + isStderr bool +} + +func (w *logsChannelWriter) Write(data []byte) (n int, err error) { + // Parse timestamp and message from the demultiplexed Docker log payload if the data looks like it contains one. + // Format: 2025-01-01T00:00:00.000000000Z message + timestamp := time.Time{} + message := data + if len(data) > 30 && data[4] == '-' && data[7] == '-' && data[10] == 'T' { + timestampPart, messagePart, found := bytes.Cut(data, []byte(" ")) + if found { + timestamp, err = time.Parse(time.RFC3339Nano, string(timestampPart)) + if err != nil { + timestamp = time.Time{} + } + message = messagePart + } + } + + entry := api.ContainerLogEntry{ + Timestamp: timestamp, + // Clone is required because message is a slice into data, which stdcopy.StdCopy may reuse + // after Write returns but before the entry is consumed from the channel. + Message: bytes.Clone(message), + } + if w.isStderr { + entry.Stream = api.LogStreamStderr + } else { + entry.Stream = api.LogStreamStdout + } + + select { + case w.ch <- entry: + return len(data), nil + case <-w.ctx.Done(): + return 0, w.ctx.Err() + } +} diff --git a/pkg/api/client.go b/pkg/api/client.go index 9c541300..f2208904 100644 --- a/pkg/api/client.go +++ b/pkg/api/client.go @@ -2,13 +2,10 @@ package api import ( "context" - "fmt" - "strings" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/volume" "github.com/psviderski/uncloud/internal/machine/api/pb" - "google.golang.org/grpc/metadata" ) type Client interface { @@ -58,41 +55,3 @@ type VolumeClient interface { ListVolumes(ctx context.Context, filter *VolumeFilter) ([]MachineVolume, error) RemoveVolume(ctx context.Context, machineNameOrID, volumeName string, force bool) error } - -// ProxyMachinesContext returns a new context that proxies gRPC requests to the specified machines. -// If namesOrIDs is nil, all machines are included. -func ProxyMachinesContext( - ctx context.Context, cli MachineClient, namesOrIDs []string, -) (context.Context, MachineMembersList, error) { - // TODO: move the machine IP resolution to the proxy router to allow setting machine names and IDs in the metadata. - machines, err := cli.ListMachines(ctx, nil) - if err != nil { - return nil, nil, fmt.Errorf("list machines: %w", err) - } - - var proxiedMachines MachineMembersList - var notFound []string - for _, nameOrID := range namesOrIDs { - if m := machines.FindByNameOrID(nameOrID); m != nil { - proxiedMachines = append(proxiedMachines, m) - } else { - notFound = append(notFound, nameOrID) - } - } - - if len(notFound) > 0 { - return nil, nil, fmt.Errorf("machines not found: %s", strings.Join(notFound, ", ")) - } - - if len(namesOrIDs) == 0 { - proxiedMachines = machines - } - - md := metadata.New(nil) - for _, m := range proxiedMachines { - machineIP, _ := m.Machine.Network.ManagementIp.ToAddr() - md.Append("machines", machineIP.String()) - } - - return metadata.NewOutgoingContext(ctx, md), proxiedMachines, nil -} diff --git a/pkg/api/logs.go b/pkg/api/logs.go new file mode 100644 index 00000000..80660fb0 --- /dev/null +++ b/pkg/api/logs.go @@ -0,0 +1,84 @@ +package api + +import ( + "errors" + "time" + + "github.com/psviderski/uncloud/internal/machine/api/pb" +) + +const ( + LogStreamUnknown LogStreamType = iota + LogStreamStdout + LogStreamStderr + // LogStreamHeartbeat represents a heartbeat log entry with a timestamp indicating that + // there are no older logs than this timestamp. + LogStreamHeartbeat +) + +type LogStreamType int + +// LogStreamTypeFromProto converts a protobuf ContainerLogEntry.StreamType to the internal LogStreamType. +func LogStreamTypeFromProto(s pb.ContainerLogEntry_StreamType) LogStreamType { + switch s { + case pb.ContainerLogEntry_STDOUT: + return LogStreamStdout + case pb.ContainerLogEntry_STDERR: + return LogStreamStderr + case pb.ContainerLogEntry_HEARTBEAT: + return LogStreamHeartbeat + default: + return LogStreamUnknown + } +} + +// LogStreamTypeToProto converts LogStreamType to protobuf ContainerLogEntry.StreamType. +func LogStreamTypeToProto(s LogStreamType) pb.ContainerLogEntry_StreamType { + switch s { + case LogStreamStdout: + return pb.ContainerLogEntry_STDOUT + case LogStreamStderr: + return pb.ContainerLogEntry_STDERR + case LogStreamHeartbeat: + return pb.ContainerLogEntry_HEARTBEAT + default: + return pb.ContainerLogEntry_UNKNOWN + } +} + +// ServiceLogsOptions specifies parameters for ServiceLogs. +type ServiceLogsOptions struct { + Follow bool + Tail int + Since string + Until string +} + +// ServiceLogEntry represents a single log entry from a service container. +type ServiceLogEntry struct { + // Metadata may not be set if an error occurred (Err is not nil). + Metadata ServiceLogEntryMetadata + ContainerLogEntry +} + +// ServiceLogEntryMetadata contains metadata about the source of a log entry. +type ServiceLogEntryMetadata struct { + ServiceID string + ServiceName string + ContainerID string + MachineID string + MachineName string +} + +// ContainerLogEntry represents a single log entry from a container. +type ContainerLogEntry struct { + Stream LogStreamType + Timestamp time.Time + Message []byte + // Err indicates that an error occurred while streaming logs from a container. + // Other fields are not set if Err is not nil. + Err error +} + +// ErrLogStreamStalled indicates that a log stream stopped sending data and may be unresponsive. +var ErrLogStreamStalled = errors.New("log stream stopped responding") diff --git a/pkg/api/service.go b/pkg/api/service.go index 224b2afc..6075cf36 100644 --- a/pkg/api/service.go +++ b/pkg/api/service.go @@ -8,6 +8,7 @@ import ( "slices" "strings" + mapset "github.com/deckarep/golang-set/v2" "github.com/distribution/reference" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" @@ -366,6 +367,16 @@ type MachineServiceContainer struct { Container ServiceContainer } +// MachineIDs returns a list of unique machine IDs where the service containers are running. +func (s *Service) MachineIDs() []string { + ids := mapset.NewSet[string]() + for _, mc := range s.Containers { + ids.Add(mc.MachineID) + } + + return ids.ToSlice() +} + // Images returns a sorted list of unique images used by the service containers. func (s *Service) Images() []string { images := make(map[string]struct{}) diff --git a/pkg/client/client.go b/pkg/client/client.go index 9a152c5d..10bd756e 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "os" + "strings" "github.com/docker/cli/cli/streams" "github.com/psviderski/uncloud/internal/machine/api/pb" @@ -76,3 +77,41 @@ func proxyToMachine(ctx context.Context, machine *pb.MachineInfo) context.Contex md := metadata.Pairs("machines", machineIP.String()) return metadata.NewOutgoingContext(ctx, md) } + +// ProxyMachinesContext returns a new context that proxies gRPC requests to the specified machines. +// If namesOrIDs is nil, all machines are included. +func (cli *Client) ProxyMachinesContext( + ctx context.Context, namesOrIDs []string, +) (context.Context, api.MachineMembersList, error) { + // TODO: move the machine IP resolution to the proxy router to allow setting machine names and IDs in the metadata. + machines, err := cli.ListMachines(ctx, nil) + if err != nil { + return nil, nil, fmt.Errorf("list machines: %w", err) + } + + var proxiedMachines api.MachineMembersList + var notFound []string + for _, nameOrID := range namesOrIDs { + if m := machines.FindByNameOrID(nameOrID); m != nil { + proxiedMachines = append(proxiedMachines, m) + } else { + notFound = append(notFound, nameOrID) + } + } + + if len(notFound) > 0 { + return nil, nil, fmt.Errorf("machines not found: %s", strings.Join(notFound, ", ")) + } + + if len(namesOrIDs) == 0 { + proxiedMachines = machines + } + + md := metadata.New(nil) + for _, m := range proxiedMachines { + machineIP, _ := m.Machine.Network.ManagementIp.ToAddr() + md.Append("machines", machineIP.String()) + } + + return metadata.NewOutgoingContext(ctx, md), proxiedMachines, nil +} diff --git a/pkg/client/image.go b/pkg/client/image.go index ecf617a6..8e4027ff 100644 --- a/pkg/client/image.go +++ b/pkg/client/image.go @@ -48,7 +48,7 @@ func (cli *Client) InspectRemoteImage(ctx context.Context, id string) ([]api.Mac // it lists images on all machines. func (cli *Client) ListImages(ctx context.Context, filter api.ImageFilter) ([]api.MachineImages, error) { // Broadcast the image list request to the specified machines or all machines if none specified. - listCtx, machines, err := api.ProxyMachinesContext(ctx, cli, filter.Machines) + listCtx, machines, err := cli.ProxyMachinesContext(ctx, filter.Machines) if err != nil { return nil, fmt.Errorf("create request context to broadcast to machines: %w", err) } diff --git a/pkg/client/logmerger.go b/pkg/client/logmerger.go new file mode 100644 index 00000000..b54ebad6 --- /dev/null +++ b/pkg/client/logmerger.go @@ -0,0 +1,310 @@ +package client + +import ( + "container/heap" + "sync" + "time" + + "github.com/psviderski/uncloud/pkg/api" +) + +// logMergerMaxInFlightPerStream limits how many entries each input stream can have in the processing queue before being +// throttled. This ensures fair interleaving between streams and prevents one fast stream from causing unbounded +// buffering while waiting for slower streams. +const ( + logMergerMaxInFlightPerStream = 100 + // logMergerHeartbeatDebounceInterval defines the minimum interval between deduplicated heartbeat entries emitted + // by the LogMerger. Keep it in sync with logsHeartbeatInterval internal/machine/docker/server.go. + logMergerHeartbeatDebounceInterval = 200 * time.Millisecond +) + +// LogMergerOptions configures the behavior of LogMerger. +type LogMergerOptions struct { + // StallTimeout specifies how long a stream can go without receiving any data before it's considered + // stalled and excluded from watermark calculation. A zero timeout disables stall detection. + StallTimeout time.Duration + // StallCheckInterval specifies how often to check for stalled streams. + StallCheckInterval time.Duration +} + +// DefaultLogMergerOptions provides sensible default options that enable stall detection for LogMerger. +var DefaultLogMergerOptions = LogMergerOptions{ + StallTimeout: 10 * time.Second, + StallCheckInterval: 1 * time.Second, +} + +// LogMerger merges multiple log streams into a single chronologically ordered stream based on timestamps. +// It uses a low watermark algorithm to ensure proper ordering across streams. +// Heartbeat entries from streams advance the watermark to enable timely emission of buffered logs. +type LogMerger struct { + streams []*mergerStream + queue logsHeap + // watermark is min(latest_timestamp for each stream). + watermark time.Time + output chan api.ServiceLogEntry + // lastEmitted is the timestamp of the last emitted log entry or heartbeat. + lastEmitted time.Time + stallTimeout time.Duration + stallCheckInterval time.Duration +} + +// NewLogMerger creates a new LogMerger for the given input streams with the specified options. +func NewLogMerger(streams []<-chan api.ServiceLogEntry, opts LogMergerOptions) *LogMerger { + mergerStreams := make([]*mergerStream, len(streams)) + now := time.Now() + for i, ch := range streams { + mergerStreams[i] = &mergerStream{ + stream: ch, + semaphore: make(chan struct{}, logMergerMaxInFlightPerStream), + lastActivity: now, + } + } + + return &LogMerger{ + streams: mergerStreams, + output: make(chan api.ServiceLogEntry), + stallTimeout: opts.StallTimeout, + stallCheckInterval: opts.StallCheckInterval, + } +} + +// Stream starts the merge process and returns a channel that emits log entries in chronological order. +// The returned channel is closed when all input streams are closed. +func (m *LogMerger) Stream() <-chan api.ServiceLogEntry { + if len(m.streams) == 0 { + close(m.output) + return m.output + } + + go m.run() + + return m.output +} + +// mergerStream combines a stream channel with its state and flow control. +type mergerStream struct { + stream <-chan api.ServiceLogEntry + semaphore chan struct{} + // Latest timestamp seen from this stream (log or heartbeat). + lastSeen time.Time + // Wall clock time when we last received any data from this stream. + lastActivity time.Time + // Metadata associated with this stream. It's populated from the first log entry received. + metadata *api.ServiceLogEntryMetadata + // Whether the stream channel has closed. + closed bool + // Whether the stream is considered stalled (no data received within timeout). + stalled bool +} + +// streamEvent represents an event from a stream (entry received or stream closed). +type streamEvent struct { + stream *mergerStream + entry api.ServiceLogEntry + closed bool +} + +// queuedEntry wraps a log entry with its source semaphore for release tracking. +type queuedEntry struct { + entry api.ServiceLogEntry + semaphore chan struct{} +} + +// run is the main processing loop that merges all streams. +func (m *LogMerger) run() { + defer close(m.output) + + // Fan-in channel for stream events. + events := make(chan streamEvent) + + // Start a reader goroutine for each stream to send entries to the events channel with flow control. + var wg sync.WaitGroup + for _, stream := range m.streams { + wg.Go(func() { + for entry := range stream.stream { + // Acquire semaphore slot before sending the entry to limit in-flight unprocessed entries per stream. + stream.semaphore <- struct{}{} + events <- streamEvent{stream: stream, entry: entry} + } + + events <- streamEvent{stream: stream, closed: true} + }) + } + + // Close events channel when all readers finish. + go func() { + wg.Wait() + close(events) + }() + + // Set up stall detection timer if enabled. + var stallCh <-chan time.Time + if m.stallTimeout > 0 && m.stallCheckInterval > 0 { + stallTicker := time.NewTicker(m.stallCheckInterval) + stallCh = stallTicker.C + defer stallTicker.Stop() + } + + // Process events and emit entries. + for { + select { + case e, ok := <-events: + if !ok { + // All streams closed: flush remaining entries in order. + for m.queue.Len() > 0 { + qe := heap.Pop(&m.queue).(queuedEntry) + m.output <- qe.entry + <-qe.semaphore + } + return + } + + e.stream.lastActivity = time.Now() + if e.stream.stalled { + e.stream.stalled = false + } + if e.stream.metadata == nil { + e.stream.metadata = &e.entry.Metadata + } + + if e.closed { + e.stream.closed = true + + m.updateWatermark() + m.emitReadyEntries() + continue + } + + // Forward errors immediately and release semaphore. + if e.entry.Err != nil { + m.output <- e.entry + <-e.stream.semaphore + continue + } + + if e.entry.Timestamp.After(e.stream.lastSeen) { + e.stream.lastSeen = e.entry.Timestamp + } + if e.entry.Stream == api.LogStreamStdout || e.entry.Stream == api.LogStreamStderr { + heap.Push(&m.queue, queuedEntry{entry: e.entry, semaphore: e.stream.semaphore}) + } + + m.updateWatermark() + m.emitReadyEntries() + + // When merging streams, each input emits its own heartbeats. We want to debounce them and emit our own + // heartbeats at the same rate as a single input stream. Note that we need to adjust the heartbeat timestamp + // to the current watermark to not violate ordering guarantees. + if e.entry.Stream == api.LogStreamHeartbeat { + if m.watermark.Sub(m.lastEmitted) >= logMergerHeartbeatDebounceInterval { + heartbeat := e.entry + heartbeat.Timestamp = m.watermark + m.output <- heartbeat + m.lastEmitted = m.watermark + } + // Heartbeat processed, release semaphore. + <-e.stream.semaphore + } + + case <-stallCh: + stalled := m.checkStalledStreams() + if len(stalled) == 0 { + continue + } + + for _, s := range stalled { + errEntry := api.ServiceLogEntry{ + ContainerLogEntry: api.ContainerLogEntry{ + Err: api.ErrLogStreamStalled, + }, + } + if s.metadata != nil { + errEntry.Metadata = *s.metadata + } + + m.output <- errEntry + } + + m.updateWatermark() + m.emitReadyEntries() + } + } +} + +// checkStalledStreams marks streams as stalled if they haven't received any data within the timeout. +// Returns true if any stream's stalled state changed. +func (m *LogMerger) checkStalledStreams() []*mergerStream { + var stalled []*mergerStream + now := time.Now() + + for _, s := range m.streams { + if s.closed || s.stalled { + continue + } + + if now.Sub(s.lastActivity) > m.stallTimeout { + s.stalled = true + stalled = append(stalled, s) + } + } + + return stalled +} + +// updateWatermark recalculates the low watermark based on the lastSeen timestamps of all active streams. +func (m *LogMerger) updateWatermark() { + first := true + + for _, s := range m.streams { + if s.closed || s.stalled { + // Closed and stalled streams don't affect watermark. + continue + } + if first || s.lastSeen.Before(m.watermark) { + m.watermark = s.lastSeen + first = false + } + } +} + +// emitReadyEntries pops and emits all buffered entries from the queue with timestamp before the watermark. +func (m *LogMerger) emitReadyEntries() { + if m.watermark.IsZero() { + // No entries received yet. + return + } + + for m.queue.Len() > 0 && m.queue[0].entry.Timestamp.Compare(m.watermark) <= 0 { + qe := heap.Pop(&m.queue).(queuedEntry) + m.output <- qe.entry + m.lastEmitted = qe.entry.Timestamp + <-qe.semaphore + } +} + +// logsHeap is a min-heap (heap.Interface) of queued entries ordered by timestamp. +type logsHeap []queuedEntry + +func (h *logsHeap) Len() int { + return len(*h) +} + +func (h *logsHeap) Less(i, j int) bool { + return (*h)[i].entry.Timestamp.Before((*h)[j].entry.Timestamp) +} + +func (h *logsHeap) Swap(i, j int) { + (*h)[i], (*h)[j] = (*h)[j], (*h)[i] +} + +func (h *logsHeap) Push(x any) { + *h = append(*h, x.(queuedEntry)) +} + +func (h *logsHeap) Pop() any { + old := *h + n := len(old) + x := old[n-1] + *h = old[:n-1] + return x +} diff --git a/pkg/client/logmerger_test.go b/pkg/client/logmerger_test.go new file mode 100644 index 00000000..fdb3e0e1 --- /dev/null +++ b/pkg/client/logmerger_test.go @@ -0,0 +1,383 @@ +package client + +import ( + "testing" + "time" + + "github.com/psviderski/uncloud/pkg/api" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// testEntry creates a ServiceLogEntry for testing. +func testEntry(stream api.LogStreamType, ts time.Time, msg string) api.ServiceLogEntry { + return api.ServiceLogEntry{ + ContainerLogEntry: api.ContainerLogEntry{ + Stream: stream, + Timestamp: ts, + Message: []byte(msg), + }, + } +} + +// collectEntries collects up to maxCount entries from the channel or until it is closed. +func collectEntries(t *testing.T, ch <-chan api.ServiceLogEntry, maxCount int) []api.ServiceLogEntry { + t.Helper() + var entries []api.ServiceLogEntry + + for i := 0; i < maxCount || maxCount <= 0; i++ { + select { + case e, ok := <-ch: + if !ok { + return entries + } + entries = append(entries, e) + case <-time.After(1 * time.Second): + require.FailNow(t, "timed out waiting for log entry") + } + } + + return entries +} + +func TestLogMerger_EmptyStreams(t *testing.T) { + t.Parallel() + + merger := NewLogMerger(nil, LogMergerOptions{}) + output := merger.Stream() + + _, ok := <-output + assert.False(t, ok, "output channel should be closed for empty streams") +} + +func TestLogMerger_SingleStream(t *testing.T) { + t.Parallel() + + ch := make(chan api.ServiceLogEntry, 10) + merger := NewLogMerger([]<-chan api.ServiceLogEntry{ch}, LogMergerOptions{}) + output := merger.Stream() + + t1 := time.Now() + t2 := t1.Add(time.Second) + + ch <- testEntry(api.LogStreamStdout, t1, "first") + ch <- testEntry(api.LogStreamStdout, t2, "second") + + results := collectEntries(t, output, 2) + + require.Len(t, results, 2) + assert.Equal(t, "first", string(results[0].Message)) + assert.Equal(t, "second", string(results[1].Message)) + + close(ch) + + results = collectEntries(t, output, 0) + assert.Len(t, results, 0, "no entries expected after close") +} + +func TestLogMerger_PreservesData(t *testing.T) { + t.Parallel() + + ch := make(chan api.ServiceLogEntry, 10) + merger := NewLogMerger([]<-chan api.ServiceLogEntry{ch}, LogMergerOptions{}) + output := merger.Stream() + + metadata := api.ServiceLogEntryMetadata{ + ServiceID: "svc-123", + ServiceName: "my-service", + MachineID: "machine-456", + MachineName: "machine-1", + } + + e := api.ServiceLogEntry{ + Metadata: metadata, + ContainerLogEntry: api.ContainerLogEntry{ + Stream: api.LogStreamStdout, + Timestamp: time.Now(), + Message: []byte("test"), + }, + } + ch <- e + close(ch) + + results := collectEntries(t, output, 0) + require.Len(t, results, 1) + assert.Equal(t, e, results[0]) +} + +func TestLogMerger_BasicMerge(t *testing.T) { + t.Parallel() + + ch1 := make(chan api.ServiceLogEntry, 10) + ch2 := make(chan api.ServiceLogEntry, 10) + + merger := NewLogMerger([]<-chan api.ServiceLogEntry{ch1, ch2}, LogMergerOptions{}) + output := merger.Stream() + + t1 := time.Now() + t2 := t1.Add(time.Second) + t3 := t1.Add(2 * time.Second) + t4 := t1.Add(3 * time.Second) + + // Send interleaved entries from both streams. + ch1 <- testEntry(api.LogStreamStdout, t1, "ch1-first") + ch2 <- testEntry(api.LogStreamStdout, t2, "ch2-first") + ch1 <- testEntry(api.LogStreamStdout, t3, "ch1-second") + ch2 <- testEntry(api.LogStreamStdout, t4, "ch2-second") + + // Send heartbeats to advance watermark past all entries. + t5 := t1.Add(4 * time.Second) + ch1 <- testEntry(api.LogStreamHeartbeat, t5, "") + ch2 <- testEntry(api.LogStreamHeartbeat, t5, "") + + results := collectEntries(t, output, 4) + require.Len(t, results, 4) + assert.Equal(t, "ch1-first", string(results[0].Message)) + assert.Equal(t, "ch2-first", string(results[1].Message)) + assert.Equal(t, "ch1-second", string(results[2].Message)) + assert.Equal(t, "ch2-second", string(results[3].Message)) + + close(ch1) + close(ch2) + + results = collectEntries(t, output, 0) + assert.Len(t, results, 1, "one debounced heartbeat expected after close") + assert.Equal(t, api.LogStreamHeartbeat, results[0].Stream) + assert.Equal(t, t5, results[0].Timestamp) +} + +func TestLogMerger_HeartbeatAdvancesWatermark(t *testing.T) { + t.Parallel() + + ch1 := make(chan api.ServiceLogEntry, 10) + ch2 := make(chan api.ServiceLogEntry, 10) + + merger := NewLogMerger([]<-chan api.ServiceLogEntry{ch1, ch2}, LogMergerOptions{}) + output := merger.Stream() + + t1 := time.Now() + t2 := t1.Add(time.Second) + t3 := t1.Add(2 * time.Second) + + // Stream 1 sends a log entry. + ch1 <- testEntry(api.LogStreamStdout, t1, "ch1-first") + ch1 <- testEntry(api.LogStreamStdout, t3, "ch1-second") + // Stream 2 is quiet but sends a heartbeat. + ch2 <- testEntry(api.LogStreamHeartbeat, t2, "") + + // Now stream 1's entry should be emitted because watermark is t1 (min of t1, t2). + results := collectEntries(t, output, 1) + require.Len(t, results, 1) + assert.Equal(t, "ch1-first", string(results[0].Message)) + + close(ch1) + close(ch2) + + results = collectEntries(t, output, 0) + require.NotEmpty(t, results) + + // Depending on timing, we may get a heartbeat before the second log entry. + require.LessOrEqual(t, len(results), 2, "one or two entries expected after close") + if len(results) == 2 { + assert.Equal(t, api.LogStreamHeartbeat, results[0].Stream) + assert.Equal(t, t2, results[0].Timestamp) + results = results[1:] + } + assert.Equal(t, "ch1-second", string(results[0].Message)) +} + +func TestLogMerger_ErrorForwarding(t *testing.T) { + t.Parallel() + + ch1 := make(chan api.ServiceLogEntry, 10) + ch2 := make(chan api.ServiceLogEntry, 10) + merger := NewLogMerger([]<-chan api.ServiceLogEntry{ch1, ch2}, LogMergerOptions{}) + output := merger.Stream() + + t1 := time.Now() + + ch1 <- testEntry(api.LogStreamStdout, t1, "ch1-first") + // Send an error entry. + ch1 <- api.ServiceLogEntry{ + ContainerLogEntry: api.ContainerLogEntry{ + Err: assert.AnError, + }, + } + + results := collectEntries(t, output, 1) + require.Len(t, results, 1, "expected error to emitted out of order") + assert.Equal(t, assert.AnError, results[0].Err) + + close(ch1) + close(ch2) + + results = collectEntries(t, output, 0) + assert.Len(t, results, 1) + assert.Equal(t, "ch1-first", string(results[0].Message)) +} + +func TestLogMerger_OutOfOrderSingleStream(t *testing.T) { + t.Parallel() + + ch := make(chan api.ServiceLogEntry, 10) + merger := NewLogMerger([]<-chan api.ServiceLogEntry{ch}, LogMergerOptions{}) + output := merger.Stream() + + t1 := time.Now() + t2 := t1.Add(time.Second) + t3 := t1.Add(2 * time.Second) + t4 := t1.Add(3 * time.Second) + + // Send entries out of order within the stream. + ch <- testEntry(api.LogStreamStdout, t3, "third") + ch <- testEntry(api.LogStreamStdout, t2, "second") + ch <- testEntry(api.LogStreamStdout, t4, "forth") + ch <- testEntry(api.LogStreamStdout, t1, "first") + + results := collectEntries(t, output, 4) + require.Len(t, results, 4) + // Emitted in the same order as sent since no buffering/reordering is done within a single stream. + assert.Equal(t, "third", string(results[0].Message)) + assert.Equal(t, "second", string(results[1].Message)) + assert.Equal(t, "forth", string(results[2].Message)) + assert.Equal(t, "first", string(results[3].Message)) + + close(ch) + + results = collectEntries(t, output, 0) + assert.Len(t, results, 0, "no entries expected after close") +} + +// Test that entries from streams with different rates are merged correctly in chronological order. +func TestLogMerger_UnevenStreams(t *testing.T) { + t.Parallel() + + numFastEntries := logMergerMaxInFlightPerStream + + // Use buffered channels to allow sends without blocking on receiver. + ch1 := make(chan api.ServiceLogEntry, numFastEntries+5) + ch2 := make(chan api.ServiceLogEntry, 10) + + merger := NewLogMerger([]<-chan api.ServiceLogEntry{ch1, ch2}, LogMergerOptions{}) + output := merger.Stream() + + baseTime := time.Now() + + // Stream 1 sends many entries quickly (0ms - 104ms). + for i := 0; i < numFastEntries; i++ { + ch1 <- testEntry(api.LogStreamStdout, baseTime.Add(time.Duration(i)*time.Millisecond), "fast") + } + + // Stream 2 sends entries that interleave with fast entries. + ch2 <- testEntry(api.LogStreamStdout, baseTime.Add(5*time.Millisecond), "slow") + ch2 <- testEntry(api.LogStreamStdout, baseTime.Add(50*time.Millisecond), "slow") + + // Send heartbeats to advance watermark past all entries so they get emitted. + finalTime := baseTime.Add(time.Second) + ch1 <- testEntry(api.LogStreamHeartbeat, finalTime, "") + ch2 <- testEntry(api.LogStreamHeartbeat, finalTime.Add(10*time.Millisecond), "") + + // Read exactly numFastEntries + 2 log entries. + expectedCount := numFastEntries + 2 + results := collectEntries(t, output, expectedCount) + require.Len(t, results, expectedCount) + + // Count entries from each stream. + fastCount := 0 + slowCount := 0 + for _, entry := range results { + switch string(entry.Message) { + case "fast": + fastCount++ + case "slow": + slowCount++ + } + } + assert.Equal(t, numFastEntries, fastCount) + assert.Equal(t, 2, slowCount) + + // Verify entries are in chronological order. + for i := 1; i < len(results); i++ { + assert.False(t, results[i].Timestamp.Before(results[i-1].Timestamp), + "entry %d (ts=%v) should not be before entry %d (ts=%v)", + i, results[i].Timestamp, i-1, results[i-1].Timestamp) + } + + close(ch1) + close(ch2) + + results = collectEntries(t, output, 0) + require.Len(t, results, 1, "one debounced heartbeat expected after close") + assert.Equal(t, api.LogStreamHeartbeat, results[0].Stream) +} + +func TestLogMerger_StalledStreamExcludedFromWatermark(t *testing.T) { + t.Parallel() + + ch1 := make(chan api.ServiceLogEntry, 10) + ch2 := make(chan api.ServiceLogEntry, 10) + + stallTimeout := 100 * time.Millisecond + merger := NewLogMerger([]<-chan api.ServiceLogEntry{ch1, ch2}, LogMergerOptions{ + StallTimeout: stallTimeout, + StallCheckInterval: 20 * time.Millisecond, + }) + output := merger.Stream() + + //// Collect all output entries in a separate goroutine. + //var results []api.ServiceLogEntry + //doneCollecting := make(chan struct{}) + //go func() { + // for entry := range output { + // results = append(results, entry) + // } + // close(doneCollecting) + //}() + + t1 := time.Now() + t2 := t1.Add(time.Second) + t3 := t1.Add(2 * time.Second) + t4 := t1.Add(3 * time.Second) + + e1 := testEntry(api.LogStreamStdout, t1, "ch1-entry") + e1.Metadata = api.ServiceLogEntryMetadata{ + ServiceID: "ch1-svc1", + ServiceName: "ch1-svcName", + ContainerID: "ch1-ctr1", + MachineID: "ch1-machine1", + MachineName: "ch1-machineName", + } + + ch1 <- e1 + ch2 <- testEntry(api.LogStreamStdout, t2, "ch2-first") + + // Watermark is t1 now so ch1's entry could be collected. + results := collectEntries(t, output, 1) + require.Len(t, results, 1) + assert.Equal(t, "ch1-entry", string(results[0].Message)) + + // Keep pushing to stream 2 so that it does not stall. But it can't emit anything because watermark is stuck at t1. + time.Sleep(stallTimeout / 2) + ch2 <- testEntry(api.LogStreamStdout, t3, "ch2-second") + + // 1/2 + 2/3 = 7/6 > 1, so stream 1 should be considered stalled now. + time.Sleep(stallTimeout / 3 * 2) + ch2 <- testEntry(api.LogStreamStdout, t4, "ch2-third") + + results = collectEntries(t, output, 1) + require.ErrorIs(t, results[0].Err, api.ErrLogStreamStalled) + assert.Equal(t, e1.Metadata, results[0].Metadata, "stalled entry should have stream metadata") + + // Now that stream 1 is marked as stalled and ignored, all in-flight entries from stream 2 are emitted. + results = collectEntries(t, output, 3) + require.Len(t, results, 3) + assert.Equal(t, "ch2-first", string(results[0].Message)) + assert.Equal(t, "ch2-second", string(results[1].Message)) + assert.Equal(t, "ch2-third", string(results[2].Message)) + + close(ch1) + close(ch2) + + results = collectEntries(t, output, 0) + assert.Len(t, results, 0) +} diff --git a/pkg/client/logs.go b/pkg/client/logs.go new file mode 100644 index 00000000..0e5517ef --- /dev/null +++ b/pkg/client/logs.go @@ -0,0 +1,141 @@ +package client + +import ( + "context" + "fmt" + "io" + + "github.com/docker/docker/pkg/stringid" + "github.com/psviderski/uncloud/internal/machine/api/pb" + "github.com/psviderski/uncloud/pkg/api" +) + +// ServiceLogs streams log entries from all service containers in chronological order based on timestamps. +// Keep in mind that perfect ordering of log events across multiple machines can't be guaranteed due to the +// imperfection of physical clocks or potential clock skew between machines. +// It uses a low watermark algorithm to ensure proper ordering across multiple machines. +// Heartbeat entries from the server advance the watermark to enable timely emission of buffered logs. +func (cli *Client) ServiceLogs( + ctx context.Context, serviceNameOrID string, opts api.ServiceLogsOptions, +) (api.Service, <-chan api.ServiceLogEntry, error) { + svc, err := cli.InspectService(ctx, serviceNameOrID) + if err != nil { + return svc, nil, fmt.Errorf("inspect service: %w", err) + } + + if len(svc.Containers) == 0 { + return svc, nil, fmt.Errorf("no containers found for service: %s", serviceNameOrID) + } + + machines, err := cli.ListMachines(ctx, nil) + if err != nil { + return svc, nil, fmt.Errorf("list machines: %w", err) + } + + ctrStreams := make([]<-chan api.ServiceLogEntry, 0, len(svc.Containers)) + for _, ctr := range svc.Containers { + // Try to get machine name for ServiceLogEntry metadata and friendlier error message. + machineName := ctr.MachineID + m := machines.FindByNameOrID(ctr.MachineID) + if m != nil { + machineName = m.Machine.Name + } + + stream, err := cli.ContainerLogs(ctx, ctr.MachineID, ctr.Container.ID, opts) + if err != nil { + return svc, nil, fmt.Errorf("stream logs from service container '%s' on machine '%s': %w", + stringid.TruncateID(ctr.Container.ID), machineName, err) + } + + // Enrich log entries from the container with service metadata. + metadata := api.ServiceLogEntryMetadata{ + ServiceID: svc.ID, + ServiceName: svc.Name, + ContainerID: ctr.Container.ID, + MachineID: ctr.MachineID, + MachineName: machineName, + } + enrichedStream := logsStreamWithServiceMetadata(stream, metadata) + ctrStreams = append(ctrStreams, enrichedStream) + } + + // Use the log merger to combine streams from all containers in chronological order. + merger := NewLogMerger(ctrStreams, DefaultLogMergerOptions) + mergedStream := merger.Stream() + + return svc, mergedStream, nil +} + +// ContainerLogs streams log entries from a single container on a specified machine. +func (cli *Client) ContainerLogs( + ctx context.Context, machineNameOrID string, containerID string, opts api.ServiceLogsOptions, +) (<-chan api.ContainerLogEntry, error) { + proxyCtx, _, err := cli.ProxyMachinesContext(ctx, []string{machineNameOrID}) + if err != nil { + return nil, fmt.Errorf("create request context to proxy to machine '%s': %w", machineNameOrID, err) + } + + req := &pb.ContainerLogsRequest{ + ContainerId: containerID, + Follow: opts.Follow, + Tail: int32(opts.Tail), + Since: opts.Since, + Until: opts.Until, + } + stream, err := cli.Docker.GRPCClient.ContainerLogs(proxyCtx, req) + if err != nil { + return nil, err + } + + ch := make(chan api.ContainerLogEntry) + + go func() { + defer close(ch) + + for { + pbEntry, err := stream.Recv() + if err == io.EOF { + return + } + if err != nil { + ch <- api.ContainerLogEntry{ + Err: err, + } + return + } + + entry := api.ContainerLogEntry{ + Stream: api.LogStreamTypeFromProto(pbEntry.Stream), + Message: pbEntry.Message, + Timestamp: pbEntry.Timestamp.AsTime(), + } + + select { + case ch <- entry: + case <-ctx.Done(): + return + } + } + }() + + return ch, nil +} + +// logsStreamWithServiceMetadata wraps a container logs stream and enriches each log entry with service metadata. +func logsStreamWithServiceMetadata( + stream <-chan api.ContainerLogEntry, metadata api.ServiceLogEntryMetadata, +) <-chan api.ServiceLogEntry { + out := make(chan api.ServiceLogEntry) + + go func() { + for entry := range stream { + out <- api.ServiceLogEntry{ + Metadata: metadata, + ContainerLogEntry: entry, + } + } + close(out) + }() + + return out +} diff --git a/pkg/client/machine.go b/pkg/client/machine.go index b58549b7..81093181 100644 --- a/pkg/client/machine.go +++ b/pkg/client/machine.go @@ -48,6 +48,26 @@ func (cli *Client) ListMachines(ctx context.Context, filter *api.MachineFilter) return machines, nil } +func MachineMatchesFilter(machine *pb.MachineMember, filter *api.MachineFilter) bool { + if filter == nil { + return true + } + + if filter.Available && machine.State == pb.MachineMember_DOWN { + return false + } + + if len(filter.NamesOrIDs) > 0 { + if !slices.ContainsFunc(filter.NamesOrIDs, func(nameOrID string) bool { + return machine.Machine.Id == nameOrID || machine.Machine.Name == nameOrID + }) { + return false + } + } + + return true +} + // UpdateMachine updates machine configuration in the cluster. func (cli *Client) UpdateMachine(ctx context.Context, req *pb.UpdateMachineRequest) (*pb.MachineInfo, error) { resp, err := cli.ClusterClient.UpdateMachine(ctx, req) @@ -76,23 +96,3 @@ func (cli *Client) RenameMachine(ctx context.Context, nameOrID, newName string) return cli.UpdateMachine(ctx, req) } - -func MachineMatchesFilter(machine *pb.MachineMember, filter *api.MachineFilter) bool { - if filter == nil { - return true - } - - if filter.Available && machine.State == pb.MachineMember_DOWN { - return false - } - - if len(filter.NamesOrIDs) > 0 { - if !slices.ContainsFunc(filter.NamesOrIDs, func(nameOrID string) bool { - return machine.Machine.Id == nameOrID || machine.Machine.Name == nameOrID - }) { - return false - } - } - - return true -} diff --git a/pkg/client/volume.go b/pkg/client/volume.go index aefeed23..6bf68913 100644 --- a/pkg/client/volume.go +++ b/pkg/client/volume.go @@ -55,7 +55,7 @@ func (cli *Client) ListVolumes(ctx context.Context, filter *api.VolumeFilter) ([ proxyMachines = filter.Machines } - listCtx, machines, err := api.ProxyMachinesContext(ctx, cli, proxyMachines) + listCtx, machines, err := cli.ProxyMachinesContext(ctx, proxyMachines) if err != nil { return nil, fmt.Errorf("create request context to broadcast to all machines: %w", err) }