@@ -25,6 +25,8 @@ import (
25
25
"io/ioutil"
26
26
"os"
27
27
"strings"
28
+ "sync"
29
+ "sync/atomic"
28
30
29
31
"github.com/docker/docker/api/types"
30
32
"github.com/docker/docker/api/types/registry"
@@ -44,18 +46,20 @@ const (
44
46
type FakeAPIClient struct {
45
47
client.CommonAPIClient
46
48
47
- tagToImageID map [string ]string
48
49
ErrImageBuild bool
49
50
ErrImageInspect bool
50
51
ErrImagePush bool
51
52
ErrImagePull bool
52
53
ErrStream bool
53
54
ErrVersion bool
54
55
55
- nextImageID int
56
- Pushed map [string ]string
57
- Pulled []string
58
- Built []types.ImageBuildOptions
56
+ nextImageID int32
57
+ tagToImageID sync.Map // map[string]string
58
+ pushed sync.Map // map[string]string
59
+ pulled sync.Map // map[string]string
60
+
61
+ mux sync.Mutex
62
+ Built []types.ImageBuildOptions
59
63
}
60
64
61
65
func (f * FakeAPIClient ) ServerVersion (ctx context.Context ) (types.Version , error ) {
@@ -66,18 +70,35 @@ func (f *FakeAPIClient) ServerVersion(ctx context.Context) (types.Version, error
66
70
}
67
71
68
72
func (f * FakeAPIClient ) Add (tag , imageID string ) * FakeAPIClient {
69
- if f .tagToImageID == nil {
70
- f .tagToImageID = make (map [string ]string )
71
- }
72
-
73
- f .tagToImageID [imageID ] = imageID
74
- f .tagToImageID [tag ] = imageID
73
+ f .tagToImageID .Store (imageID , imageID )
74
+ f .tagToImageID .Store (tag , imageID )
75
75
if ! strings .Contains (tag , ":" ) {
76
- f .tagToImageID [ tag + ":latest" ] = imageID
76
+ f .tagToImageID . Store ( tag + ":latest" , imageID )
77
77
}
78
78
return f
79
79
}
80
80
81
+ func (f * FakeAPIClient ) Pulled () []string {
82
+ var p []string
83
+ f .pulled .Range (func (ref , _ interface {}) bool {
84
+ p = append (p , ref .(string ))
85
+ return true
86
+ })
87
+ return p
88
+ }
89
+
90
+ func (f * FakeAPIClient ) Pushed () map [string ]string {
91
+ p := make (map [string ]string )
92
+ f .pushed .Range (func (ref , id interface {}) bool {
93
+ p [ref .(string )] = id .(string )
94
+ return true
95
+ })
96
+ if len (p ) == 0 {
97
+ return nil
98
+ }
99
+ return p
100
+ }
101
+
81
102
type notFoundError struct {
82
103
error
83
104
}
@@ -103,49 +124,69 @@ func (f *FakeAPIClient) ImageBuild(_ context.Context, _ io.Reader, options types
103
124
return types.ImageBuildResponse {}, fmt .Errorf ("" )
104
125
}
105
126
106
- f .nextImageID ++
107
- imageID := fmt .Sprintf ("sha256:%d" , f . nextImageID )
127
+ next := atomic . AddInt32 ( & f .nextImageID , 1 )
128
+ imageID := fmt .Sprintf ("sha256:%d" , next )
108
129
109
130
for _ , tag := range options .Tags {
110
131
f .Add (tag , imageID )
111
132
}
112
133
134
+ f .mux .Lock ()
113
135
f .Built = append (f .Built , options )
136
+ f .mux .Unlock ()
114
137
115
138
return types.ImageBuildResponse {
116
139
Body : f .body (imageID ),
117
140
}, nil
118
141
}
119
142
120
- func (f * FakeAPIClient ) ImageInspectWithRaw (_ context.Context , ref string ) (types.ImageInspect , []byte , error ) {
143
+ func (f * FakeAPIClient ) ImageInspectWithRaw (_ context.Context , refOrID string ) (types.ImageInspect , []byte , error ) {
121
144
if f .ErrImageInspect {
122
145
return types.ImageInspect {}, nil , fmt .Errorf ("" )
123
146
}
124
147
125
- for tag , imageID := range f .tagToImageID {
126
- if tag == ref || imageID == ref {
127
- rawConfig := []byte (fmt .Sprintf (`{"Config":{"Image":"%s"}}` , imageID ))
148
+ ref , imageID , err := f .findImageID (refOrID )
149
+ if err != nil {
150
+ return types.ImageInspect {}, nil , err
151
+ }
128
152
129
- var repoDigests []string
130
- if digest , found := f .Pushed [ref ]; found {
131
- repoDigests = append (repoDigests , ref + "@" + digest )
132
- }
153
+ rawConfig := []byte (fmt .Sprintf (`{"Config":{"Image":"%s"}}` , imageID ))
133
154
134
- return types.ImageInspect {
135
- ID : imageID ,
136
- RepoDigests : repoDigests ,
137
- }, rawConfig , nil
138
- }
155
+ var repoDigests []string
156
+ if digest , found := f .pushed .Load (ref ); found {
157
+ repoDigests = append (repoDigests , ref + "@" + digest .(string ))
139
158
}
140
159
141
- return types.ImageInspect {}, nil , & notFoundError {}
160
+ return types.ImageInspect {
161
+ ID : imageID ,
162
+ RepoDigests : repoDigests ,
163
+ }, rawConfig , nil
164
+ }
165
+
166
+ func (f * FakeAPIClient ) findImageID (refOrID string ) (string , string , error ) {
167
+ if id , found := f .tagToImageID .Load (refOrID ); found {
168
+ return refOrID , id .(string ), nil
169
+ }
170
+ var ref , id string
171
+ f .tagToImageID .Range (func (r , i interface {}) bool {
172
+ if r == refOrID || i == refOrID {
173
+ ref = r .(string )
174
+ id = i .(string )
175
+ return false
176
+ }
177
+ return true
178
+ })
179
+ if ref == "" {
180
+ return "" , "" , & notFoundError {}
181
+ }
182
+ return ref , id , nil
142
183
}
143
184
144
185
func (f * FakeAPIClient ) DistributionInspect (ctx context.Context , ref , encodedRegistryAuth string ) (registry.DistributionInspect , error ) {
145
- if sha , found := f .Pushed [ ref ] ; found {
186
+ if sha , found := f .pushed . Load ( ref ) ; found {
146
187
return registry.DistributionInspect {
147
188
Descriptor : v1.Descriptor {
148
- Digest : digest .Digest (sha ),
189
+ Digest : digest .Digest (sha .( string ) ),
149
190
},
150
191
}, nil
151
192
}
@@ -154,12 +195,12 @@ func (f *FakeAPIClient) DistributionInspect(ctx context.Context, ref, encodedReg
154
195
}
155
196
156
197
func (f * FakeAPIClient ) ImageTag (_ context.Context , image , ref string ) error {
157
- imageID , ok := f .tagToImageID [ image ]
198
+ imageID , ok := f .tagToImageID . Load ( image )
158
199
if ! ok {
159
200
return fmt .Errorf ("image %s not found" , image )
160
201
}
161
202
162
- f .Add (ref , imageID )
203
+ f .Add (ref , imageID .( string ) )
163
204
return nil
164
205
}
165
206
@@ -168,22 +209,24 @@ func (f *FakeAPIClient) ImagePush(_ context.Context, ref string, _ types.ImagePu
168
209
return nil , fmt .Errorf ("" )
169
210
}
170
211
212
+ // use the digest if previously pushed
213
+ imageID , found := f .tagToImageID .Load (ref )
214
+ if ! found {
215
+ imageID = ""
216
+ }
171
217
sha256Digester := sha256 .New ()
172
- if _ , err := sha256Digester .Write ([]byte (f . tagToImageID [ ref ] )); err != nil {
218
+ if _ , err := sha256Digester .Write ([]byte (imageID .( string ) )); err != nil {
173
219
return nil , err
174
220
}
175
221
176
222
digest := "sha256:" + fmt .Sprintf ("%x" , sha256Digester .Sum (nil ))[0 :64 ]
177
- if f .Pushed == nil {
178
- f .Pushed = make (map [string ]string )
179
- }
180
- f .Pushed [ref ] = digest
181
223
224
+ f .pushed .Store (ref , digest )
182
225
return f .body (digest ), nil
183
226
}
184
227
185
228
func (f * FakeAPIClient ) ImagePull (_ context.Context , ref string , _ types.ImagePullOptions ) (io.ReadCloser , error ) {
186
- f .Pulled = append ( f . Pulled , ref )
229
+ f .pulled . Store ( ref , ref )
187
230
if f .ErrImagePull {
188
231
return nil , fmt .Errorf ("" )
189
232
}
@@ -203,8 +246,8 @@ func (f *FakeAPIClient) ImageLoad(ctx context.Context, input io.Reader, quiet bo
203
246
return types.ImageLoadResponse {}, fmt .Errorf ("reading tar" )
204
247
}
205
248
206
- f .nextImageID ++
207
- imageID := fmt .Sprintf ("sha256:%d" , f . nextImageID )
249
+ next := atomic . AddInt32 ( & f .nextImageID , 1 )
250
+ imageID := fmt .Sprintf ("sha256:%d" , next )
208
251
f .Add (ref , imageID )
209
252
210
253
return types.ImageLoadResponse {
0 commit comments