mirror of
https://github.com/luxfi/cli.git
synced 2026-10-30 17:01:20 +00:00
119 lines
4.1 KiB
Go
119 lines
4.1 KiB
Go
// Copyright (C) 2022-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package docker
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/luxfi/cli/pkg/utils"
|
|
"github.com/luxfi/cli/pkg/ux"
|
|
"github.com/luxfi/constants"
|
|
"github.com/luxfi/sdk/models"
|
|
)
|
|
|
|
// PullDockerImage pulls a docker image on a remote host.
|
|
func PullDockerImage(host *models.Host, image string) error {
|
|
ux.Logger.Info("Pulling docker image %s on %s", image, host.NodeID)
|
|
_, err := host.Command("docker pull "+image, nil, constants.SSHLongRunningScriptTimeout)
|
|
return err
|
|
}
|
|
|
|
// LocalImageExists checks if a docker image exists on a remote host.
|
|
func LocalImageExists(host *models.Host, image string) (bool, error) {
|
|
output, err := host.Command("docker images --format '{{.Repository}}:{{.Tag}}'", nil, constants.SSHLongRunningScriptTimeout)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
for _, localImage := range parseDockerImageListOutput(output) {
|
|
if localImage == image {
|
|
return true, nil
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
// parseDockerImageListOutput parses the output of a docker images command.
|
|
func parseDockerImageListOutput(output []byte) []string {
|
|
return strings.Split(string(output), "\n")
|
|
}
|
|
|
|
func parseRemoteGoModFile(path string, host *models.Host) (string, error) {
|
|
goMod := filepath.Join(path, "go.mod")
|
|
// download and parse go.mod
|
|
tmpFile, err := os.CreateTemp("", "go-mod-*.txt")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer func() { _ = os.Remove(tmpFile.Name()) }()
|
|
if err := host.Download(goMod, tmpFile.Name(), constants.SSHFileOpsTimeout); err != nil {
|
|
return "", err
|
|
}
|
|
return utils.ReadGoVersion(tmpFile.Name())
|
|
}
|
|
|
|
// BuildDockerImage builds a docker image on a remote host.
|
|
func BuildDockerImage(host *models.Host, image string, path string, dockerfile string) error {
|
|
goVersion, err := parseRemoteGoModFile(path, host)
|
|
if err != nil {
|
|
// fall back to default
|
|
ux.Logger.Info("failed to read go version from go.mod: %s. falling back to default", err)
|
|
goVersion = constants.BuildEnvGolangVersion
|
|
}
|
|
cmd := fmt.Sprintf("cd %s && docker build -q --build-arg GO_VERSION=%s -t %s -f %s .", path, goVersion, image, dockerfile)
|
|
_, err = host.Command(cmd, nil, constants.SSHLongRunningScriptTimeout)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to build docker image %s: %w", image, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// BuildDockerImageFromGitRepo builds a docker image from a git repo on a remote host.
|
|
func BuildDockerImageFromGitRepo(host *models.Host, image string, gitRepo string, commit string) error {
|
|
if commit == "" {
|
|
commit = "HEAD"
|
|
}
|
|
tmpDir, err := host.CreateTempDir()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
if err := host.Remove(tmpDir, true); err != nil {
|
|
ux.Logger.Error("Error removing temporary directory %s: %s", tmpDir, err)
|
|
}
|
|
}()
|
|
// clone the repo and checkout commit
|
|
if _, err := host.Command(fmt.Sprintf("git clone %s %s && cd %s && git checkout %s", gitRepo, tmpDir, tmpDir, commit), nil, constants.SSHLongRunningScriptTimeout); err != nil {
|
|
return err
|
|
}
|
|
// build the image
|
|
if err := BuildDockerImage(host, image, tmpDir, "Dockerfile"); err != nil {
|
|
return err
|
|
}
|
|
ux.Logger.Info("Docker image %s built from %s using %s commit/branch/tag", image, gitRepo, commit)
|
|
return nil
|
|
}
|
|
|
|
// PrepareDockerImageWithRepo ensures a docker image is available on the host,
|
|
// pulling or building from the git repo if necessary.
|
|
func PrepareDockerImageWithRepo(host *models.Host, image string, gitRepo string, commit string) error {
|
|
localImageExists, _ := LocalImageExists(host, image)
|
|
if localImageExists {
|
|
ux.Logger.Info("Docker image %s is FOUND on %s", image, host.NodeID)
|
|
return nil
|
|
}
|
|
ux.Logger.Info("Docker image %s not found on %s, pulling it", image, host.NodeID)
|
|
if err := PullDockerImage(host, image); err != nil {
|
|
ux.Logger.Info("Docker image %s not found on %s, building it from %s using %s commit/branch/tag", image, host.NodeID, gitRepo, commit)
|
|
if err := BuildDockerImageFromGitRepo(host, image, gitRepo, commit); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
ux.Logger.Info("Docker image %s is READY on %s", image, host.NodeID)
|
|
return nil
|
|
}
|