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 { ContainerClient DNSClient ImageClient MachineClient ServiceClient VolumeClient } type ContainerClient interface { CreateContainer( ctx context.Context, serviceID string, spec ServiceSpec, machineID string, ) (container.CreateResponse, error) InspectContainer(ctx context.Context, serviceNameOrID, containerNameOrID string) (MachineServiceContainer, error) RemoveContainer(ctx context.Context, serviceNameOrID, containerNameOrID string, opts container.RemoveOptions) error StartContainer(ctx context.Context, serviceNameOrID, containerNameOrID string) error StopContainer(ctx context.Context, serviceNameOrID, containerNameOrID string, opts container.StopOptions) error } type DNSClient interface { GetDomain(ctx context.Context) (string, error) } type ImageClient interface { InspectImage(ctx context.Context, id string) ([]MachineImage, error) InspectRemoteImage(ctx context.Context, id string) ([]MachineRemoteImage, error) } type MachineClient interface { InspectMachine(ctx context.Context, id string) (*pb.MachineMember, error) ListMachines(ctx context.Context, filter *MachineFilter) (MachineMembersList, error) UpdateMachine(ctx context.Context, req *pb.UpdateMachineRequest) (*pb.MachineInfo, error) RenameMachine(ctx context.Context, nameOrID, newName string) (*pb.MachineInfo, error) } type ServiceClient interface { RunService(ctx context.Context, spec ServiceSpec) (RunServiceResponse, error) InspectService(ctx context.Context, id string) (Service, error) RemoveService(ctx context.Context, id string) error } type VolumeClient interface { CreateVolume(ctx context.Context, machineNameOrID string, opts volume.CreateOptions) (MachineVolume, error) 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 }