Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions internal/cmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ func newDeployCommand() *deployCommand {
deployCommand.cmd.Flags().DurationVar(&deployCommand.args.ServiceOptions.WriterAffinityTimeout, "writer-affinity-timeout", server.DefaultWriterAffinityTimeout, "Time after a write before read requests will be routed to readers")
deployCommand.cmd.Flags().BoolVar(&deployCommand.args.ServiceOptions.ReadTargetsAcceptWebsockets, "read-target-websockets", false, "Route WebSocket traffic to read targets, when available")

deployCommand.cmd.Flags().DurationVar(&deployCommand.args.ServiceOptions.IdleTimeout, "idle-timeout", 0, "Stop container after this duration of inactivity (0 to disable)")
deployCommand.cmd.Flags().DurationVar(&deployCommand.args.ServiceOptions.IdleWakeTimeout, "idle-wake-timeout", server.DefaultIdleWakeTimeout, "Max time to hold request while waking container")

deployCommand.cmd.Flags().DurationVar(&deployCommand.args.TargetOptions.ResponseTimeout, "target-timeout", server.DefaultTargetTimeout, "Maximum time to wait for the target server to respond when serving requests")

deployCommand.cmd.Flags().BoolVar(&deployCommand.args.TargetOptions.BufferRequests, "buffer-requests", false, "Buffer requests before forwarding to target")
Expand Down
3 changes: 2 additions & 1 deletion internal/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ func newRunCommand() *runCommand {
runCommand.cmd.Flags().IntVar(&globalConfig.HttpsPort, "https-port", getEnvInt("HTTPS_PORT", server.DefaultHttpsPort), "Port to serve HTTPS traffic on")
runCommand.cmd.Flags().IntVar(&globalConfig.MetricsPort, "metrics-port", getEnvInt("METRICS_PORT", 0), "Publish metrics on the specified port (default zero to disable)")
runCommand.cmd.Flags().BoolVar(&globalConfig.HTTP3Enabled, "http3", false, "Enable HTTP/3")
runCommand.cmd.Flags().StringVar(&globalConfig.DockerSocketPath, "docker-socket", getEnvString("DOCKER_SOCKET", server.DefaultDockerSocketPath), "Path to Docker socket")

return runCommand
}

func (c *runCommand) run(cmd *cobra.Command, args []string) error {
c.setLogger()

router := server.NewRouter(globalConfig.StatePath())
router := server.NewRouter(globalConfig.StatePath(), globalConfig.DockerSocketPath)
router.RestoreLastSavedState()

s := server.NewServer(&globalConfig, router)
Expand Down
2 changes: 2 additions & 0 deletions internal/server/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
const (
DefaultHttpPort = 80
DefaultHttpsPort = 443
DefaultDockerSocketPath = "/var/run/docker.sock"
)

type Config struct {
Expand All @@ -20,6 +21,7 @@ type Config struct {
HTTP3Enabled bool

AlternateConfigDir string
DockerSocketPath string
}

func (c Config) SocketPath() string {
Expand Down
64 changes: 64 additions & 0 deletions internal/server/docker_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package server

import (
"context"
"fmt"
"net"
"net/http"
)

type DockerClient struct {
httpClient *http.Client
}

func NewDockerClient(socketPath string) *DockerClient {
return &DockerClient{
httpClient: &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return (&net.Dialer{}).DialContext(ctx, "unix", socketPath)
},
},
},
}
}

func (c *DockerClient) StopContainer(ctx context.Context, name string) error {
url := fmt.Sprintf("http://localhost/v1.41/containers/%s/stop", name)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, nil)
if err != nil {
return err
}

resp, err := c.httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusNotModified {
return fmt.Errorf("unexpected status code from docker stop: %d", resp.StatusCode)
}

return nil
}

func (c *DockerClient) StartContainer(ctx context.Context, name string) error {
url := fmt.Sprintf("http://localhost/v1.41/containers/%s/start", name)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, nil)
if err != nil {
return err
}

resp, err := c.httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusNotModified {
return fmt.Errorf("unexpected status code from docker start: %d", resp.StatusCode)
}

return nil
}
44 changes: 44 additions & 0 deletions internal/server/docker_client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package server

import (
"context"
"net"
"net/http"
"net/http/httptest"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestDockerClient_StopStart(t *testing.T) {
stopCalled := false
startCalled := false

server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/v1.41/containers/test-container/stop" {
stopCalled = true
w.WriteHeader(http.StatusNoContent)
} else if r.URL.Path == "/v1.41/containers/test-container/start" {
startCalled = true
w.WriteHeader(http.StatusNoContent)
}
}))

socketPath := t.TempDir() + "/docker.sock"
l, err := net.Listen("unix", socketPath)
require.NoError(t, err)
server.Listener = l
server.Start()
defer server.Close()

client := NewDockerClient(socketPath)

err = client.StopContainer(context.Background(), "test-container")
assert.NoError(t, err)
assert.True(t, stopCalled)

err = client.StartContainer(context.Background(), "test-container")
assert.NoError(t, err)
assert.True(t, startCalled)
}
Loading
Loading