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