| ... | ... |
@@ -19859,6 +19859,10 @@ |
| 19859 | 19859 |
"insecure": {
|
| 19860 | 19860 |
"type": "boolean", |
| 19861 | 19861 |
"description": "if true, the server may bypass certificate verification or connect directly over HTTP during image import" |
| 19862 |
+ }, |
|
| 19863 |
+ "scheduled": {
|
|
| 19864 |
+ "type": "boolean", |
|
| 19865 |
+ "description": "if true, the server will periodically check to ensure this tag is up to date" |
|
| 19862 | 19866 |
} |
| 19863 | 19867 |
} |
| 19864 | 19868 |
}, |
| ... | ... |
@@ -2352,6 +2352,7 @@ func deepCopy_api_TagEventList(in imageapi.TagEventList, out *imageapi.TagEventL |
| 2352 | 2352 |
|
| 2353 | 2353 |
func deepCopy_api_TagImportPolicy(in imageapi.TagImportPolicy, out *imageapi.TagImportPolicy, c *conversion.Cloner) error {
|
| 2354 | 2354 |
out.Insecure = in.Insecure |
| 2355 |
+ out.Scheduled = in.Scheduled |
|
| 2355 | 2356 |
return nil |
| 2356 | 2357 |
} |
| 2357 | 2358 |
|
| ... | ... |
@@ -4114,6 +4114,7 @@ func autoconvert_api_TagImportPolicy_To_v1_TagImportPolicy(in *imageapi.TagImpor |
| 4114 | 4114 |
defaulting.(func(*imageapi.TagImportPolicy))(in) |
| 4115 | 4115 |
} |
| 4116 | 4116 |
out.Insecure = in.Insecure |
| 4117 |
+ out.Scheduled = in.Scheduled |
|
| 4117 | 4118 |
return nil |
| 4118 | 4119 |
} |
| 4119 | 4120 |
|
| ... | ... |
@@ -4526,6 +4527,7 @@ func autoconvert_v1_TagImportPolicy_To_api_TagImportPolicy(in *imageapiv1.TagImp |
| 4526 | 4526 |
defaulting.(func(*imageapiv1.TagImportPolicy))(in) |
| 4527 | 4527 |
} |
| 4528 | 4528 |
out.Insecure = in.Insecure |
| 4529 |
+ out.Scheduled = in.Scheduled |
|
| 4529 | 4530 |
return nil |
| 4530 | 4531 |
} |
| 4531 | 4532 |
|
| ... | ... |
@@ -2275,6 +2275,7 @@ func deepCopy_v1_TagEventCondition(in imageapiv1.TagEventCondition, out *imageap |
| 2275 | 2275 |
|
| 2276 | 2276 |
func deepCopy_v1_TagImportPolicy(in imageapiv1.TagImportPolicy, out *imageapiv1.TagImportPolicy, c *conversion.Cloner) error {
|
| 2277 | 2277 |
out.Insecure = in.Insecure |
| 2278 |
+ out.Scheduled = in.Scheduled |
|
| 2278 | 2279 |
return nil |
| 2279 | 2280 |
} |
| 2280 | 2281 |
|
| ... | ... |
@@ -2112,6 +2112,7 @@ func deepCopy_v1beta3_TagEventCondition(in imageapiv1beta3.TagEventCondition, ou |
| 2112 | 2112 |
|
| 2113 | 2113 |
func deepCopy_v1beta3_TagImportPolicy(in imageapiv1beta3.TagImportPolicy, out *imageapiv1beta3.TagImportPolicy, c *conversion.Cloner) error {
|
| 2114 | 2114 |
out.Insecure = in.Insecure |
| 2115 |
+ out.Scheduled = in.Scheduled |
|
| 2115 | 2116 |
return nil |
| 2116 | 2117 |
} |
| 2117 | 2118 |
|
| ... | ... |
@@ -112,6 +112,8 @@ type TagReference struct {
|
| 112 | 112 |
type TagImportPolicy struct {
|
| 113 | 113 |
// Insecure is true if the server may bypass certificate verification or connect directly over HTTP during image import. |
| 114 | 114 |
Insecure bool |
| 115 |
+ // Scheduled indicates to the server that this tag should be periodically checked to ensure it is up to date, and imported |
|
| 116 |
+ Scheduled bool |
|
| 115 | 117 |
} |
| 116 | 118 |
|
| 117 | 119 |
// ImageStreamStatus contains information about the state of this image stream. |
| ... | ... |
@@ -195,7 +195,8 @@ func init() {
|
| 195 | 195 |
Annotations: curr.Annotations, |
| 196 | 196 |
Reference: curr.Reference, |
| 197 | 197 |
ImportPolicy: newer.TagImportPolicy{
|
| 198 |
- Insecure: curr.ImportPolicy.Insecure, |
|
| 198 |
+ Insecure: curr.ImportPolicy.Insecure, |
|
| 199 |
+ Scheduled: curr.ImportPolicy.Scheduled, |
|
| 199 | 200 |
}, |
| 200 | 201 |
} |
| 201 | 202 |
if curr.Generation != nil {
|
| ... | ... |
@@ -223,7 +224,8 @@ func init() {
|
| 223 | 223 |
Annotations: newTagReference.Annotations, |
| 224 | 224 |
Reference: newTagReference.Reference, |
| 225 | 225 |
ImportPolicy: TagImportPolicy{
|
| 226 |
- Insecure: newTagReference.ImportPolicy.Insecure, |
|
| 226 |
+ Insecure: newTagReference.ImportPolicy.Insecure, |
|
| 227 |
+ Scheduled: newTagReference.ImportPolicy.Scheduled, |
|
| 227 | 228 |
}, |
| 228 | 229 |
} |
| 229 | 230 |
if newTagReference.Generation != nil {
|
| ... | ... |
@@ -90,6 +90,8 @@ type NamedTagReference struct {
|
| 90 | 90 |
type TagImportPolicy struct {
|
| 91 | 91 |
// Insecure is true if the server may bypass certificate verification or connect directly over HTTP during image import. |
| 92 | 92 |
Insecure bool `json:"insecure,omitempty" description:"if true, the server may bypass certificate verification or connect directly over HTTP during image import"` |
| 93 |
+ // Scheduled indicates to the server that this tag should be periodically checked to ensure it is up to date, and imported |
|
| 94 |
+ Scheduled bool `json:"scheduled,omitempty" description:"if true, the server will periodically check to ensure this tag is up to date"` |
|
| 93 | 95 |
} |
| 94 | 96 |
|
| 95 | 97 |
// ImageStreamStatus contains information about the state of this image stream. |
| ... | ... |
@@ -243,7 +243,8 @@ func init() {
|
| 243 | 243 |
Annotations: curr.Annotations, |
| 244 | 244 |
Reference: curr.Reference, |
| 245 | 245 |
ImportPolicy: newer.TagImportPolicy{
|
| 246 |
- Insecure: curr.ImportPolicy.Insecure, |
|
| 246 |
+ Insecure: curr.ImportPolicy.Insecure, |
|
| 247 |
+ Scheduled: curr.ImportPolicy.Scheduled, |
|
| 247 | 248 |
}, |
| 248 | 249 |
} |
| 249 | 250 |
if curr.Generation != nil {
|
| ... | ... |
@@ -271,7 +272,8 @@ func init() {
|
| 271 | 271 |
Annotations: newTagReference.Annotations, |
| 272 | 272 |
Reference: newTagReference.Reference, |
| 273 | 273 |
ImportPolicy: TagImportPolicy{
|
| 274 |
- Insecure: newTagReference.ImportPolicy.Insecure, |
|
| 274 |
+ Insecure: newTagReference.ImportPolicy.Insecure, |
|
| 275 |
+ Scheduled: newTagReference.ImportPolicy.Scheduled, |
|
| 275 | 276 |
}, |
| 276 | 277 |
} |
| 277 | 278 |
if newTagReference.Generation != nil {
|
| ... | ... |
@@ -85,6 +85,8 @@ type NamedTagReference struct {
|
| 85 | 85 |
type TagImportPolicy struct {
|
| 86 | 86 |
// Insecure is true if the server may bypass certificate verification or connect directly over HTTP during image import. |
| 87 | 87 |
Insecure bool `json:"insecure,omitempty" description:"if true, the server may bypass certificate verification or connect directly over HTTP during image import"` |
| 88 |
+ // Scheduled indicates to the server that this tag should be periodically checked to ensure it is up to date, and imported |
|
| 89 |
+ Scheduled bool `json:"scheduled,omitempty" description:"if true, the server will periodically check to ensure this tag is up to date"` |
|
| 88 | 90 |
} |
| 89 | 91 |
|
| 90 | 92 |
// ImageStreamStatus contains information about the state of this image stream. |
| ... | ... |
@@ -95,7 +95,14 @@ func ValidateImageStream(stream *api.ImageStream) field.ErrorList {
|
| 95 | 95 |
for tag, tagRef := range stream.Spec.Tags {
|
| 96 | 96 |
if tagRef.From != nil {
|
| 97 | 97 |
switch tagRef.From.Kind {
|
| 98 |
- case "DockerImage", "ImageStreamImage", "ImageStreamTag": |
|
| 98 |
+ case "DockerImage": |
|
| 99 |
+ if ref, err := api.ParseDockerImageReference(stream.Spec.DockerImageRepository); err == nil && tagRef.ImportPolicy.Scheduled && len(ref.ID) > 0 {
|
|
| 100 |
+ result = append(result, field.Invalid(field.NewPath("spec", "tags").Key(tag).Child("from", "name"), tagRef.From.Name, "only tags can be scheduled for import"))
|
|
| 101 |
+ } |
|
| 102 |
+ case "ImageStreamImage", "ImageStreamTag": |
|
| 103 |
+ if tagRef.ImportPolicy.Scheduled {
|
|
| 104 |
+ result = append(result, field.Invalid(field.NewPath("spec", "tags").Key(tag).Child("importPolicy", "scheduled"), tagRef.ImportPolicy.Scheduled, "only tags pointing to Docker repositories may be scheduled for background import"))
|
|
| 105 |
+ } |
|
| 99 | 106 |
default: |
| 100 | 107 |
result = append(result, field.Invalid(field.NewPath("spec", "tags").Key(tag).Child("from", "kind"), tagRef.From.Kind, "valid values are 'DockerImage', 'ImageStreamImage', 'ImageStreamTag'"))
|
| 101 | 108 |
} |
| ... | ... |
@@ -191,8 +198,12 @@ func ValidateImageStreamImport(isi *api.ImageStreamImport) field.ErrorList {
|
| 191 | 191 |
if len(spec.From.Name) == 0 {
|
| 192 | 192 |
errs = append(errs, field.Required(imagesPath.Index(i).Child("from", "name")))
|
| 193 | 193 |
} else {
|
| 194 |
- if _, err := api.ParseDockerImageReference(spec.From.Name); err != nil {
|
|
| 194 |
+ if ref, err := api.ParseDockerImageReference(spec.From.Name); err != nil {
|
|
| 195 | 195 |
errs = append(errs, field.Invalid(imagesPath.Index(i).Child("from", "name"), spec.From.Name, err.Error()))
|
| 196 |
+ } else {
|
|
| 197 |
+ if len(ref.ID) > 0 && spec.ImportPolicy.Scheduled {
|
|
| 198 |
+ errs = append(errs, field.Invalid(imagesPath.Index(i).Child("from", "name"), spec.From.Name, "only tags can be scheduled for import"))
|
|
| 199 |
+ } |
|
| 196 | 200 |
} |
| 197 | 201 |
} |
| 198 | 202 |
default: |
| ... | ... |
@@ -207,8 +218,12 @@ func ValidateImageStreamImport(isi *api.ImageStreamImport) field.ErrorList {
|
| 207 | 207 |
if len(spec.From.Name) == 0 {
|
| 208 | 208 |
errs = append(errs, field.Required(repoPath.Child("from", "name")))
|
| 209 | 209 |
} else {
|
| 210 |
- if _, err := api.ParseDockerImageReference(spec.From.Name); err != nil {
|
|
| 211 |
- errs = append(errs, field.Invalid(repoPath.Child("from", "name"), spec.From.Name, err.Error()))
|
|
| 210 |
+ if ref, err := api.ParseDockerImageReference(from.Name); err != nil {
|
|
| 211 |
+ errs = append(errs, field.Invalid(repoPath.Child("from", "name"), from.Name, err.Error()))
|
|
| 212 |
+ } else {
|
|
| 213 |
+ if len(ref.ID) > 0 || len(ref.Tag) > 0 {
|
|
| 214 |
+ errs = append(errs, field.Invalid(repoPath.Child("from", "name"), from.Name, "you must specify an image repository, not a tag or ID"))
|
|
| 215 |
+ } |
|
| 212 | 216 |
} |
| 213 | 217 |
} |
| 214 | 218 |
default: |
| ... | ... |
@@ -276,6 +276,29 @@ func TestValidateImageStream(t *testing.T) {
|
| 276 | 276 |
field.Required(field.NewPath("status", "tags").Key("tag").Child("items").Index(2).Child("dockerImageReference")),
|
| 277 | 277 |
}, |
| 278 | 278 |
}, |
| 279 |
+ "only DockerImage tags can be scheduled": {
|
|
| 280 |
+ namespace: "namespace", |
|
| 281 |
+ name: "foo", |
|
| 282 |
+ specTags: map[string]api.TagReference{
|
|
| 283 |
+ "tag": {
|
|
| 284 |
+ From: &kapi.ObjectReference{
|
|
| 285 |
+ Kind: "DockerImage", |
|
| 286 |
+ Name: "abc", |
|
| 287 |
+ }, |
|
| 288 |
+ ImportPolicy: api.TagImportPolicy{Scheduled: true},
|
|
| 289 |
+ }, |
|
| 290 |
+ "other": {
|
|
| 291 |
+ From: &kapi.ObjectReference{
|
|
| 292 |
+ Kind: "ImageStreamTag", |
|
| 293 |
+ Name: "other:latest", |
|
| 294 |
+ }, |
|
| 295 |
+ ImportPolicy: api.TagImportPolicy{Scheduled: true},
|
|
| 296 |
+ }, |
|
| 297 |
+ }, |
|
| 298 |
+ expected: field.ErrorList{
|
|
| 299 |
+ field.Invalid(field.NewPath("spec", "tags").Key("other").Child("importPolicy", "scheduled"), true, "only tags pointing to Docker repositories may be scheduled for background import"),
|
|
| 300 |
+ }, |
|
| 301 |
+ }, |
|
| 279 | 302 |
"valid": {
|
| 280 | 303 |
namespace: "namespace", |
| 281 | 304 |
name: "foo", |