1
1
package etcd
2
2
3
3
import (
4
+ "k8s.io/apimachinery/pkg/api/errors"
4
5
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5
6
"k8s.io/apimachinery/pkg/runtime"
6
7
apirequest "k8s.io/apiserver/pkg/endpoints/request"
@@ -46,7 +47,8 @@ func NewREST(
46
47
subjectAccessReviewRegistry authorizationclient.SubjectAccessReviewInterface ,
47
48
limitVerifier imageadmission.LimitVerifier ,
48
49
registryWhitelister whitelist.RegistryWhitelister ,
49
- ) (* REST , * StatusREST , * InternalREST , error ) {
50
+ imageLayerIndex ImageLayerIndex ,
51
+ ) (* REST , * LayersREST , * StatusREST , * InternalREST , error ) {
50
52
store := registry.Store {
51
53
NewFunc : func () runtime.Object { return & imageapi.ImageStream {} },
52
54
NewListFunc : func () runtime.Object { return & imageapi.ImageStreamList {} },
@@ -71,9 +73,11 @@ func NewREST(
71
73
AttrFunc : storage .AttrFunc (storage .DefaultNamespaceScopedAttr ).WithFieldMutation (imageapi .ImageStreamSelector ),
72
74
}
73
75
if err := store .CompleteWithOptions (options ); err != nil {
74
- return nil , nil , nil , err
76
+ return nil , nil , nil , nil , err
75
77
}
76
78
79
+ layersREST := & LayersREST {index : imageLayerIndex , store : & store }
80
+
77
81
statusStrategy := imagestream .NewStatusStrategy (strategy )
78
82
statusStore := store
79
83
statusStore .Decorator = nil
@@ -88,7 +92,7 @@ func NewREST(
88
92
internalStore .UpdateStrategy = internalStrategy
89
93
90
94
internalREST := & InternalREST {store : & internalStore }
91
- return rest , statusREST , internalREST , nil
95
+ return rest , layersREST , statusREST , internalREST , nil
92
96
}
93
97
94
98
// StatusREST implements the REST endpoint for changing the status of an image stream.
@@ -138,6 +142,76 @@ func (r *InternalREST) Update(ctx apirequest.Context, name string, objInfo rest.
138
142
return r .store .Update (ctx , name , objInfo , createValidation , updateValidation )
139
143
}
140
144
145
+ // LayersREST implements the REST endpoint for changing both the spec and status of an image stream.
146
+ type LayersREST struct {
147
+ store * registry.Store
148
+ index ImageLayerIndex
149
+ }
150
+
151
+ var _ rest.Getter = & LayersREST {}
152
+
153
+ func (r * LayersREST ) New () runtime.Object {
154
+ return & imageapi.ImageStreamLayers {}
155
+ }
156
+
157
+ // Get returns the layers for an image stream.
158
+ func (r * LayersREST ) Get (ctx apirequest.Context , name string , options * metav1.GetOptions ) (runtime.Object , error ) {
159
+ if ! r .index .HasSynced () {
160
+ return nil , errors .NewServerTimeout (r .store .DefaultQualifiedResource , "get" , 2 )
161
+ }
162
+ obj , err := r .store .Get (ctx , name , options )
163
+ if err != nil {
164
+ return nil , err
165
+ }
166
+ is := obj .(* imageapi.ImageStream )
167
+ isl := & imageapi.ImageStreamLayers {
168
+ ObjectMeta : is .ObjectMeta ,
169
+ Blobs : make (map [string ]imageapi.ImageLayerData ),
170
+ Layers : make (map [string ]imageapi.BlobReferences ),
171
+ Manifests : make (map [string ]string ),
172
+ }
173
+
174
+ for _ , status := range is .Status .Tags {
175
+ for _ , item := range status .Items {
176
+ if len (item .Image ) == 0 {
177
+ continue
178
+ }
179
+
180
+ obj , _ , _ := r .index .GetByKey (item .Image )
181
+ entry , ok := obj .(* ImageLayers )
182
+ if ! ok {
183
+ continue
184
+ }
185
+
186
+ if _ , ok := isl .Layers [item .Image ]; ! ok {
187
+ names := make (imageapi.BlobReferences , 0 , len (entry .Layers ))
188
+ for _ , layer := range entry .Layers {
189
+ names = append (names , layer .Name )
190
+ if _ , ok := isl .Blobs [layer .Name ]; ! ok {
191
+ isl .Blobs [layer .Name ] = imageapi.ImageLayerData {LayerSize : & layer .LayerSize , MediaType : layer .MediaType }
192
+ }
193
+ }
194
+ isl .Layers [item .Image ] = names
195
+ }
196
+
197
+ if blob := entry .Manifest ; blob != nil {
198
+ if _ , ok := isl .Manifests [item .Image ]; ! ok {
199
+ isl .Manifests [item .Image ] = blob .Name
200
+ if _ , ok := isl .Blobs [blob .Name ]; ! ok {
201
+ if blob .LayerSize == 0 {
202
+ // only send media type since we don't the size of the manifest
203
+ isl .Blobs [blob .Name ] = imageapi.ImageLayerData {MediaType : blob .MediaType }
204
+ } else {
205
+ isl .Blobs [blob .Name ] = imageapi.ImageLayerData {LayerSize : & blob .LayerSize , MediaType : blob .MediaType }
206
+ }
207
+ }
208
+ }
209
+ }
210
+ }
211
+ }
212
+ return isl , nil
213
+ }
214
+
141
215
// LegacyREST allows us to wrap and alter some behavior
142
216
type LegacyREST struct {
143
217
* REST
0 commit comments