@@ -2,16 +2,12 @@ package container
22
33import (
44 "context"
5+ "errors"
56 "fmt"
67
7- "github.com/containerd/errdefs"
8- "github.com/containerd/platforms"
9-
108 "github.com/docker/docker/api/types/container"
11- apiimage "github.com/docker/docker/api/types/image"
129 apinetwork "github.com/docker/docker/api/types/network"
1310 "github.com/docker/go-sdk/client"
14- "github.com/docker/go-sdk/image"
1511)
1612
1713// Run is a convenience function that creates a new container and starts it.
@@ -23,6 +19,17 @@ func Run(ctx context.Context, opts ...ContainerCustomizer) (*Container, error) {
2319 started : true ,
2420 }
2521
22+ // initialize the validate functions with the default ones
23+ def .validateFuncs = []func () error {
24+ func () error {
25+ if def .image == "" {
26+ return errors .New ("image is required" )
27+ }
28+ return nil
29+ },
30+ def .validateMounts ,
31+ }
32+
2633 for _ , opt := range opts {
2734 if err := opt .Customize (& def ); err != nil {
2835 return nil , fmt .Errorf ("customize: %w" , err )
@@ -51,54 +58,6 @@ func Run(ctx context.Context, opts ...ContainerCustomizer) (*Container, error) {
5158 DefaultLoggingHook ,
5259 }
5360
54- for _ , is := range def .imageSubstitutors {
55- modifiedTag , err := is .Substitute (def .image )
56- if err != nil {
57- return nil , fmt .Errorf ("failed to substitute image %s with %s: %w" , def .image , is .Description (), err )
58- }
59-
60- if modifiedTag != def .image {
61- def .dockerClient .Logger ().Info ("Replacing image" , "description" , is .Description (), "from" , def .image , "to" , modifiedTag )
62- def .image = modifiedTag
63- }
64- }
65-
66- var platform * platforms.Platform
67-
68- if def .imagePlatform != "" {
69- p , err := platforms .Parse (def .imagePlatform )
70- if err != nil {
71- return nil , fmt .Errorf ("invalid platform %s: %w" , def .imagePlatform , err )
72- }
73- platform = & p
74- }
75-
76- var shouldPullImage bool
77-
78- if def .alwaysPullImage {
79- shouldPullImage = true // If requested always attempt to pull image
80- } else {
81- img , err := def .dockerClient .ImageInspect (ctx , def .image )
82- if err != nil {
83- if ! errdefs .IsNotFound (err ) {
84- return nil , err
85- }
86- shouldPullImage = true
87- }
88- if platform != nil && (img .Architecture != platform .Architecture || img .Os != platform .OS ) {
89- shouldPullImage = true
90- }
91- }
92-
93- if shouldPullImage {
94- pullOpt := apiimage.PullOptions {
95- Platform : def .imagePlatform , // may be empty
96- }
97- if err := image .Pull (ctx , def .image , image .WithPullClient (def .dockerClient ), image .WithPullOptions (pullOpt )); err != nil {
98- return nil , err
99- }
100- }
101-
10261 def .labels [moduleLabel ] = Version ()
10362
10463 dockerInput := & container.Config {
@@ -131,7 +90,25 @@ func Run(ctx context.Context, opts ...ContainerCustomizer) (*Container, error) {
13190 return nil , err
13291 }
13392
134- resp , err := def .dockerClient .ContainerCreate (ctx , dockerInput , hostConfig , networkingConfig , platform , def .name )
93+ // Image substitution must be done after the creating hook has been called,
94+ // as the image could have been overridden in there.
95+ for _ , is := range def .imageSubstitutors {
96+ modifiedTag , err := is .Substitute (def .image )
97+ if err != nil {
98+ return nil , fmt .Errorf ("failed to substitute image %s with %s: %w" , def .image , is .Description (), err )
99+ }
100+
101+ if modifiedTag != def .image {
102+ def .dockerClient .Logger ().Info ("Replacing image" , "description" , is .Description (), "from" , def .image , "to" , modifiedTag )
103+ def .image = modifiedTag
104+ }
105+ }
106+
107+ // Update the image name in the docker input after the creating hook has been called,
108+ // as it could have been overridden in there.
109+ dockerInput .Image = def .image
110+
111+ resp , err := def .dockerClient .ContainerCreate (ctx , dockerInput , hostConfig , networkingConfig , def .platform , def .name )
135112 if err != nil {
136113 return nil , fmt .Errorf ("container create: %w" , err )
137114 }
0 commit comments