2024-01-09 03:26:03 +08:00
//go:build !(WITHOUT_DOCKER || !(linux || darwin || windows || netbsd))
2023-01-11 06:08:57 +08:00
2019-01-13 12:45:25 +08:00
package container
import (
2020-02-07 14:17:58 +08:00
"context"
2021-05-06 00:37:17 +08:00
"encoding/base64"
"encoding/json"
2022-06-11 05:16:42 +08:00
"fmt"
2023-05-04 00:44:26 +08:00
"strings"
2019-01-13 12:45:25 +08:00
2021-11-14 03:35:45 +08:00
"github.com/docker/distribution/reference"
2019-01-13 12:45:25 +08:00
"github.com/docker/docker/api/types"
2023-07-11 12:55:53 +08:00
"github.com/docker/docker/api/types/registry"
2021-03-29 12:08:40 +08:00
"github.com/nektos/act/pkg/common"
2019-01-13 12:45:25 +08:00
)
// NewDockerPullExecutor function to create a run executor for the container
func NewDockerPullExecutor ( input NewDockerPullExecutorInput ) common . Executor {
2020-02-07 14:17:58 +08:00
return func ( ctx context . Context ) error {
logger := common . Logger ( ctx )
2020-02-24 07:01:25 +08:00
logger . Debugf ( "%sdocker pull %v" , logPrefix , input . Image )
2019-01-13 12:45:25 +08:00
2020-02-07 14:17:58 +08:00
if common . Dryrun ( ctx ) {
return nil
}
pull := input . ForcePull
if ! pull {
2021-03-29 12:08:40 +08:00
imageExists , err := ImageExistsLocally ( ctx , input . Image , input . Platform )
2022-06-17 23:55:21 +08:00
logger . Debugf ( "Image exists? %v" , imageExists )
2020-02-07 14:17:58 +08:00
if err != nil {
2022-06-11 05:16:42 +08:00
return fmt . Errorf ( "unable to determine if image already exists for image '%s' (%s): %w" , input . Image , input . Platform , err )
2020-02-07 14:17:58 +08:00
}
if ! imageExists {
pull = true
}
}
if ! pull {
2019-01-13 12:45:25 +08:00
return nil
}
2022-06-17 23:55:21 +08:00
imageRef := cleanImage ( ctx , input . Image )
2021-03-29 12:08:40 +08:00
logger . Debugf ( "pulling image '%v' (%s)" , imageRef , input . Platform )
2019-01-13 12:45:25 +08:00
2020-05-04 12:15:42 +08:00
cli , err := GetDockerClient ( ctx )
2019-01-13 12:45:25 +08:00
if err != nil {
return err
}
2021-10-25 00:50:43 +08:00
defer cli . Close ( )
2019-01-13 12:45:25 +08:00
2021-05-06 00:37:17 +08:00
imagePullOptions , err := getImagePullOptions ( ctx , input )
if err != nil {
return err
}
reader , err := cli . ImagePull ( ctx , imageRef , imagePullOptions )
2020-02-07 14:17:58 +08:00
_ = logDockerResponse ( logger , reader , err != nil )
2019-01-13 12:45:25 +08:00
if err != nil {
2023-05-04 00:44:26 +08:00
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 )
}
2019-01-13 12:45:25 +08:00
return err
}
return nil
}
}
2021-05-06 00:37:17 +08:00
func getImagePullOptions ( ctx context . Context , input NewDockerPullExecutorInput ) ( types . ImagePullOptions , error ) {
imagePullOptions := types . ImagePullOptions {
Platform : input . Platform ,
}
2023-05-04 00:44:26 +08:00
logger := common . Logger ( ctx )
2021-11-28 02:21:32 +08:00
2021-05-06 00:37:17 +08:00
if input . Username != "" && input . Password != "" {
logger . Debugf ( "using authentication for docker pull" )
2023-07-11 12:55:53 +08:00
authConfig := registry . AuthConfig {
2021-05-06 00:37:17 +08:00
Username : input . Username ,
Password : input . Password ,
}
encodedJSON , err := json . Marshal ( authConfig )
if err != nil {
return imagePullOptions , err
}
2021-11-28 02:21:32 +08:00
imagePullOptions . RegistryAuth = base64 . URLEncoding . EncodeToString ( encodedJSON )
} else {
2022-06-17 23:55:21 +08:00
authConfig , err := LoadDockerAuthConfig ( ctx , input . Image )
2021-11-28 02:21:32 +08:00
if err != nil {
return imagePullOptions , err
}
if authConfig . Username == "" && authConfig . Password == "" {
return imagePullOptions , nil
}
2023-05-04 00:44:26 +08:00
logger . Info ( "using DockerAuthConfig authentication for docker pull" )
2021-11-28 02:21:32 +08:00
encodedJSON , err := json . Marshal ( authConfig )
if err != nil {
return imagePullOptions , err
}
2021-05-06 00:37:17 +08:00
imagePullOptions . RegistryAuth = base64 . URLEncoding . EncodeToString ( encodedJSON )
}
return imagePullOptions , nil
}
2022-06-17 23:55:21 +08:00
func cleanImage ( ctx context . Context , image string ) string {
2021-11-14 03:35:45 +08:00
ref , err := reference . ParseAnyReference ( image )
if err != nil {
2022-06-17 23:55:21 +08:00
common . Logger ( ctx ) . Error ( err )
2021-11-14 03:35:45 +08:00
return ""
2019-01-13 12:45:25 +08:00
}
2021-11-14 03:35:45 +08:00
return ref . String ( )
2019-01-13 12:45:25 +08:00
}