syntax = "proto3";

package api;

option go_package = "github.com/psviderski/uncloud/internal/machine/api/pb";

import "google/protobuf/empty.proto";
import "internal/machine/api/pb/common.proto";

service Docker {
  rpc CreateContainer(CreateContainerRequest) returns (CreateContainerResponse);
  rpc InspectContainer(InspectContainerRequest) returns (InspectContainerResponse);
  rpc StartContainer(StartContainerRequest) returns (google.protobuf.Empty);
  rpc StopContainer(StopContainerRequest) returns (google.protobuf.Empty);
  rpc ListContainers(ListContainersRequest) returns (ListContainersResponse);
  rpc RemoveContainer(RemoveContainerRequest) returns (google.protobuf.Empty);

  rpc ExecContainer(stream ExecContainerRequest) returns (stream ExecContainerResponse);
  rpc ContainerLogs(LogsRequest) returns (stream LogEntry);

  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
  // Docker auth credentials if necessary.
  rpc InspectRemoteImage(InspectRemoteImageRequest) returns (InspectRemoteImageResponse);
  rpc ListImages(ListImagesRequest) returns (ListImagesResponse);

  rpc CreateVolume(CreateVolumeRequest) returns (CreateVolumeResponse);
  rpc ListVolumes(ListVolumesRequest) returns (ListVolumesResponse);
  rpc RemoveVolume(RemoveVolumeRequest) returns (google.protobuf.Empty);

  rpc CreateServiceContainer(CreateServiceContainerRequest) returns (CreateContainerResponse);
  rpc InspectServiceContainer(InspectContainerRequest) returns (ServiceContainer);
  rpc ListServiceContainers(ListServiceContainersRequest) returns (ListServiceContainersResponse);
  rpc RemoveServiceContainer(RemoveContainerRequest) returns (google.protobuf.Empty);
}

message CreateContainerRequest {
  // JSON serialised container.Config.
  bytes config = 1;
  // JSON serialised container.HostConfig.
  bytes host_config = 2;
  // JSON serialised network.NetworkingConfig.
  bytes network_config = 3;
  // JSON serialised ocispec.Platform.
  bytes platform = 4;
  string name = 5;
}

message CreateContainerResponse {
  // JSON serialised container.CreateResponse.
  bytes response = 1;
}

message InspectContainerRequest {
  string id = 1;
}

message InspectContainerResponse {
  // JSON serialised container.InspectResponse.
  bytes response = 1;
}

message StartContainerRequest {
  string id = 1;
  // JSON serialised container.StartOptions.
  bytes options = 2;
}

message StopContainerRequest {
  string id = 1;
  // JSON serialised container.StopOptions.
  bytes options = 2;
}

message ListContainersRequest {
  // JSON serialised container.ListOptions.
  bytes options = 1;
}

message ListContainersResponse {
  // Must contain only one repeated messages field to allow broadcasting ListContainers requests to multiple machines.
  repeated MachineContainers messages = 1;
}

message MachineContainers {
  Metadata metadata = 1;
  // JSON serialised []container.InspectResponse.
  bytes containers = 2;
}

message RemoveContainerRequest {
  string id = 1;
  // JSON serialised container.RemoveOptions.
  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 PullImageRequest {
  string image = 1;
  // JSON serialised image.PullOptions.
  bytes options = 2;
}

message JSONMessage {
  // JSON serialised jsonmessage.JSONMessage.
  bytes message = 1;
}

message InspectImageRequest {
  string id = 1;
}

message InspectImageResponse {
  // Must contain only one repeated messages field to allow broadcasting InspectImage requests to multiple machines.
  repeated Image messages = 1;
}

message Image {
  Metadata metadata = 1;
  // JSON serialised image.InspectResponse.
  bytes image = 2;
}

message InspectRemoteImageRequest {
  string id = 1;
}

message InspectRemoteImageResponse {
  // Must contain only one repeated messages field to allow broadcasting InspectRemoteImage requests to multiple machines.
  repeated RemoteImage messages = 1;
}

message RemoteImage {
  Metadata metadata = 1;
  // Image reference in the canonical form with the digest.
  string reference = 2;
  // Raw JSON manifest from the registry.
  bytes manifest = 3;
}

message ListImagesRequest {
  // JSON serialised image.ListOptions.
  bytes options = 1;
}

message ListImagesResponse {
  // Must contain only one repeated messages field to allow broadcasting ListImages requests to multiple machines.
  repeated MachineImages messages = 1;
}

message MachineImages {
  Metadata metadata = 1;
  // JSON serialised []image.Summary.
  bytes images = 2;
  // True if Docker uses the containerd image store, false if it uses its internal image store.
  bool containerd_store = 3;
}

message CreateVolumeRequest {
  // JSON serialised volume.CreateOptions.
  bytes options = 1;
}

message CreateVolumeResponse {
  // JSON serialised volume.Volume.
  bytes volume = 1;
}

message ListVolumesRequest {
  // JSON serialised volume.ListOptions.
  bytes options = 1;
}

message ListVolumesResponse {
  // Must contain only one repeated messages field to allow broadcasting ListVolumes requests to multiple machines.
  repeated MachineVolumes messages = 1;
}

message MachineVolumes {
  Metadata metadata = 1;
  // JSON serialised volume.ListResponse.
  bytes response = 2;
}

message RemoveVolumeRequest {
  string id = 1;
  bool force = 2;
}

message CreateServiceContainerRequest {
  string service_id = 1;
  // JSON serialised api.ServiceSpec.
  bytes service_spec = 2;
  string container_name = 3;

  // ContainerType specifies the purpose of the container being created.
  enum ContainerType {
    // SERVICE is the default type for long-running service containers.
    SERVICE = 0;
    // PRE_DEPLOY is a one-shot container for a pre-deploy hook to run before service deployment.
    PRE_DEPLOY = 1;
  }
  ContainerType container_type = 4;
}

message ServiceContainer {
  // JSON serialised container.InspectResponse.
  bytes container = 1;
  // JSON serialised api.ServiceSpec.
  bytes service_spec = 2;
}

message ListServiceContainersRequest {
  string service_id = 1;
  // JSON serialised container.ListOptions.
  bytes options = 2;
}

message ListServiceContainersResponse {
  // Must contain only one repeated messages field to allow broadcasting ListServiceContainers requests
  // to multiple machines.
  repeated MachineServiceContainers messages = 1;
}

message MachineServiceContainers {
  Metadata metadata = 1;
  repeated ServiceContainer containers = 2;
  // One-shot containers for deployment hooks (e.g. pre-deploy).
  repeated ServiceContainer hook_containers = 3;
}
