169 lines
3.2 KiB
Go
169 lines
3.2 KiB
Go
|
package buildkitd
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"os/exec"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/docker/distribution/reference"
|
||
|
"github.com/rs/zerolog/log"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
image = "moby/buildkit"
|
||
|
version = "v0.8.2"
|
||
|
imageVersion = image + ":" + version
|
||
|
containerName = "dagger-buildkitd"
|
||
|
)
|
||
|
|
||
|
func Start(ctx context.Context) (string, error) {
|
||
|
lg := log.Ctx(ctx)
|
||
|
|
||
|
// Attempt to detect the current buildkit version
|
||
|
currentVersion, err := getBuildkitVersion(ctx)
|
||
|
if err != nil {
|
||
|
// If that failed, it might either be because buildkitd is not running
|
||
|
// or because the docker CLI is out of service.
|
||
|
if err := checkDocker(ctx); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
currentVersion = ""
|
||
|
lg.Debug().Msg("no buildkit daemon detected")
|
||
|
} else {
|
||
|
lg.Debug().Str("version", currentVersion).Msg("detected buildkit version")
|
||
|
}
|
||
|
|
||
|
if currentVersion != version {
|
||
|
if currentVersion != "" {
|
||
|
lg.
|
||
|
Info().
|
||
|
Str("version", version).
|
||
|
Msg("upgrading buildkit")
|
||
|
if err := remvoveBuildkit(ctx); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
} else {
|
||
|
lg.
|
||
|
Info().
|
||
|
Str("version", version).
|
||
|
Msg("starting buildkit")
|
||
|
}
|
||
|
if err := startBuildkit(ctx); err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fmt.Sprintf("docker-container://%s", containerName), nil
|
||
|
}
|
||
|
|
||
|
// ensure the docker CLI is available and properly set up (e.g. permissions to
|
||
|
// communicate with the daemon, etc)
|
||
|
func checkDocker(ctx context.Context) error {
|
||
|
cmd := exec.CommandContext(ctx, "docker", "info")
|
||
|
output, err := cmd.CombinedOutput()
|
||
|
if err != nil {
|
||
|
log.
|
||
|
Ctx(ctx).
|
||
|
Error().
|
||
|
Err(err).
|
||
|
Bytes("output", output).
|
||
|
Msg("failed to run docker")
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func startBuildkit(ctx context.Context) error {
|
||
|
lg := log.
|
||
|
Ctx(ctx).
|
||
|
With().
|
||
|
Str("version", version).
|
||
|
Logger()
|
||
|
|
||
|
lg.Debug().Msg("pulling buildkit image")
|
||
|
cmd := exec.CommandContext(ctx,
|
||
|
"docker",
|
||
|
"pull",
|
||
|
imageVersion,
|
||
|
)
|
||
|
output, err := cmd.CombinedOutput()
|
||
|
if err != nil {
|
||
|
lg.
|
||
|
Error().
|
||
|
Err(err).
|
||
|
Bytes("output", output).
|
||
|
Msg("failed to pull buildkit image")
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
cmd = exec.CommandContext(ctx,
|
||
|
"docker",
|
||
|
"run",
|
||
|
"-d",
|
||
|
"--restart", "always",
|
||
|
"--name", containerName,
|
||
|
"--privileged",
|
||
|
imageVersion,
|
||
|
)
|
||
|
output, err = cmd.CombinedOutput()
|
||
|
if err != nil {
|
||
|
log.
|
||
|
Ctx(ctx).
|
||
|
Error().
|
||
|
Err(err).
|
||
|
Bytes("output", output).
|
||
|
Msg("unable to start buildkitd")
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func remvoveBuildkit(ctx context.Context) error {
|
||
|
lg := log.
|
||
|
Ctx(ctx)
|
||
|
|
||
|
cmd := exec.CommandContext(ctx,
|
||
|
"docker",
|
||
|
"rm",
|
||
|
"-fv",
|
||
|
containerName,
|
||
|
)
|
||
|
output, err := cmd.CombinedOutput()
|
||
|
if err != nil {
|
||
|
lg.
|
||
|
Error().
|
||
|
Err(err).
|
||
|
Bytes("output", output).
|
||
|
Msg("failed to stop buildkit")
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func getBuildkitVersion(ctx context.Context) (string, error) {
|
||
|
cmd := exec.CommandContext(ctx,
|
||
|
"docker",
|
||
|
"inspect",
|
||
|
"--format",
|
||
|
"{{.Config.Image}}",
|
||
|
containerName,
|
||
|
)
|
||
|
output, err := cmd.CombinedOutput()
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
ref, err := reference.ParseNormalizedNamed(strings.TrimSpace(string(output)))
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
tag, ok := ref.(reference.Tagged)
|
||
|
if !ok {
|
||
|
return "", fmt.Errorf("failed to parse image: %s", output)
|
||
|
}
|
||
|
return tag.Tag(), nil
|
||
|
}
|