diff options
author | Daniel Baumann <daniel@debian.org> | 2024-10-20 23:07:42 +0200 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-11-09 15:38:42 +0100 |
commit | 714c83b2736d7e308bc33c49057952490eb98be2 (patch) | |
tree | 1d9ba7035798368569cd49056f4d596efc908cd8 /pkg/container/docker_pull.go | |
parent | Initial commit. (diff) | |
download | forgejo-act-714c83b2736d7e308bc33c49057952490eb98be2.tar.xz forgejo-act-714c83b2736d7e308bc33c49057952490eb98be2.zip |
Adding upstream version 1.21.4.HEADupstream/1.21.4upstreamdebian
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'pkg/container/docker_pull.go')
-rw-r--r-- | pkg/container/docker_pull.go | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/pkg/container/docker_pull.go b/pkg/container/docker_pull.go new file mode 100644 index 0000000..7c94c10 --- /dev/null +++ b/pkg/container/docker_pull.go @@ -0,0 +1,126 @@ +//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows || netbsd)) + +package container + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "strings" + + "github.com/docker/distribution/reference" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/registry" + + "github.com/nektos/act/pkg/common" +) + +// NewDockerPullExecutor function to create a run executor for the container +func NewDockerPullExecutor(input NewDockerPullExecutorInput) common.Executor { + return func(ctx context.Context) error { + logger := common.Logger(ctx) + logger.Debugf("%sdocker pull %v", logPrefix, input.Image) + + if common.Dryrun(ctx) { + return nil + } + + pull := input.ForcePull + if !pull { + imageExists, err := ImageExistsLocally(ctx, input.Image, input.Platform) + logger.Debugf("Image exists? %v", imageExists) + if err != nil { + return fmt.Errorf("unable to determine if image already exists for image '%s' (%s): %w", input.Image, input.Platform, err) + } + + if !imageExists { + pull = true + } + } + + if !pull { + return nil + } + + imageRef := cleanImage(ctx, input.Image) + logger.Debugf("pulling image '%v' (%s)", imageRef, input.Platform) + + cli, err := GetDockerClient(ctx) + if err != nil { + return err + } + defer cli.Close() + + imagePullOptions, err := getImagePullOptions(ctx, input) + if err != nil { + return err + } + + reader, err := cli.ImagePull(ctx, imageRef, imagePullOptions) + + _ = logDockerResponse(logger, reader, err != nil) + if err != nil { + if imagePullOptions.RegistryAuth != "" && strings.Contains(err.Error(), "unauthorized") { + logger.Errorf("pulling image '%v' (%s) failed with credentials %s retrying without them, please check for stale docker config files", imageRef, input.Platform, err.Error()) + imagePullOptions.RegistryAuth = "" + reader, err = cli.ImagePull(ctx, imageRef, imagePullOptions) + + _ = logDockerResponse(logger, reader, err != nil) + } + return err + } + return nil + } +} + +func getImagePullOptions(ctx context.Context, input NewDockerPullExecutorInput) (types.ImagePullOptions, error) { + imagePullOptions := types.ImagePullOptions{ + Platform: input.Platform, + } + logger := common.Logger(ctx) + + if input.Username != "" && input.Password != "" { + logger.Debugf("using authentication for docker pull") + + authConfig := registry.AuthConfig{ + Username: input.Username, + Password: input.Password, + } + + encodedJSON, err := json.Marshal(authConfig) + if err != nil { + return imagePullOptions, err + } + + imagePullOptions.RegistryAuth = base64.URLEncoding.EncodeToString(encodedJSON) + } else { + authConfig, err := LoadDockerAuthConfig(ctx, input.Image) + if err != nil { + return imagePullOptions, err + } + if authConfig.Username == "" && authConfig.Password == "" { + return imagePullOptions, nil + } + logger.Info("using DockerAuthConfig authentication for docker pull") + + encodedJSON, err := json.Marshal(authConfig) + if err != nil { + return imagePullOptions, err + } + + imagePullOptions.RegistryAuth = base64.URLEncoding.EncodeToString(encodedJSON) + } + + return imagePullOptions, nil +} + +func cleanImage(ctx context.Context, image string) string { + ref, err := reference.ParseAnyReference(image) + if err != nil { + common.Logger(ctx).Error(err) + return "" + } + + return ref.String() +} |