Skip to content
Merged
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
78 changes: 65 additions & 13 deletions internal/service/docker_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ package service

import (
"context"
"errors"
"fmt"
"os"
"time"

"github.com/cenkalti/backoff/v5"
"github.com/steveiliop56/ding"
"github.com/tinyauthapp/tinyauth/internal/model"
"github.com/tinyauthapp/tinyauth/internal/utils/decoders"
Expand All @@ -14,6 +18,10 @@ import (
"github.com/docker/docker/client"
)

var (
ErrPingFailed = fmt.Errorf("failed to ping docker")
)

type DockerService struct {
log *logger.Logger
client *client.Client
Expand All @@ -31,24 +39,52 @@ type DockerServiceInput struct {
}

func NewDockerService(i DockerServiceInput) (*DockerService, error) {
client, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
return nil, err
service := &DockerService{
log: i.Log,
context: i.Ctx,
}

client.NegotiateAPIVersion(i.Ctx)
service.log.App.Debug().Msg("Attempting to connect to Docker")

_, err = client.Ping(i.Ctx)
if os.Getenv("DOCKER_HOST") == "" {
cli, err := service.connect()
if err != nil {
if errors.Is(err, ErrPingFailed) {
service.log.App.Debug().Msg("Docker not connected")
return nil, nil
}
return nil, fmt.Errorf("failed to connect to docker: %w", err)
}
service.client = cli
} else {
exp := backoff.NewExponentialBackOff()
exp.InitialInterval = 3 * time.Second
exp.RandomizationFactor = 0.1
exp.Multiplier = 1.5
exp.Reset()

operation := func() (*client.Client, error) {
if service.client != nil {
service.client.Close()
}
cli, err := service.connect()
if err != nil {
return nil, err
}
return cli, nil
}

if err != nil {
i.Log.App.Debug().Err(err).Msg("Docker not connected")
return nil, nil
}
cli, err := backoff.Retry(service.context, operation, backoff.WithBackOff(exp), backoff.WithMaxTries(3))

service := &DockerService{
log: i.Log,
client: client,
context: i.Ctx,
if err != nil {
if errors.Is(err, ErrPingFailed) {
service.log.App.Debug().Msg("Docker not connected after retrying")
return nil, nil
}
return nil, fmt.Errorf("failed to connect to docker after retrying: %w", err)
}

service.client = cli
}

service.isConnected = true
Expand All @@ -59,6 +95,22 @@ func NewDockerService(i DockerServiceInput) (*DockerService, error) {
return service, nil
}

func (docker *DockerService) connect() (*client.Client, error) {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())

if err != nil {
return nil, err
}

_, err = cli.Ping(docker.context)

if err != nil {
return nil, ErrPingFailed
}

return cli, nil
}

func (docker *DockerService) getContainers() ([]container.Summary, error) {
return docker.client.ContainerList(docker.context, container.ListOptions{})
}
Expand Down