add Docker gRPC service to create and start a Docker container on machine

This commit is contained in:
Pavel Sviderski
2024-11-01 15:04:06 +10:00
parent 5bf3cba2d6
commit 5cb765d286
5 changed files with 705 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
package docker
import (
"context"
"encoding/json"
"fmt"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"google.golang.org/grpc"
"uncloud/internal/machine/api/pb"
)
// Client is a gRPC client for the Docker service that provides a similar interface to the Docker HTTP client.
type Client struct {
conn *grpc.ClientConn
grpcClient pb.DockerClient
}
// NewClient creates a new Docker gRPC client with the provided gRPC connection.
func NewClient(conn *grpc.ClientConn) *Client {
return &Client{
conn: conn,
grpcClient: pb.NewDockerClient(conn),
}
}
// Close closes the gRPC connection.
func (c *Client) Close() error {
return c.conn.Close()
}
// CreateContainer creates a new container based on the given configuration.
func (c *Client) CreateContainer(
ctx context.Context,
config *container.Config,
hostConfig *container.HostConfig,
networkingConfig *network.NetworkingConfig,
platform *ocispec.Platform,
name string,
) (container.CreateResponse, error) {
var resp container.CreateResponse
// Serialize configs to JSON.
configBytes, err := json.Marshal(config)
if err != nil {
return resp, fmt.Errorf("marshal container config: %w", err)
}
hostConfigBytes, err := json.Marshal(hostConfig)
if err != nil {
return resp, fmt.Errorf("marshal host config: %w", err)
}
networkingConfigBytes, err := json.Marshal(networkingConfig)
if err != nil {
return resp, fmt.Errorf("marshal networking config: %w", err)
}
platformBytes, err := json.Marshal(platform)
if err != nil {
return resp, fmt.Errorf("marshal platform: %w", err)
}
grpcResp, err := c.grpcClient.CreateContainer(ctx, &pb.CreateContainerRequest{
Config: configBytes,
HostConfig: hostConfigBytes,
NetworkConfig: networkingConfigBytes,
Platform: platformBytes,
Name: name,
})
if err != nil {
return resp, err
}
if err = json.Unmarshal(grpcResp.Response, &resp); err != nil {
return resp, fmt.Errorf("unmarshal gRPC response: %w", err)
}
return resp, nil
}
// StartContainer starts a container with the given ID and options.
func (c *Client) StartContainer(ctx context.Context, id string, options container.StartOptions) error {
optionsBytes, err := json.Marshal(options)
if err != nil {
return fmt.Errorf("marshal start options: %w", err)
}
_, err = c.grpcClient.StartContainer(ctx, &pb.StartContainerRequest{
Id: id,
Options: optionsBytes,
})
return err
}