Browse code

Image API cleanup

Remove json tags from internal API.

Remove ImageRepository*.

Remove TagReference.DockerImageReference from internal.

Make Image its own field instead of being embedded for ImageStreamTag
and ImageStreamImage. Remove ImageName as it's now available at
Image.Name.

Andy Goldstein authored on 2015/06/06 05:41:51
Showing 53 changed files
... ...
@@ -12057,4 +12057,4 @@
12057 12057
     }
12058 12058
    }
12059 12059
   }
12060
- }
12060
+ }
12061 12061
\ No newline at end of file
... ...
@@ -12227,32 +12227,16 @@
12227 12227
    "v1.ImageStreamImage": {
12228 12228
     "id": "v1.ImageStreamImage",
12229 12229
     "required": [
12230
-     "imageName"
12230
+     "image"
12231 12231
     ],
12232 12232
     "properties": {
12233 12233
      "apiVersion": {
12234 12234
       "type": "string",
12235 12235
       "description": "version of the schema the object should have"
12236 12236
      },
12237
-     "dockerImageManifest": {
12238
-      "type": "string",
12239
-      "description": "raw JSON of the manifest"
12240
-     },
12241
-     "dockerImageMetadata": {
12242
-      "type": "string",
12243
-      "description": "metadata about this image"
12244
-     },
12245
-     "dockerImageMetadataVersion": {
12246
-      "type": "string",
12247
-      "description": "conveys version of the object, if empty defaults to '1.0'"
12248
-     },
12249
-     "dockerImageReference": {
12250
-      "type": "string",
12251
-      "description": "string that can be used to pull this image"
12252
-     },
12253
-     "imageName": {
12254
-      "type": "string",
12255
-      "description": "name of image"
12237
+     "image": {
12238
+      "$ref": "v1.Image",
12239
+      "description": "the image associated with the ImageStream and image name"
12256 12240
      },
12257 12241
      "kind": {
12258 12242
       "type": "string",
... ...
@@ -12355,32 +12339,16 @@
12355 12355
    "v1.ImageStreamTag": {
12356 12356
     "id": "v1.ImageStreamTag",
12357 12357
     "required": [
12358
-     "imageName"
12358
+     "image"
12359 12359
     ],
12360 12360
     "properties": {
12361 12361
      "apiVersion": {
12362 12362
       "type": "string",
12363 12363
       "description": "version of the schema the object should have"
12364 12364
      },
12365
-     "dockerImageManifest": {
12366
-      "type": "string",
12367
-      "description": "raw JSON of the manifest"
12368
-     },
12369
-     "dockerImageMetadata": {
12370
-      "type": "string",
12371
-      "description": "metadata about this image"
12372
-     },
12373
-     "dockerImageMetadataVersion": {
12374
-      "type": "string",
12375
-      "description": "conveys version of the object, if empty defaults to '1.0'"
12376
-     },
12377
-     "dockerImageReference": {
12378
-      "type": "string",
12379
-      "description": "string that can be used to pull this image"
12380
-     },
12381
-     "imageName": {
12382
-      "type": "string",
12383
-      "description": "name of image"
12365
+     "image": {
12366
+      "$ref": "v1.Image",
12367
+      "description": "the image associated with the ImageStream and tag"
12384 12368
      },
12385 12369
      "kind": {
12386 12370
       "type": "string",
... ...
@@ -14181,4 +14149,4 @@
14181 14181
     }
14182 14182
    }
14183 14183
   }
14184
- }
14184
+ }
14185 14185
\ No newline at end of file
... ...
@@ -73,9 +73,6 @@ func TestExampleObjectSchemas(t *testing.T) {
73 73
 			"jenkins-config":       &kapi.List{},
74 74
 			"application-template": &templateapi.Template{},
75 75
 		},
76
-		"../examples/image-repositories": {
77
-			"image-repositories": &imageapi.ImageRepositoryList{},
78
-		},
79 76
 		"../examples/image-streams": {
80 77
 			"image-streams-centos7": &imageapi.ImageStreamList{},
81 78
 			"image-streams-rhel7":   &imageapi.ImageStreamList{},
... ...
@@ -86,16 +83,14 @@ func TestExampleObjectSchemas(t *testing.T) {
86 86
 			"mongodb-template":    &templateapi.Template{},
87 87
 		},
88 88
 		"../test/integration/fixtures": {
89
-			"test-deployment-config":        &deployapi.DeploymentConfig{},
90
-			"test-image":                    &imageapi.Image{},
91
-			"test-image-repository":         &imageapi.ImageRepository{},
92
-			"test-image-repository-mapping": &imageapi.ImageRepositoryMapping{},
93
-			"test-image-stream":             &imageapi.ImageStream{},
94
-			"test-image-stream-mapping":     &imageapi.ImageStreamMapping{},
95
-			"test-route":                    &routeapi.Route{},
96
-			"test-service":                  &kapi.Service{},
97
-			"test-buildcli":                 &kapi.List{},
98
-			"test-buildcli-beta2":           &kapi.List{},
89
+			"test-deployment-config":    &deployapi.DeploymentConfig{},
90
+			"test-image":                &imageapi.Image{},
91
+			"test-image-stream":         &imageapi.ImageStream{},
92
+			"test-image-stream-mapping": &imageapi.ImageStreamMapping{},
93
+			"test-route":                &routeapi.Route{},
94
+			"test-service":              &kapi.Service{},
95
+			"test-buildcli":             &kapi.List{},
96
+			"test-buildcli-beta2":       &kapi.List{},
99 97
 		},
100 98
 		"../test/templates/fixtures": {
101 99
 			"crunchydata-pod": nil, // Explicitly fails validation, but should pass transformation
... ...
@@ -50,17 +50,24 @@ func fuzzInternalObject(t *testing.T, forVersion string, item runtime.Object, se
50 50
 			j.DockerImageMetadataVersion = []string{"pre012", "1.0"}[c.Rand.Intn(2)]
51 51
 			j.DockerImageReference = c.RandString()
52 52
 		},
53
-		func(j *image.ImageRepositoryMapping, c fuzz.Continue) {
54
-			c.FuzzNoCustom(j)
55
-			j.DockerImageRepository = ""
56
-		},
57 53
 		func(j *image.ImageStreamMapping, c fuzz.Continue) {
58 54
 			c.FuzzNoCustom(j)
59 55
 			j.DockerImageRepository = ""
60 56
 		},
57
+		func(j *image.ImageStreamImage, c fuzz.Continue) {
58
+			c.Fuzz(&j.Image)
59
+			// because we de-embedded Image from ImageStreamImage, in order to round trip
60
+			// successfully, the ImageStreamImage's ObjectMeta must match the Image's.
61
+			j.ObjectMeta = j.Image.ObjectMeta
62
+		},
63
+		func(j *image.ImageStreamTag, c fuzz.Continue) {
64
+			c.Fuzz(&j.Image)
65
+			// because we de-embedded Image from ImageStreamTag, in order to round trip
66
+			// successfully, the ImageStreamTag's ObjectMeta must match the Image's.
67
+			j.ObjectMeta = j.Image.ObjectMeta
68
+		},
61 69
 		func(j *image.TagReference, c fuzz.Continue) {
62 70
 			c.FuzzNoCustom(j)
63
-			j.DockerImageReference = ""
64 71
 			if j.From != nil {
65 72
 				specs := []string{"", "ImageStreamTag", "ImageStreamImage"}
66 73
 				j.From.Kind = specs[c.Intn(len(specs))]
... ...
@@ -224,12 +231,8 @@ var skipStandardVersions = map[string][]string{
224 224
 	"DockerImage": {"pre012", "1.0"},
225 225
 }
226 226
 var skipV1beta1 = map[string]struct{}{}
227
-var skipV1beta3 = map[string]struct{}{
228
-	"ImageRepository": {},
229
-}
230
-var skipV1 = map[string]struct{}{
231
-	"ImageRepository": {},
232
-}
227
+var skipV1beta3 = map[string]struct{}{}
228
+var skipV1 = map[string]struct{}{}
233 229
 
234 230
 const fuzzIters = 20
235 231
 
... ...
@@ -238,7 +241,7 @@ func TestSpecificKind(t *testing.T) {
238 238
 	api.Scheme.Log(t)
239 239
 	defer api.Scheme.Log(nil)
240 240
 
241
-	kind := "ImageRepositoryList"
241
+	kind := "ImageStreamTag"
242 242
 	item, err := api.Scheme.New("", kind)
243 243
 	if err != nil {
244 244
 		t.Errorf("Couldn't make a %v? %v", kind, err)
... ...
@@ -45,20 +45,8 @@ func ValidateObject(obj runtime.Object) (errors []error) {
45 45
 	case *imageapi.Image:
46 46
 		t.Namespace = ""
47 47
 		errors = imagev.ValidateImage(t)
48
-	case *imageapi.ImageRepository:
49
-		s := &imageapi.ImageStream{}
50
-		if err := kapi.Scheme.Convert(&t, &s); err != nil {
51
-			return []error{err}
52
-		}
53
-		return imagev.ValidateImageStream(s)
54 48
 	case *imageapi.ImageStream:
55 49
 		errors = imagev.ValidateImageStream(t)
56
-	case *imageapi.ImageRepositoryMapping:
57
-		m := &imageapi.ImageStreamMapping{}
58
-		if err := kapi.Scheme.Convert(&t, &m); err != nil {
59
-			return []error{err}
60
-		}
61
-		return imagev.ValidateImageStreamMapping(m)
62 50
 	case *imageapi.ImageStreamMapping:
63 51
 		errors = imagev.ValidateImageStreamMapping(t)
64 52
 	case *deployapi.DeploymentConfig:
... ...
@@ -400,7 +400,7 @@ func mockBuildConfigInstantiator(buildcfg *buildapi.BuildConfig, imageStream *im
400 400
 				return imageStream, nil
401 401
 			},
402 402
 			GetImageStreamTagFunc: func(ctx kapi.Context, name string) (*imageapi.ImageStreamTag, error) {
403
-				return &imageapi.ImageStreamTag{Image: *image, ImageName: name}, nil
403
+				return &imageapi.ImageStreamTag{Image: *image}, nil
404 404
 			},
405 405
 			GetImageStreamImageFunc: func(ctx kapi.Context, name string) (*imageapi.ImageStreamImage, error) {
406 406
 				return &imageapi.ImageStreamImage{Image: *image}, nil
... ...
@@ -299,7 +299,7 @@ func (g *BuildGenerator) resolveImageStreamReference(ctx kapi.Context, from *kap
299 299
 		}
300 300
 		return image.String(), nil
301 301
 	case "ImageStreamImage":
302
-		image, err := g.Client.GetImageStreamImage(kapi.WithNamespace(ctx, namespace), from.Name)
302
+		imageStreamImage, err := g.Client.GetImageStreamImage(kapi.WithNamespace(ctx, namespace), from.Name)
303 303
 		if err != nil {
304 304
 			glog.V(2).Infof("Error ImageStreamReference %s in namespace %s: %v", from.Name, namespace, err)
305 305
 			if errors.IsNotFound(err) {
... ...
@@ -307,10 +307,11 @@ func (g *BuildGenerator) resolveImageStreamReference(ctx kapi.Context, from *kap
307 307
 			}
308 308
 			return "", fatalError{err}
309 309
 		}
310
+		image := imageStreamImage.Image
310 311
 		glog.V(4).Infof("Resolved ImageStreamReference %s to image %s with reference %s in namespace %s", from.Name, image.Name, image.DockerImageReference, namespace)
311 312
 		return image.DockerImageReference, nil
312 313
 	case "ImageStreamTag":
313
-		image, err := g.Client.GetImageStreamTag(kapi.WithNamespace(ctx, namespace), from.Name)
314
+		imageStreamTag, err := g.Client.GetImageStreamTag(kapi.WithNamespace(ctx, namespace), from.Name)
314 315
 		if err != nil {
315 316
 			glog.V(2).Infof("Error resolving ImageStreamTag reference %s in namespace %s: %v", from.Name, namespace, err)
316 317
 			if errors.IsNotFound(err) {
... ...
@@ -318,6 +319,7 @@ func (g *BuildGenerator) resolveImageStreamReference(ctx kapi.Context, from *kap
318 318
 			}
319 319
 			return "", fatalError{err}
320 320
 		}
321
+		image := imageStreamTag.Image
321 322
 		glog.V(4).Infof("Resolved ImageStreamTag %s to image %s with reference %s in namespace %s", from.Name, image.Name, image.DockerImageReference, namespace)
322 323
 		return image.DockerImageReference, nil
323 324
 	case "DockerImage":
... ...
@@ -339,7 +339,6 @@ func TestGenerateBuildWithImageTagForSourceStrategyImageRepository(t *testing.T)
339 339
 			},
340 340
 			GetImageStreamTagFunc: func(ctx kapi.Context, name string) (*imageapi.ImageStreamTag, error) {
341 341
 				return &imageapi.ImageStreamTag{
342
-					ImageName: name,
343 342
 					Image: imageapi.Image{
344 343
 						ObjectMeta:           kapi.ObjectMeta{Name: imageRepoName + ":" + newTag},
345 344
 						DockerImageReference: originalImage + ":" + newTag,
... ...
@@ -417,7 +416,6 @@ func TestGenerateBuildWithImageTagForDockerStrategyImageRepository(t *testing.T)
417 417
 			},
418 418
 			GetImageStreamTagFunc: func(ctx kapi.Context, name string) (*imageapi.ImageStreamTag, error) {
419 419
 				return &imageapi.ImageStreamTag{
420
-					ImageName: name,
421 420
 					Image: imageapi.Image{
422 421
 						ObjectMeta:           kapi.ObjectMeta{Name: imageRepoName + ":" + newTag},
423 422
 						DockerImageReference: originalImage + ":" + newTag,
... ...
@@ -494,7 +492,6 @@ func TestGenerateBuildWithImageTagForCustomStrategyImageRepository(t *testing.T)
494 494
 			},
495 495
 			GetImageStreamTagFunc: func(ctx kapi.Context, name string) (*imageapi.ImageStreamTag, error) {
496 496
 				return &imageapi.ImageStreamTag{
497
-					ImageName: name,
498 497
 					Image: imageapi.Image{
499 498
 						ObjectMeta:           kapi.ObjectMeta{Name: imageRepoName + ":" + newTag},
500 499
 						DockerImageReference: originalImage + ":" + newTag,
... ...
@@ -964,7 +961,6 @@ func mockBuildGenerator() *BuildGenerator {
964 964
 			},
965 965
 			GetImageStreamTagFunc: func(ctx kapi.Context, name string) (*imageapi.ImageStreamTag, error) {
966 966
 				return &imageapi.ImageStreamTag{
967
-					ImageName: name,
968 967
 					Image: imageapi.Image{
969 968
 						ObjectMeta:           kapi.ObjectMeta{Name: imageRepoName + ":" + newTag},
970 969
 						DockerImageReference: latestDockerReference,
... ...
@@ -103,7 +103,7 @@ func TestCreateInstantiate(t *testing.T) {
103 103
 				return imageStream, nil
104 104
 			},
105 105
 			GetImageStreamTagFunc: func(ctx kapi.Context, name string) (*imageapi.ImageStreamTag, error) {
106
-				return &imageapi.ImageStreamTag{*image, name}, nil
106
+				return &imageapi.ImageStreamTag{Image: *image}, nil
107 107
 			},
108 108
 			GetImageStreamImageFunc: func(ctx kapi.Context, name string) (*imageapi.ImageStreamImage, error) {
109 109
 				return &imageapi.ImageStreamImage{Image: *image}, nil
110 110
deleted file mode 100644
... ...
@@ -1,102 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
5
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
6
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
7
-
8
-	imageapi "github.com/openshift/origin/pkg/image/api"
9
-)
10
-
11
-// ImageRepositoriesNamespacer has methods to work with ImageRepository resources in a namespace
12
-type ImageRepositoriesNamespacer interface {
13
-	ImageRepositories(namespace string) ImageRepositoryInterface
14
-}
15
-
16
-// ImageRepositoryInterface exposes methods on ImageRepository resources.
17
-type ImageRepositoryInterface interface {
18
-	List(label labels.Selector, field fields.Selector) (*imageapi.ImageRepositoryList, error)
19
-	Get(name string) (*imageapi.ImageRepository, error)
20
-	Create(repo *imageapi.ImageRepository) (*imageapi.ImageRepository, error)
21
-	Update(repo *imageapi.ImageRepository) (*imageapi.ImageRepository, error)
22
-	Delete(name string) error
23
-	Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
24
-}
25
-
26
-// ImageRepositoryNamespaceGetter exposes methods to get ImageRepositories by Namespace
27
-type ImageRepositoryNamespaceGetter interface {
28
-	GetByNamespace(namespace, name string) (*imageapi.ImageRepository, error)
29
-}
30
-
31
-// imageRepositories implements ImageRepositoriesNamespacer interface
32
-type imageRepositories struct {
33
-	r  *Client
34
-	ns string
35
-}
36
-
37
-// newImageRepositories returns an imageRepositories
38
-func newImageRepositories(c *Client, namespace string) *imageRepositories {
39
-	return &imageRepositories{
40
-		r:  c,
41
-		ns: namespace,
42
-	}
43
-}
44
-
45
-// List returns a list of imagerepositories that match the label and field selectors.
46
-func (c *imageRepositories) List(label labels.Selector, field fields.Selector) (result *imageapi.ImageRepositoryList, err error) {
47
-	result = &imageapi.ImageRepositoryList{}
48
-	err = c.r.Get().
49
-		Namespace(c.ns).
50
-		Resource("imageRepositories").
51
-		LabelsSelectorParam(label).
52
-		FieldsSelectorParam(field).
53
-		Do().
54
-		Into(result)
55
-	return
56
-}
57
-
58
-// Get returns information about a particular imagerepository and error if one occurs.
59
-func (c *imageRepositories) Get(name string) (result *imageapi.ImageRepository, err error) {
60
-	result = &imageapi.ImageRepository{}
61
-	err = c.r.Get().Namespace(c.ns).Resource("imageRepositories").Name(name).Do().Into(result)
62
-	return
63
-}
64
-
65
-// GetByNamespace returns information about a particular imagerepository in a particular namespace and error if one occurs.
66
-func (c *imageRepositories) GetByNamespace(namespace, name string) (result *imageapi.ImageRepository, err error) {
67
-	result = &imageapi.ImageRepository{}
68
-	c.r.Get().Namespace(namespace).Resource("imageRepositories").Name(name).Do().Into(result)
69
-	return
70
-}
71
-
72
-// Create create a new imagerepository. Returns the server's representation of the imagerepository and error if one occurs.
73
-func (c *imageRepositories) Create(repo *imageapi.ImageRepository) (result *imageapi.ImageRepository, err error) {
74
-	result = &imageapi.ImageRepository{}
75
-	err = c.r.Post().Namespace(c.ns).Resource("imageRepositories").Body(repo).Do().Into(result)
76
-	return
77
-}
78
-
79
-// Update updates the imagerepository on the server. Returns the server's representation of the imagerepository and error if one occurs.
80
-func (c *imageRepositories) Update(repo *imageapi.ImageRepository) (result *imageapi.ImageRepository, err error) {
81
-	result = &imageapi.ImageRepository{}
82
-	err = c.r.Put().Namespace(c.ns).Resource("imageRepositories").Name(repo.Name).Body(repo).Do().Into(result)
83
-	return
84
-}
85
-
86
-// Delete deletes an image repository, returns error if one occurs.
87
-func (c *imageRepositories) Delete(name string) (err error) {
88
-	err = c.r.Delete().Namespace(c.ns).Resource("imageRepositories").Name(name).Do().Error()
89
-	return
90
-}
91
-
92
-// Watch returns a watch.Interface that watches the requested imagerepositories.
93
-func (c *imageRepositories) Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
94
-	return c.r.Get().
95
-		Prefix("watch").
96
-		Namespace(c.ns).
97
-		Resource("imageRepositories").
98
-		Param("resourceVersion", resourceVersion).
99
-		LabelsSelectorParam(label).
100
-		FieldsSelectorParam(field).
101
-		Watch()
102
-}
103 1
deleted file mode 100644
... ...
@@ -1,34 +0,0 @@
1
-package client
2
-
3
-import (
4
-	imageapi "github.com/openshift/origin/pkg/image/api"
5
-)
6
-
7
-// ImageRepositoryMappingsNamespacer has methods to work with ImageRepositoryMapping resources in a namespace
8
-type ImageRepositoryMappingsNamespacer interface {
9
-	ImageRepositoryMappings(namespace string) ImageRepositoryMappingInterface
10
-}
11
-
12
-// ImageRepositoryMappingInterface exposes methods on ImageRepositoryMapping resources.
13
-type ImageRepositoryMappingInterface interface {
14
-	Create(mapping *imageapi.ImageRepositoryMapping) error
15
-}
16
-
17
-// imageRepositoryMappings implements ImageRepositoryMappingsNamespacer interface
18
-type imageRepositoryMappings struct {
19
-	r  *Client
20
-	ns string
21
-}
22
-
23
-// newImageRepositoryMappings returns an imageRepositoryMappings
24
-func newImageRepositoryMappings(c *Client, namespace string) *imageRepositoryMappings {
25
-	return &imageRepositoryMappings{
26
-		r:  c,
27
-		ns: namespace,
28
-	}
29
-}
30
-
31
-// Create creates a new imagerepository mapping on the server. Returns error if one occurs.
32
-func (c *imageRepositoryMappings) Create(mapping *imageapi.ImageRepositoryMapping) error {
33
-	return c.r.Post().Namespace(c.ns).Resource("imageRepositoryMappings").Body(mapping).Do().Error()
34
-}
35 1
deleted file mode 100644
... ...
@@ -1,44 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"fmt"
5
-
6
-	"github.com/openshift/origin/pkg/image/api"
7
-)
8
-
9
-// ImageRepositoryTagsNamespacer has methods to work with ImageRepositoryTag resources in a namespace
10
-type ImageRepositoryTagsNamespacer interface {
11
-	ImageRepositoryTags(namespace string) ImageRepositoryTagInterface
12
-}
13
-
14
-// ImageRepositoryTagInterface exposes methods on ImageRepositoryTag resources.
15
-type ImageRepositoryTagInterface interface {
16
-	Get(name, tag string) (*api.ImageRepositoryTag, error)
17
-	Delete(name, tag string) error
18
-}
19
-
20
-// imageRepositoryTags implements ImageRepositoryTagsNamespacer interface
21
-type imageRepositoryTags struct {
22
-	r  *Client
23
-	ns string
24
-}
25
-
26
-// newImageRepositoryTags returns an imageRepositoryTags
27
-func newImageRepositoryTags(c *Client, namespace string) *imageRepositoryTags {
28
-	return &imageRepositoryTags{
29
-		r:  c,
30
-		ns: namespace,
31
-	}
32
-}
33
-
34
-// Get finds the specified image by name of an image repository and tag.
35
-func (c *imageRepositoryTags) Get(name, tag string) (result *api.ImageRepositoryTag, err error) {
36
-	result = &api.ImageRepositoryTag{}
37
-	err = c.r.Get().Namespace(c.ns).Resource("imageRepositoryTags").Name(fmt.Sprintf("%s:%s", name, tag)).Do().Into(result)
38
-	return
39
-}
40
-
41
-// Delete deletes the specified tag from the image repository.
42
-func (c *imageRepositoryTags) Delete(name, tag string) error {
43
-	return c.r.Delete().Namespace(c.ns).Resource("imageRepositoryTags").Name(fmt.Sprintf("%s:%s", name, tag)).Do().Error()
44
-}
... ...
@@ -464,7 +464,7 @@ func (d *ImageStreamTagDescriber) Describe(namespace, name string) (string, erro
464 464
 		return "", err
465 465
 	}
466 466
 
467
-	return describeImage(&imageStreamTag.Image, imageStreamTag.ImageName)
467
+	return describeImage(&imageStreamTag.Image, imageStreamTag.Image.Name)
468 468
 }
469 469
 
470 470
 // ImageStreamImageDescriber generates information about a ImageStreamImage (Image).
... ...
@@ -481,7 +481,7 @@ func (d *ImageStreamImageDescriber) Describe(namespace, name string) (string, er
481 481
 		return "", err
482 482
 	}
483 483
 
484
-	return describeImage(&imageStreamImage.Image, imageStreamImage.ImageName)
484
+	return describeImage(&imageStreamImage.Image, imageStreamImage.Image.Name)
485 485
 }
486 486
 
487 487
 // ImageStreamDescriber generates information about a ImageStream
... ...
@@ -165,9 +165,12 @@ func formatImageStreamTags(out *tabwriter.Writer, stream *imageapi.ImageStream)
165 165
 		specTag := ""
166 166
 		if ok {
167 167
 			if tagRef.From != nil {
168
-				specTag = fmt.Sprintf("%s/%s", tagRef.From.Namespace, tagRef.From.Name)
169
-			} else if len(tagRef.DockerImageReference) != 0 {
170
-				specTag = tagRef.DockerImageReference
168
+				switch tagRef.From.Kind {
169
+				case "ImageStreamTag", "ImageStreamImage":
170
+					specTag = fmt.Sprintf("%s/%s", tagRef.From.Namespace, tagRef.From.Name)
171
+				case "DockerImage":
172
+					specTag = tagRef.From.Name
173
+				}
171 174
 			}
172 175
 		} else {
173 176
 			specTag = "<pushed>"
... ...
@@ -68,11 +68,8 @@ func NewHumanReadablePrinter(noHeaders, withNamespace bool) *kctl.HumanReadableP
68 68
 	p.Handler(buildConfigColumns, printBuildConfigList)
69 69
 	p.Handler(imageColumns, printImage)
70 70
 	p.Handler(imageStreamTagColumns, printImageStreamTag)
71
-	p.Handler(imageColumns, printImageRepositoryTag)
72 71
 	p.Handler(imageStreamImageColumns, printImageStreamImage)
73 72
 	p.Handler(imageColumns, printImageList)
74
-	p.Handler(imageStreamColumns, printImageRepository)
75
-	p.Handler(imageStreamColumns, printImageRepositoryList)
76 73
 	p.Handler(imageStreamColumns, printImageStream)
77 74
 	p.Handler(imageStreamColumns, printImageStreamList)
78 75
 	p.Handler(projectColumns, printProject)
... ...
@@ -228,20 +225,16 @@ func printImage(image *imageapi.Image, w io.Writer, withNamespace bool) error {
228 228
 
229 229
 func printImageStreamTag(ist *imageapi.ImageStreamTag, w io.Writer, withNamespace bool) error {
230 230
 	created := fmt.Sprintf("%s ago", formatRelativeTime(ist.CreationTimestamp.Time))
231
-	_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", ist.Name, ist.Image.DockerImageReference, created, ist.ImageName)
231
+	_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", ist.Name, ist.Image.DockerImageReference, created, ist.Image.Name)
232 232
 	return err
233 233
 }
234 234
 
235 235
 func printImageStreamImage(isi *imageapi.ImageStreamImage, w io.Writer, withNamespace bool) error {
236 236
 	created := fmt.Sprintf("%s ago", formatRelativeTime(isi.CreationTimestamp.Time))
237
-	_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", isi.Name, isi.Image.DockerImageReference, created, isi.ImageName)
237
+	_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", isi.Name, isi.Image.DockerImageReference, created, isi.Image.Name)
238 238
 	return err
239 239
 }
240 240
 
241
-func printImageRepositoryTag(irt *imageapi.ImageRepositoryTag, w io.Writer, withNamespace bool) error {
242
-	return printImage(&irt.Image, w, withNamespace)
243
-}
244
-
245 241
 func printImageList(images *imageapi.ImageList, w io.Writer, withNamespace bool) error {
246 242
 	for _, image := range images.Items {
247 243
 		if err := printImage(&image, w, withNamespace); err != nil {
... ...
@@ -251,26 +244,6 @@ func printImageList(images *imageapi.ImageList, w io.Writer, withNamespace bool)
251 251
 	return nil
252 252
 }
253 253
 
254
-func printImageRepository(repo *imageapi.ImageRepository, w io.Writer, withNamespace bool) error {
255
-	tags := ""
256
-	set := util.NewStringSet()
257
-	for tag := range repo.Status.Tags {
258
-		set.Insert(tag)
259
-	}
260
-	tags = strings.Join(set.List(), ",")
261
-	_, err := fmt.Fprintf(w, "%s\t%s\t%s\n", repo.Name, repo.Status.DockerImageRepository, tags)
262
-	return err
263
-}
264
-
265
-func printImageRepositoryList(repos *imageapi.ImageRepositoryList, w io.Writer, withNamespace bool) error {
266
-	for _, repo := range repos.Items {
267
-		if err := printImageRepository(&repo, w, withNamespace); err != nil {
268
-			return err
269
-		}
270
-	}
271
-	return nil
272
-}
273
-
274 254
 func printImageStream(stream *imageapi.ImageStream, w io.Writer, withNamespace bool) error {
275 255
 	tags := ""
276 256
 	set := util.NewStringSet()
... ...
@@ -123,9 +123,9 @@ func (r *repository) GetByTag(ctx context.Context, tag string) (*manifest.Signed
123 123
 	}
124 124
 	image := &imageStreamTag.Image
125 125
 
126
-	dgst, err := digest.ParseDigest(imageStreamTag.ImageName)
126
+	dgst, err := digest.ParseDigest(imageStreamTag.Image.Name)
127 127
 	if err != nil {
128
-		log.Errorf("Error parsing digest %q: %v", imageStreamTag.ImageName, err)
128
+		log.Errorf("Error parsing digest %q: %v", imageStreamTag.Image.Name, err)
129 129
 		return nil, err
130 130
 	}
131 131
 
... ...
@@ -270,7 +270,14 @@ func (r *ImageRef) ImageStream() (*imageapi.ImageStream, error) {
270 270
 			Name: name,
271 271
 		},
272 272
 		Spec: imageapi.ImageStreamSpec{
273
-			Tags: map[string]imageapi.TagReference{imageapi.DefaultImageTag: {DockerImageReference: r.DockerImageReference.String()}},
273
+			Tags: map[string]imageapi.TagReference{
274
+				imageapi.DefaultImageTag: {
275
+					From: &kapi.ObjectReference{
276
+						Kind: "DockerImage",
277
+						Name: r.DockerImageReference.String(),
278
+					},
279
+				},
280
+			},
274 281
 		},
275 282
 	}
276 283
 	if !r.OutputImage {
... ...
@@ -279,13 +279,14 @@ func (r ImageStreamResolver) Resolve(value string) (*ComponentMatch, error) {
279 279
 		if latest == nil {
280 280
 			return nil, ErrNoMatch{value: value, qualifier: fmt.Sprintf("no image recorded for %s/%s:%s", repo.Namespace, repo.Name, searchTag)}
281 281
 		}
282
-		imageData, err := r.ImageStreamImages.ImageStreamImages(namespace).Get(ref.Name, latest.Image)
282
+		imageStreamImage, err := r.ImageStreamImages.ImageStreamImages(namespace).Get(ref.Name, latest.Image)
283 283
 		if err != nil {
284 284
 			if errors.IsNotFound(err) {
285 285
 				return nil, ErrNoMatch{value: value, qualifier: fmt.Sprintf("tag %q is set, but image %q has been removed", searchTag, latest.Image)}
286 286
 			}
287 287
 			return nil, err
288 288
 		}
289
+		imageData := imageStreamImage.Image
289 290
 
290 291
 		ref.Registry = ""
291 292
 		return &ComponentMatch{
... ...
@@ -47,63 +47,6 @@ func init() {
47 47
 			out.Size = in.Size
48 48
 			return nil
49 49
 		},
50
-		func(in *ImageStream, out *ImageRepository, s conversion.Scope) error {
51
-			if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
52
-				return err
53
-			}
54
-
55
-			out.DockerImageRepository = in.Spec.DockerImageRepository
56
-
57
-			if in.Spec.Tags != nil && out.Tags == nil {
58
-				out.Tags = make(map[string]string)
59
-			}
60
-			for tag, tagRef := range in.Spec.Tags {
61
-				value := tagRef.DockerImageReference
62
-				if len(value) == 0 && tagRef.From != nil && len(tagRef.From.Kind) == 0 {
63
-					value = tagRef.From.Name
64
-				}
65
-				out.Tags[tag] = value
66
-			}
67
-
68
-			return s.Convert(&in.Status, &out.Status, 0)
69
-		},
70
-		func(in *ImageRepository, out *ImageStream, s conversion.Scope) error {
71
-			if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
72
-				return err
73
-			}
74
-
75
-			out.Spec.DockerImageRepository = in.DockerImageRepository
76
-
77
-			if in.Tags != nil && out.Spec.Tags == nil {
78
-				out.Spec.Tags = make(map[string]TagReference)
79
-			}
80
-			for tag, value := range in.Tags {
81
-				out.Spec.Tags[tag] = TagReference{DockerImageReference: value}
82
-			}
83
-			return s.Convert(&in.Status, &out.Status, 0)
84
-		},
85
-		func(in *ImageStreamStatus, out *ImageRepositoryStatus, s conversion.Scope) error {
86
-			out.DockerImageRepository = in.DockerImageRepository
87
-			out.Tags = in.Tags
88
-			return nil
89
-		},
90
-		func(in *ImageRepositoryStatus, out *ImageStreamStatus, s conversion.Scope) error {
91
-			out.DockerImageRepository = in.DockerImageRepository
92
-			out.Tags = in.Tags
93
-			return nil
94
-		},
95
-		func(in *ImageStreamMapping, out *ImageRepositoryMapping, s conversion.Scope) error {
96
-			return s.DefaultConvert(in, out, conversion.IgnoreMissingFields|conversion.AllowDifferentFieldTypeNames)
97
-		},
98
-		func(in *ImageRepositoryMapping, out *ImageStreamMapping, s conversion.Scope) error {
99
-			return s.DefaultConvert(in, out, conversion.IgnoreMissingFields|conversion.AllowDifferentFieldTypeNames)
100
-		},
101
-		func(in *ImageStreamTag, out *ImageRepositoryTag, s conversion.Scope) error {
102
-			return s.DefaultConvert(in, out, conversion.IgnoreMissingFields|conversion.AllowDifferentFieldTypeNames)
103
-		},
104
-		func(in *ImageRepositoryTag, out *ImageStreamTag, s conversion.Scope) error {
105
-			return s.DefaultConvert(in, out, conversion.IgnoreMissingFields|conversion.AllowDifferentFieldTypeNames)
106
-		},
107 50
 	)
108 51
 	if err != nil {
109 52
 		// If one of the conversion functions is malformed, detect it immediately.
... ...
@@ -8,10 +8,6 @@ func init() {
8 8
 	api.Scheme.AddKnownTypes("",
9 9
 		&Image{},
10 10
 		&ImageList{},
11
-		&ImageRepository{},
12
-		&ImageRepositoryList{},
13
-		&ImageRepositoryMapping{},
14
-		&ImageRepositoryTag{},
15 11
 		&ImageStream{},
16 12
 		&ImageStreamList{},
17 13
 		&ImageStreamMapping{},
... ...
@@ -21,13 +17,11 @@ func init() {
21 21
 	)
22 22
 }
23 23
 
24
-func (*Image) IsAnAPIObject()                  {}
25
-func (*ImageList) IsAnAPIObject()              {}
26
-func (*ImageRepository) IsAnAPIObject()        {}
27
-func (*ImageRepositoryList) IsAnAPIObject()    {}
28
-func (*ImageRepositoryMapping) IsAnAPIObject() {}
29
-func (*DockerImage) IsAnAPIObject()            {}
30
-func (*ImageStream) IsAnAPIObject()            {}
31
-func (*ImageStreamList) IsAnAPIObject()        {}
32
-func (*ImageStreamMapping) IsAnAPIObject()     {}
33
-func (*ImageStreamTag) IsAnAPIObject()         {}
24
+func (*Image) IsAnAPIObject()              {}
25
+func (*ImageList) IsAnAPIObject()          {}
26
+func (*DockerImage) IsAnAPIObject()        {}
27
+func (*ImageStream) IsAnAPIObject()        {}
28
+func (*ImageStreamList) IsAnAPIObject()    {}
29
+func (*ImageStreamMapping) IsAnAPIObject() {}
30
+func (*ImageStreamTag) IsAnAPIObject()     {}
31
+func (*ImageStreamImage) IsAnAPIObject()   {}
... ...
@@ -7,10 +7,10 @@ import (
7 7
 
8 8
 // ImageList is a list of Image objects.
9 9
 type ImageList struct {
10
-	kapi.TypeMeta `json:",inline"`
11
-	kapi.ListMeta `json:"metadata,omitempty"`
10
+	kapi.TypeMeta
11
+	kapi.ListMeta
12 12
 
13
-	Items []Image `json:"items"`
13
+	Items []Image
14 14
 }
15 15
 
16 16
 const (
... ...
@@ -24,175 +24,119 @@ const (
24 24
 
25 25
 	// InsecureRepositoryAnnotation may be set true on an image stream to allow insecure access to pull content.
26 26
 	InsecureRepositoryAnnotation = "openshift.io/image.insecureRepository"
27
+
28
+	// DefaultImageTag is used when an image tag is needed and the configuration does not specify a tag to use.
29
+	DefaultImageTag = "latest"
27 30
 )
28 31
 
29 32
 // Image is an immutable representation of a Docker image and metadata at a point in time.
30 33
 type Image struct {
31
-	kapi.TypeMeta   `json:",inline"`
32
-	kapi.ObjectMeta `json:"metadata,omitempty"`
34
+	kapi.TypeMeta
35
+	kapi.ObjectMeta
33 36
 
34 37
 	// The string that can be used to pull this image.
35
-	DockerImageReference string `json:"dockerImageReference,omitempty"`
38
+	DockerImageReference string
36 39
 	// Metadata about this image
37
-	DockerImageMetadata DockerImage `json:"dockerImageMetadata,omitempty"`
40
+	DockerImageMetadata DockerImage
38 41
 	// This attribute conveys the version of docker metadata the JSON should be stored in, which if empty defaults to "1.0"
39
-	DockerImageMetadataVersion string `json:"dockerImageMetadataVersion,omitempty"`
42
+	DockerImageMetadataVersion string
40 43
 	// The raw JSON of the manifest
41
-	DockerImageManifest string `json:"rawManifest,omitempty"`
42
-}
43
-
44
-// ImageRepositoryList is a list of ImageRepository objects.
45
-//
46
-// ImageRepositoryList is DEPRECATED; use ImageStreamList instead.
47
-type ImageRepositoryList struct {
48
-	kapi.TypeMeta `json:",inline"`
49
-	kapi.ListMeta `json:"metadata,omitempty"`
50
-
51
-	Items []ImageRepository `json:"items"`
44
+	DockerImageManifest string
52 45
 }
53 46
 
54 47
 // ImageStreamList is a list of ImageStream objects.
55 48
 type ImageStreamList struct {
56
-	kapi.TypeMeta `json:",inline"`
57
-	kapi.ListMeta `json:"metadata,omitempty"`
49
+	kapi.TypeMeta
50
+	kapi.ListMeta
58 51
 
59
-	Items []ImageStream `json:"items"`
60
-}
61
-
62
-// ImageRepository stores a mapping of tags to images, metadata overrides that are applied
63
-// when images are tagged in a repository, and an optional reference to a Docker image
64
-// repository on a registry.
65
-//
66
-// ImageRepository is DEPRECATED; use ImageStream instead.
67
-type ImageRepository struct {
68
-	kapi.TypeMeta   `json:",inline"`
69
-	kapi.ObjectMeta `json:"metadata,omitempty"`
70
-
71
-	// Optional, if specified this repository is backed by a Docker repository on this server
72
-	DockerImageRepository string `json:"dockerImageRepository,omitempty"`
73
-	// Tags map arbitrary string values to specific image locators
74
-	Tags map[string]string `json:"tags,omitempty"`
75
-
76
-	// Status describes the current state of this repository
77
-	Status ImageRepositoryStatus `json:"status,omitempty"`
52
+	Items []ImageStream
78 53
 }
79 54
 
80 55
 // ImageStream stores a mapping of tags to images, metadata overrides that are applied
81 56
 // when images are tagged in a stream, and an optional reference to a Docker image
82 57
 // repository on a registry.
83 58
 type ImageStream struct {
84
-	kapi.TypeMeta   `json:",inline"`
85
-	kapi.ObjectMeta `json:"metadata,omitempty"`
59
+	kapi.TypeMeta
60
+	kapi.ObjectMeta
86 61
 
87 62
 	// Spec describes the desired state of this stream
88
-	Spec ImageStreamSpec `json:"spec"`
63
+	Spec ImageStreamSpec
89 64
 	// Status describes the current state of this stream
90
-	Status ImageStreamStatus `json:"status,omitempty"`
65
+	Status ImageStreamStatus
91 66
 }
92 67
 
93 68
 // ImageStreamSpec represents options for ImageStreams.
94 69
 type ImageStreamSpec struct {
95 70
 	// Optional, if specified this stream is backed by a Docker repository on this server
96
-	DockerImageRepository string `json:"dockerImageRepository"`
71
+	DockerImageRepository string
97 72
 	// Tags map arbitrary string values to specific image locators
98
-	Tags map[string]TagReference `json:"tags,omitempty"`
73
+	Tags map[string]TagReference
99 74
 }
100 75
 
101
-// TagReference allows a user to TODO.
76
+// TagReference specifies optional annotations for images using this tag and an optional reference to an ImageStreamTag, ImageStreamImage, or DockerImage this tag should track.
102 77
 type TagReference struct {
103
-	Annotations          map[string]string     `json:"annotations,omitempty"`
104
-	DockerImageReference string                `json:"dockerImageReference,omitempty"`
105
-	From                 *kapi.ObjectReference `json:"from,omitempty"`
106
-}
107
-
108
-// ImageRepositoryStatus contains information about the state of this image repository.
109
-//
110
-// ImageRepositoryStatus is DEPRECATED; use ImageStreamStatus instead.
111
-type ImageRepositoryStatus struct {
112
-	// Represents the effective location this repository may be accessed at. May be empty until the server
113
-	// determines where the repository is located
114
-	DockerImageRepository string `json:"dockerImageRepository,omitempty"`
115
-	// A historical record of images associated with each tag. The first entry in the TagEvent array is
116
-	// the currently tagged image.
117
-	Tags map[string]TagEventList `json:"tags,omitempty"`
78
+	// Optional; if specified, annotations that are applied to images retrieved via ImageStreamTags.
79
+	Annotations map[string]string
80
+	// Optional; if specified, a reference to another image that this tag should point to. Valid values are ImageStreamTag, ImageStreamImage, and DockerImage.
81
+	From *kapi.ObjectReference
118 82
 }
119 83
 
120 84
 // ImageStreamStatus contains information about the state of this image stream.
121 85
 type ImageStreamStatus struct {
122 86
 	// Represents the effective location this stream may be accessed at. May be empty until the server
123 87
 	// determines where the repository is located
124
-	DockerImageRepository string `json:"dockerImageRepository,omitempty"`
88
+	DockerImageRepository string
125 89
 	// A historical record of images associated with each tag. The first entry in the TagEvent array is
126 90
 	// the currently tagged image.
127
-	Tags map[string]TagEventList `json:"tags,omitempty"`
91
+	Tags map[string]TagEventList
128 92
 }
129 93
 
130 94
 // TagEventList contains a historical record of images associated with a tag.
131 95
 type TagEventList struct {
132
-	Items []TagEvent `json:"items"`
96
+	Items []TagEvent
133 97
 }
134 98
 
135 99
 // TagEvent is used by ImageRepositoryStatus to keep a historical record of images associated with a tag.
136 100
 type TagEvent struct {
137 101
 	// When the TagEvent was created
138
-	Created util.Time `json:"created"`
102
+	Created util.Time
139 103
 	// The string that can be used to pull this image
140
-	DockerImageReference string `json:"dockerImageReference"`
104
+	DockerImageReference string
141 105
 	// The image
142
-	Image string `json:"image"`
143
-}
144
-
145
-// ImageRepositoryMapping represents a mapping from a single tag to a Docker image as
146
-// well as the reference to the Docker image repository the image came from.
147
-//
148
-// ImageRepositoryMapping is DEPRECATED; use ImageStreamMapping instead.
149
-type ImageRepositoryMapping struct {
150
-	kapi.TypeMeta   `json:",inline"`
151
-	kapi.ObjectMeta `json:"metadata,omitempty"`
152
-
153
-	// The Docker image repository the specified image is located in
154
-	DockerImageRepository string `json:"dockerImageRepository"`
155
-	// A Docker image.
156
-	Image Image `json:"image"`
157
-	// A string value this image can be located with inside the repository.
158
-	Tag string `json:"tag"`
106
+	Image string
159 107
 }
160 108
 
161 109
 // ImageStreamMapping represents a mapping from a single tag to a Docker image as
162 110
 // well as the reference to the Docker image repository the image came from.
163 111
 type ImageStreamMapping struct {
164
-	kapi.TypeMeta   `json:",inline"`
165
-	kapi.ObjectMeta `json:"metadata,omitempty"`
112
+	kapi.TypeMeta
113
+	kapi.ObjectMeta
166 114
 
167 115
 	// The Docker image repository the specified image is located in
168 116
 	// DEPRECATED: remove once v1beta1 support is dropped
169
-	DockerImageRepository string `json:"dockerImageRepository"`
117
+	DockerImageRepository string
170 118
 	// A Docker image.
171
-	Image Image `json:"image"`
119
+	Image Image
172 120
 	// A string value this image can be located with inside the repository.
173
-	Tag string `json:"tag"`
174
-}
175
-
176
-// ImageRepositoryTag exists to allow calls to `osc get imageRepositoryTag ...` to function.
177
-//
178
-// ImageRepositoryTag is DEPRECATED; use ImageStreamTag instead.
179
-type ImageRepositoryTag struct {
180
-	Image `json:",inline"`
121
+	Tag string
181 122
 }
182 123
 
183
-// ImageStreamTag exists to allow calls to `osc get imageStreamTag ...` to function.
124
+// ImageStreamTag represents an Image that is retrieved by tag name from an ImageStream.
184 125
 type ImageStreamTag struct {
185
-	Image     `json:",inline"`
186
-	ImageName string
187
-}
126
+	kapi.TypeMeta
127
+	kapi.ObjectMeta
188 128
 
189
-// DefaultImageTag is used when an image tag is needed and the configuration does not specify a tag to use.
190
-const DefaultImageTag = "latest"
129
+	// The Image associated with the ImageStream and tag.
130
+	Image Image
131
+}
191 132
 
192
-// ImageStreamImage exists to allow calls to `osc get imageStreamImage ...` to function.
133
+// ImageStreamImage represents an Image that is retrieved by image name from an ImageStream.
193 134
 type ImageStreamImage struct {
194
-	Image     `json:",inline"`
195
-	ImageName string
135
+	kapi.TypeMeta
136
+	kapi.ObjectMeta
137
+
138
+	// The Image associated with the ImageStream and image name.
139
+	Image Image
196 140
 }
197 141
 
198 142
 // DockerImageReference points to a Docker image.
... ...
@@ -5,7 +5,6 @@ import (
5 5
 	"sort"
6 6
 
7 7
 	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
8
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1"
9 8
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
10 9
 
11 10
 	newer "github.com/openshift/origin/pkg/image/api"
... ...
@@ -154,77 +153,6 @@ func init() {
154 154
 		func(in *ImageStreamMapping, out *newer.ImageStreamMapping, s conversion.Scope) error {
155 155
 			return s.DefaultConvert(in, out, conversion.SourceToDest)
156 156
 		},
157
-
158
-		// convert internal deprecated ImageRepository objects to Stream objects
159
-		func(in *newer.ImageRepository, out *ImageStream, s conversion.Scope) error {
160
-			if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
161
-				return err
162
-			}
163
-			out.Spec.DockerImageRepository = in.DockerImageRepository
164
-			for tag, value := range in.Tags {
165
-				out.Spec.Tags = append(out.Spec.Tags, NamedTagReference{
166
-					Name: tag,
167
-					From: &v1.ObjectReference{
168
-						Name: value,
169
-					},
170
-				})
171
-			}
172
-			return s.Convert(&in.Status, &out.Status, 0)
173
-		},
174
-		func(in *ImageStream, out *newer.ImageRepository, s conversion.Scope) error {
175
-			if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
176
-				return err
177
-			}
178
-
179
-			out.DockerImageRepository = in.Spec.DockerImageRepository
180
-			if in.Spec.Tags != nil && out.Tags == nil {
181
-				out.Tags = make(map[string]string)
182
-			}
183
-			for _, namedTagReference := range in.Spec.Tags {
184
-				if namedTagReference.From != nil {
185
-					out.Tags[namedTagReference.Name] = namedTagReference.From.Name
186
-				}
187
-			}
188
-
189
-			return s.Convert(&in.Status, &out.Status, 0)
190
-		},
191
-		func(in *ImageStreamMapping, out *newer.ImageRepositoryMapping, s conversion.Scope) error {
192
-			if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
193
-				return err
194
-			}
195
-			out.Tag = in.Tag
196
-			return s.Convert(&in.Image, &out.Image, 0)
197
-		},
198
-		func(in *newer.ImageRepositoryStatus, out *ImageStreamStatus, s conversion.Scope) error {
199
-			out.DockerImageRepository = in.DockerImageRepository
200
-			return s.Convert(&in.Tags, &out.Tags, 0)
201
-		},
202
-		func(in *ImageStreamStatus, out *newer.ImageRepositoryStatus, s conversion.Scope) error {
203
-			out.DockerImageRepository = in.DockerImageRepository
204
-			out.Tags = make(map[string]newer.TagEventList)
205
-			return s.Convert(&in.Tags, &out.Tags, 0)
206
-		},
207
-		func(in *newer.ImageRepositoryMapping, out *ImageStreamMapping, s conversion.Scope) error {
208
-			return s.DefaultConvert(in, out, conversion.IgnoreMissingFields|conversion.AllowDifferentFieldTypeNames)
209
-		},
210
-		func(in *newer.ImageRepositoryList, out *ImageStreamList, s conversion.Scope) error {
211
-			if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil {
212
-				return err
213
-			}
214
-			return s.Convert(&in.Items, &out.Items, 0)
215
-		},
216
-		func(in *ImageStreamList, out *newer.ImageRepositoryList, s conversion.Scope) error {
217
-			if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil {
218
-				return err
219
-			}
220
-			return s.Convert(&in.Items, &out.Items, 0)
221
-		},
222
-		func(in *newer.ImageRepositoryTag, out *ImageStreamTag, s conversion.Scope) error {
223
-			return s.Convert(&in.Image, &out.Image, conversion.IgnoreMissingFields)
224
-		},
225
-		func(in *ImageStreamTag, out *newer.ImageRepositoryTag, s conversion.Scope) error {
226
-			return s.Convert(&in.Image, &out.Image, conversion.IgnoreMissingFields)
227
-		},
228 157
 	)
229 158
 	if err != nil {
230 159
 		// If one of the conversion functions is malformed, detect it immediately.
... ...
@@ -17,12 +17,6 @@ func init() {
17 17
 		&ImageStreamTag{},
18 18
 		&ImageStreamImage{},
19 19
 	)
20
-	// Legacy names are supported
21
-	api.Scheme.AddKnownTypeWithName("v1", "ImageRepository", &ImageStream{})
22
-	api.Scheme.AddKnownTypeWithName("v1", "ImageRepositoryList", &ImageStreamList{})
23
-	api.Scheme.AddKnownTypeWithName("v1", "ImageRepositoryMapping", &ImageStreamMapping{})
24
-	api.Scheme.AddKnownTypeWithName("v1", "ImageRepositoryTag", &ImageStreamTag{})
25
-	api.Scheme.AddKnownTypeWithName("v1", "ImageRepositoryImage", &ImageStreamImage{})
26 20
 }
27 21
 
28 22
 func (*Image) IsAnAPIObject()              {}
... ...
@@ -31,3 +25,4 @@ func (*ImageStream) IsAnAPIObject()        {}
31 31
 func (*ImageStreamList) IsAnAPIObject()    {}
32 32
 func (*ImageStreamMapping) IsAnAPIObject() {}
33 33
 func (*ImageStreamTag) IsAnAPIObject()     {}
34
+func (*ImageStreamImage) IsAnAPIObject()   {}
... ...
@@ -58,7 +58,7 @@ type ImageStreamSpec struct {
58 58
 	Tags []NamedTagReference `json:"tags,omitempty" description:"map arbitrary string values to specific image locators"`
59 59
 }
60 60
 
61
-// NamedTagReference specifies optional annotations for images using this tag and an optional reference to another ImageStreamTag or ImageStreamImage this tag should track.
61
+// NamedTagReference specifies optional annotations for images using this tag and an optional reference to an ImageStreamTag, ImageStreamImage, or DockerImage this tag should track.
62 62
 type NamedTagReference struct {
63 63
 	Name        string                `json:"name" description:"name of tag"`
64 64
 	Annotations map[string]string     `json:"annotations,omitempty" description:"annotations associated with images using this tag"`
... ...
@@ -81,7 +81,7 @@ type NamedTagEventList struct {
81 81
 	Items []TagEvent `json:"items" description:"list of tag events related to the tag"`
82 82
 }
83 83
 
84
-// TagEvent is used by ImageRepositoryStatus to keep a historical record of images associated with a tag.
84
+// TagEvent is used by ImageStreamStatus to keep a historical record of images associated with a tag.
85 85
 type TagEvent struct {
86 86
 	// When the TagEvent was created
87 87
 	Created util.Time `json:"created" description:"when the event was created"`
... ...
@@ -103,23 +103,22 @@ type ImageStreamMapping struct {
103 103
 	Tag string `json:"tag" description:"string value this image can be located with inside the repository"`
104 104
 }
105 105
 
106
-// ImageRepositoryTag exists to allow calls to `osc get imageRepositoryTag ...` to function.
107
-//
108
-// ImageRepositoryTag is DEPRECATED; use ImageStreamTag instead.
109
-type ImageRepositoryTag struct {
110
-	Image
111
-}
112
-
113
-// ImageStreamTag exists to allow calls to `osc get imageStreamTag ...` to function.
106
+// ImageStreamTag represents an Image that is retrieved by tag name from an ImageStream.
114 107
 type ImageStreamTag struct {
115
-	Image     `json:",inline"`
116
-	ImageName string `json:"imageName" description:"name of image"`
108
+	kapi.TypeMeta   `json:",inline"`
109
+	kapi.ObjectMeta `json:"metadata,omitempty"`
110
+
111
+	// The Image associated with the ImageStream and tag.
112
+	Image Image `json:"image" description:"the image associated with the ImageStream and tag"`
117 113
 }
118 114
 
119
-// ImageStreamImage exists to allow calls to `osc get imageStreamImage ...` to function.
115
+// ImageStreamImage represents an Image that is retrieved by image name from an ImageStream.
120 116
 type ImageStreamImage struct {
121
-	Image     `json:",inline"`
122
-	ImageName string `json:"imageName" description:"name of image"`
117
+	kapi.TypeMeta   `json:",inline"`
118
+	kapi.ObjectMeta `json:"metadata,omitempty"`
119
+
120
+	// The Image associated with the ImageStream and image name.
121
+	Image Image `json:"image" description:"the image associated with the ImageStream and image name"`
123 122
 }
124 123
 
125 124
 // DockerImageReference points to a Docker image.
... ...
@@ -5,7 +5,6 @@ import (
5 5
 	"sort"
6 6
 
7 7
 	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
8
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
9 8
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
10 9
 
11 10
 	newer "github.com/openshift/origin/pkg/image/api"
... ...
@@ -155,93 +154,85 @@ func init() {
155 155
 			return s.DefaultConvert(in, out, conversion.SourceToDest)
156 156
 		},
157 157
 
158
-		// convert internal deprecated ImageRepository objects to Stream objects
159
-		func(in *newer.ImageRepository, out *ImageStream, s conversion.Scope) error {
158
+		func(in *newer.ImageStream, out *ImageStream, s conversion.Scope) error {
160 159
 			if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
161 160
 				return err
162 161
 			}
163
-			out.Spec.DockerImageRepository = in.DockerImageRepository
164
-			for tag, value := range in.Tags {
165
-				out.Spec.Tags = append(out.Spec.Tags, NamedTagReference{
166
-					Name: tag,
167
-					From: &v1beta3.ObjectReference{
168
-						Name: value,
169
-					},
170
-				})
162
+			if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
163
+				return err
171 164
 			}
172 165
 			return s.Convert(&in.Status, &out.Status, 0)
173 166
 		},
174
-		func(in *ImageStream, out *newer.ImageRepository, s conversion.Scope) error {
167
+		func(in *ImageStream, out *newer.ImageStream, s conversion.Scope) error {
175 168
 			if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
176 169
 				return err
177 170
 			}
178
-
179
-			out.DockerImageRepository = in.Spec.DockerImageRepository
180
-			if in.Spec.Tags != nil && out.Tags == nil {
181
-				out.Tags = make(map[string]string)
182
-			}
183
-			for _, namedTagReference := range in.Spec.Tags {
184
-				if namedTagReference.From != nil {
185
-					out.Tags[namedTagReference.Name] = namedTagReference.From.Name
186
-				}
171
+			if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
172
+				return err
187 173
 			}
188
-
189 174
 			return s.Convert(&in.Status, &out.Status, 0)
190 175
 		},
191
-		func(in *ImageStreamMapping, out *newer.ImageRepositoryMapping, s conversion.Scope) error {
192
-			if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
176
+		func(in *newer.ImageStreamImage, out *ImageStreamImage, s conversion.Scope) error {
177
+			if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
193 178
 				return err
194 179
 			}
195
-			out.Tag = in.Tag
196
-			return s.Convert(&in.Image, &out.Image, 0)
197
-		},
198
-		func(in *newer.ImageRepositoryStatus, out *ImageStreamStatus, s conversion.Scope) error {
199
-			out.DockerImageRepository = in.DockerImageRepository
200
-			return s.Convert(&in.Tags, &out.Tags, 0)
201
-		},
202
-		func(in *ImageStreamStatus, out *newer.ImageRepositoryStatus, s conversion.Scope) error {
203
-			out.DockerImageRepository = in.DockerImageRepository
204
-			out.Tags = make(map[string]newer.TagEventList)
205
-			return s.Convert(&in.Tags, &out.Tags, 0)
206
-		},
207
-		func(in *newer.ImageRepositoryMapping, out *ImageStreamMapping, s conversion.Scope) error {
208
-			return s.DefaultConvert(in, out, conversion.IgnoreMissingFields|conversion.AllowDifferentFieldTypeNames)
209
-		},
210
-		func(in *newer.ImageRepositoryList, out *ImageStreamList, s conversion.Scope) error {
211
-			if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil {
180
+
181
+			if err := s.Convert(&in.Image.ObjectMeta, &out.ObjectMeta, 0); err != nil {
212 182
 				return err
213 183
 			}
214
-			return s.Convert(&in.Items, &out.Items, 0)
184
+
185
+			out.ImageName = in.Image.Name
186
+			out.Name = in.Name
187
+
188
+			return nil
215 189
 		},
216
-		func(in *ImageStreamList, out *newer.ImageRepositoryList, s conversion.Scope) error {
217
-			if err := s.Convert(&in.ListMeta, &out.ListMeta, 0); err != nil {
190
+		func(in *ImageStreamImage, out *newer.ImageStreamImage, s conversion.Scope) error {
191
+			imageName := in.ImageName
192
+			isiName := in.Name
193
+
194
+			if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
218 195
 				return err
219 196
 			}
220
-			return s.Convert(&in.Items, &out.Items, 0)
221
-		},
222
-		func(in *newer.ImageRepositoryTag, out *ImageStreamTag, s conversion.Scope) error {
223
-			return s.Convert(&in.Image, &out.Image, conversion.IgnoreMissingFields)
224
-		},
225
-		func(in *ImageStreamTag, out *newer.ImageRepositoryTag, s conversion.Scope) error {
226
-			return s.Convert(&in.Image, &out.Image, conversion.IgnoreMissingFields)
227
-		},
228
-		func(in *newer.ImageStream, out *ImageStream, s conversion.Scope) error {
197
+
229 198
 			if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
230 199
 				return err
231 200
 			}
232
-			if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
201
+
202
+			out.Image.Name = imageName
203
+			out.Name = isiName
204
+
205
+			return nil
206
+		},
207
+		func(in *newer.ImageStreamTag, out *ImageStreamTag, s conversion.Scope) error {
208
+			if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
233 209
 				return err
234 210
 			}
235
-			return s.Convert(&in.Status, &out.Status, 0)
211
+
212
+			if err := s.Convert(&in.Image.ObjectMeta, &out.ObjectMeta, 0); err != nil {
213
+				return err
214
+			}
215
+
216
+			out.ImageName = in.Image.Name
217
+			out.Name = in.Name
218
+
219
+			return nil
236 220
 		},
237
-		func(in *ImageStream, out *newer.ImageStream, s conversion.Scope) error {
238
-			if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
221
+		func(in *ImageStreamTag, out *newer.ImageStreamTag, s conversion.Scope) error {
222
+			imageName := in.ImageName
223
+			istName := in.Name
224
+
225
+			if err := s.Convert(&in.Image, &out.Image, 0); err != nil {
239 226
 				return err
240 227
 			}
241
-			if err := s.Convert(&in.Spec, &out.Spec, 0); err != nil {
228
+
229
+			if err := s.Convert(&in.ObjectMeta, &out.ObjectMeta, 0); err != nil {
242 230
 				return err
243 231
 			}
244
-			return s.Convert(&in.Status, &out.Status, 0)
232
+
233
+			out.Image.Name = imageName
234
+			out.Name = istName
235
+
236
+			return nil
245 237
 		},
246 238
 	)
247 239
 	if err != nil {
... ...
@@ -17,12 +17,6 @@ func init() {
17 17
 		&ImageStreamTag{},
18 18
 		&ImageStreamImage{},
19 19
 	)
20
-	// Legacy names are supported
21
-	api.Scheme.AddKnownTypeWithName("v1beta3", "ImageRepository", &ImageStream{})
22
-	api.Scheme.AddKnownTypeWithName("v1beta3", "ImageRepositoryList", &ImageStreamList{})
23
-	api.Scheme.AddKnownTypeWithName("v1beta3", "ImageRepositoryMapping", &ImageStreamMapping{})
24
-	api.Scheme.AddKnownTypeWithName("v1beta3", "ImageRepositoryTag", &ImageStreamTag{})
25
-	api.Scheme.AddKnownTypeWithName("v1beta3", "ImageRepositoryImage", &ImageStreamImage{})
26 20
 }
27 21
 
28 22
 func (*Image) IsAnAPIObject()              {}
... ...
@@ -58,7 +58,7 @@ type ImageStreamSpec struct {
58 58
 	Tags []NamedTagReference `json:"tags,omitempty"`
59 59
 }
60 60
 
61
-// NamedTagReference allows a user to TODO.
61
+// NamedTagReference specifies optional annotations for images using this tag and an optional reference to an ImageStreamTag, ImageStreamImage, or DockerImage this tag should track.
62 62
 type NamedTagReference struct {
63 63
 	Name        string                `json:"name"`
64 64
 	Annotations map[string]string     `json:"annotations,omitempty"`
... ...
@@ -103,20 +103,13 @@ type ImageStreamMapping struct {
103 103
 	Tag string `json:"tag"`
104 104
 }
105 105
 
106
-// ImageRepositoryTag exists to allow calls to `osc get imageRepositoryTag ...` to function.
107
-//
108
-// ImageRepositoryTag is DEPRECATED; use ImageStreamTag instead.
109
-type ImageRepositoryTag struct {
110
-	Image
111
-}
112
-
113
-// ImageStreamTag exists to allow calls to `osc get imageStreamTag ...` to function.
106
+// ImageStreamTag represents an Image that is retrieved by tag name from an ImageStream.
114 107
 type ImageStreamTag struct {
115 108
 	Image     `json:",inline"`
116 109
 	ImageName string `json:"imageName"`
117 110
 }
118 111
 
119
-// ImageStreamImage exists to allow calls to `osc get imageStreamImage ...` to function.
112
+// ImageStreamImage represents an Image that is retrieved by image name from an ImageStream.
120 113
 type ImageStreamImage struct {
121 114
 	Image     `json:",inline"`
122 115
 	ImageName string `json:"imageName"`
... ...
@@ -75,8 +75,12 @@ func ValidateImageStream(stream *api.ImageStream) fielderrors.ValidationErrorLis
75 75
 		}
76 76
 	}
77 77
 	for tag, tagRef := range stream.Spec.Tags {
78
-		if len(tagRef.DockerImageReference) > 0 && tagRef.From != nil {
79
-			result = append(result, fielderrors.NewFieldInvalid(fmt.Sprintf("spec.tags[%s]", tag), "", "only 1 of dockerImageReference or from may be set"))
78
+		if tagRef.From != nil {
79
+			switch tagRef.From.Kind {
80
+			case "DockerImage", "ImageStreamImage", "ImageStreamTag":
81
+			default:
82
+				result = append(result, fielderrors.NewFieldInvalid(fmt.Sprintf("spec.tags[%s].from.kind", tag), tagRef.From.Kind, "valid values are 'DockerImage', 'ImageStreamImage', 'ImageStreamTag'"))
83
+			}
80 84
 		}
81 85
 	}
82 86
 	for tag, history := range stream.Status.Tags {
... ...
@@ -249,19 +249,6 @@ func TestValidateImageStream(t *testing.T) {
249 249
 				fielderrors.NewFieldInvalid("spec.dockerImageRepository", "a-|///bbb", "the docker pull spec \"a-|///bbb\" must be two or three segments separated by slashes"),
250 250
 			},
251 251
 		},
252
-		"both dockerImageReference and from set": {
253
-			namespace: "namespace",
254
-			name:      "foo",
255
-			specTags: map[string]api.TagReference{
256
-				"tag": {
257
-					DockerImageReference: "abc",
258
-					From:                 &kapi.ObjectReference{},
259
-				},
260
-			},
261
-			expected: fielderrors.ValidationErrorList{
262
-				fielderrors.NewFieldInvalid("spec.tags[tag]", "", "only 1 of dockerImageReference or from may be set"),
263
-			},
264
-		},
265 252
 		"status tag missing dockerImageReference": {
266 253
 			namespace: "namespace",
267 254
 			name:      "foo",
... ...
@@ -284,7 +271,10 @@ func TestValidateImageStream(t *testing.T) {
284 284
 			name:      "foo",
285 285
 			specTags: map[string]api.TagReference{
286 286
 				"tag": {
287
-					DockerImageReference: "abc",
287
+					From: &kapi.ObjectReference{
288
+						Kind: "DockerImage",
289
+						Name: "abc",
290
+					},
288 291
 				},
289 292
 				"other": {
290 293
 					From: &kapi.ObjectReference{
... ...
@@ -67,7 +67,7 @@ func (c *ImportController) Next(stream *api.ImageStream) error {
67 67
 
68 68
 	imageToTag := make(map[string][]string)
69 69
 	for tag, image := range tags {
70
-		if specTag, ok := stream.Spec.Tags[tag]; ok && (len(specTag.DockerImageReference) != 0 || specTag.From != nil) {
70
+		if specTag, ok := stream.Spec.Tags[tag]; ok && specTag.From != nil {
71 71
 			// spec tag is set to track another tag - do not import
72 72
 			continue
73 73
 		}
... ...
@@ -248,17 +248,27 @@ func TestControllerWithSpecTags(t *testing.T) {
248 248
 		"no tracking": {
249 249
 			expectUpdate: true,
250 250
 		},
251
-		"dockerImageReference": {
252
-			dockerImageReference: "some/repo",
253
-			expectUpdate:         false,
251
+		"docker image": {
252
+			from: &kapi.ObjectReference{
253
+				Kind: "DockerImage",
254
+				Name: "some/repo",
255
+			},
256
+			expectUpdate: false,
254 257
 		},
255
-		"from tracking": {
258
+		"from image stream tag": {
256 259
 			from: &kapi.ObjectReference{
257 260
 				Kind: "ImageStreamTag",
258 261
 				Name: "2.0",
259 262
 			},
260 263
 			expectUpdate: false,
261 264
 		},
265
+		"from image stream image": {
266
+			from: &kapi.ObjectReference{
267
+				Kind: "ImageStreamImage",
268
+				Name: "foo@sha256:1234",
269
+			},
270
+			expectUpdate: false,
271
+		},
262 272
 	}
263 273
 
264 274
 	for name, test := range tests {
... ...
@@ -281,8 +291,7 @@ func TestControllerWithSpecTags(t *testing.T) {
281 281
 				DockerImageRepository: "foo/bar",
282 282
 				Tags: map[string]api.TagReference{
283 283
 					api.DefaultImageTag: {
284
-						DockerImageReference: test.dockerImageReference,
285
-						From:                 test.from,
284
+						From: test.from,
286 285
 					},
287 286
 				},
288 287
 			},
289 288
deleted file mode 100644
... ...
@@ -1,93 +0,0 @@
1
-package imagerepository
2
-
3
-import (
4
-	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
5
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
6
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
7
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
8
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
9
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
10
-
11
-	"github.com/openshift/origin/pkg/image/api"
12
-)
13
-
14
-// Registry is an interface for things that know how to store ImageRepository objects.
15
-type Registry interface {
16
-	// ListImageRepositories obtains a list of image repositories that match a selector.
17
-	ListImageRepositories(ctx kapi.Context, selector labels.Selector) (*api.ImageRepositoryList, error)
18
-	// GetImageRepository retrieves a specific image repository.
19
-	GetImageRepository(ctx kapi.Context, id string) (*api.ImageRepository, error)
20
-	// CreateImageRepository creates a new image repository.
21
-	CreateImageRepository(ctx kapi.Context, repo *api.ImageRepository) error
22
-	// UpdateImageRepository updates an image repository.
23
-	UpdateImageRepository(ctx kapi.Context, repo *api.ImageRepository) error
24
-	// UpdateImageRepository updates an image repository's status.
25
-	UpdateImageRepositoryStatus(ctx kapi.Context, repo *api.ImageRepository) error
26
-	// DeleteImageRepository deletes an image repository.
27
-	DeleteImageRepository(ctx kapi.Context, id string) error
28
-	// WatchImageRepositories watches for new/changed/deleted image repositories.
29
-	WatchImageRepositories(ctx kapi.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
30
-}
31
-
32
-// Storage is an interface for a standard REST Storage backend
33
-type Storage interface {
34
-	rest.GracefulDeleter
35
-	rest.Lister
36
-	rest.Getter
37
-	rest.Watcher
38
-
39
-	Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error)
40
-	Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error)
41
-}
42
-
43
-// storage puts strong typing around storage calls
44
-type storage struct {
45
-	Storage
46
-	status rest.Updater
47
-}
48
-
49
-// NewRegistry returns a new Registry interface for the given Storage. Any mismatched
50
-// types will panic.
51
-func NewRegistry(s Storage, status rest.Updater) Registry {
52
-	return &storage{s, status}
53
-}
54
-
55
-func (s *storage) ListImageRepositories(ctx kapi.Context, label labels.Selector) (*api.ImageRepositoryList, error) {
56
-	obj, err := s.List(ctx, label, fields.Everything())
57
-	if err != nil {
58
-		return nil, err
59
-	}
60
-	return obj.(*api.ImageRepositoryList), nil
61
-}
62
-
63
-func (s *storage) GetImageRepository(ctx kapi.Context, imageRepositoryID string) (*api.ImageRepository, error) {
64
-	obj, err := s.Get(ctx, imageRepositoryID)
65
-	if err != nil {
66
-		return nil, err
67
-	}
68
-	return obj.(*api.ImageRepository), nil
69
-}
70
-
71
-func (s *storage) CreateImageRepository(ctx kapi.Context, imageRepository *api.ImageRepository) error {
72
-	_, err := s.Create(ctx, imageRepository)
73
-	return err
74
-}
75
-
76
-func (s *storage) UpdateImageRepository(ctx kapi.Context, imageRepository *api.ImageRepository) error {
77
-	_, _, err := s.Update(ctx, imageRepository)
78
-	return err
79
-}
80
-
81
-func (s *storage) UpdateImageRepositoryStatus(ctx kapi.Context, imageRepository *api.ImageRepository) error {
82
-	_, _, err := s.status.Update(ctx, imageRepository)
83
-	return err
84
-}
85
-
86
-func (s *storage) DeleteImageRepository(ctx kapi.Context, imageRepositoryID string) error {
87
-	_, err := s.Delete(ctx, imageRepositoryID, nil)
88
-	return err
89
-}
90
-
91
-func (s *storage) WatchImageRepositories(ctx kapi.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
92
-	return s.Watch(ctx, label, field, resourceVersion)
93
-}
94 1
deleted file mode 100644
... ...
@@ -1,137 +0,0 @@
1
-package imagerepository
2
-
3
-import (
4
-	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
5
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
6
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
7
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
8
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
9
-	"github.com/openshift/origin/pkg/image/api"
10
-	"github.com/openshift/origin/pkg/image/registry/imagestream"
11
-)
12
-
13
-type REST struct {
14
-	imageStreamRegistry imagestream.Registry
15
-}
16
-
17
-func NewREST(isr imagestream.Registry) (*REST, *StatusREST) {
18
-	return &REST{imageStreamRegistry: isr}, &StatusREST{imageStreamRegistry: isr}
19
-}
20
-
21
-// New returns a new object
22
-func (r *REST) New() runtime.Object {
23
-	return &api.ImageRepository{}
24
-}
25
-
26
-// NewList returns a new list object
27
-func (r *REST) NewList() runtime.Object {
28
-	return &api.ImageRepositoryList{}
29
-}
30
-
31
-// List obtains a list of image repositories with labels that match selector.
32
-func (r *REST) List(ctx kapi.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) {
33
-	imageStreamList, err := r.imageStreamRegistry.ListImageStreams(ctx, label)
34
-	if err != nil {
35
-		return nil, err
36
-	}
37
-	imageRepoList := api.ImageRepositoryList{}
38
-	if err := kapi.Scheme.Convert(imageStreamList, &imageRepoList); err != nil {
39
-		return nil, err
40
-	}
41
-	return &imageRepoList, nil
42
-}
43
-
44
-// Watch begins watching for new, changed, or deleted image repositories.
45
-func (r *REST) Watch(ctx kapi.Context, label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
46
-	return r.imageStreamRegistry.WatchImageStreams(ctx, label, field, resourceVersion)
47
-}
48
-
49
-// Get gets a specific image repository specified by its ID.
50
-func (r *REST) Get(ctx kapi.Context, name string) (runtime.Object, error) {
51
-	stream, err := r.imageStreamRegistry.GetImageStream(ctx, name)
52
-	if err != nil {
53
-		return nil, err
54
-	}
55
-
56
-	repo := api.ImageRepository{}
57
-	if err := kapi.Scheme.Convert(stream, &repo); err != nil {
58
-		return nil, err
59
-	}
60
-
61
-	return &repo, nil
62
-}
63
-
64
-// Create creates a image repository based on a specification.
65
-func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) {
66
-	repo := obj.(*api.ImageRepository)
67
-	var stream api.ImageStream
68
-	if err := kapi.Scheme.Convert(repo, &stream); err != nil {
69
-		return nil, err
70
-	}
71
-
72
-	createdStream, err := r.imageStreamRegistry.CreateImageStream(ctx, &stream)
73
-	if err != nil {
74
-		return nil, err
75
-	}
76
-
77
-	createdRepo := api.ImageRepository{}
78
-	if err := kapi.Scheme.Convert(createdStream, &createdRepo); err != nil {
79
-		return nil, err
80
-	}
81
-
82
-	return &createdRepo, nil
83
-}
84
-
85
-// Update changes a image repository specification.
86
-func (r *REST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
87
-	repo := obj.(*api.ImageRepository)
88
-	var stream api.ImageStream
89
-	if err := kapi.Scheme.Convert(repo, &stream); err != nil {
90
-		return nil, false, err
91
-	}
92
-
93
-	updatedStream, err := r.imageStreamRegistry.UpdateImageStream(ctx, &stream)
94
-	if err != nil {
95
-		return nil, false, err
96
-	}
97
-
98
-	updatedRepo := api.ImageRepository{}
99
-	if err := kapi.Scheme.Convert(updatedStream, &updatedRepo); err != nil {
100
-		return nil, false, err
101
-	}
102
-	return &updatedRepo, false, err
103
-}
104
-
105
-// Delete deletes an existing image repository specified by its ID.
106
-func (r *REST) Delete(ctx kapi.Context, name string, options *kapi.DeleteOptions) (runtime.Object, error) {
107
-	return r.imageStreamRegistry.DeleteImageStream(ctx, name)
108
-}
109
-
110
-// StatusREST implements the REST endpoint for changing the status of an image repository.
111
-type StatusREST struct {
112
-	imageStreamRegistry imagestream.Registry
113
-}
114
-
115
-func (r *StatusREST) New() runtime.Object {
116
-	return &api.ImageRepository{}
117
-}
118
-
119
-// Update alters the status subset of an object.
120
-func (r *StatusREST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
121
-	repo := obj.(*api.ImageRepository)
122
-	var stream api.ImageStream
123
-	if err := kapi.Scheme.Convert(&repo, &stream); err != nil {
124
-		return nil, false, err
125
-	}
126
-
127
-	updatedStream, err := r.imageStreamRegistry.UpdateImageStreamStatus(ctx, &stream)
128
-	if err != nil {
129
-		return nil, false, err
130
-	}
131
-
132
-	updatedRepo := api.ImageRepository{}
133
-	if err := kapi.Scheme.Convert(updatedStream, &updatedRepo); err != nil {
134
-		return nil, false, err
135
-	}
136
-	return &updatedRepo, false, err
137
-}
138 1
deleted file mode 100644
... ...
@@ -1,314 +0,0 @@
1
-package imagerepository
2
-
3
-import (
4
-	"fmt"
5
-	"strings"
6
-	"testing"
7
-
8
-	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
9
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
10
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
11
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
12
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
13
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
14
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
15
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
16
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
17
-	"github.com/coreos/go-etcd/etcd"
18
-
19
-	"github.com/openshift/origin/pkg/api/latest"
20
-	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
21
-	"github.com/openshift/origin/pkg/authorization/registry/subjectaccessreview"
22
-	"github.com/openshift/origin/pkg/image/api"
23
-	"github.com/openshift/origin/pkg/image/registry/imagestream"
24
-	imagestreametcd "github.com/openshift/origin/pkg/image/registry/imagestream/etcd"
25
-)
26
-
27
-var testDefaultRegistry = imagestream.DefaultRegistryFunc(func() (string, bool) { return "", false })
28
-
29
-type fakeSubjectAccessReviewRegistry struct {
30
-}
31
-
32
-var _ subjectaccessreview.Registry = &fakeSubjectAccessReviewRegistry{}
33
-
34
-func (f *fakeSubjectAccessReviewRegistry) CreateSubjectAccessReview(ctx kapi.Context, subjectAccessReview *authorizationapi.SubjectAccessReview) (*authorizationapi.SubjectAccessReviewResponse, error) {
35
-	return nil, nil
36
-}
37
-
38
-type fakeUser struct {
39
-}
40
-
41
-var _ user.Info = &fakeUser{}
42
-
43
-func (u *fakeUser) GetName() string {
44
-	return "user"
45
-}
46
-
47
-func (u *fakeUser) GetUID() string {
48
-	return "uid"
49
-}
50
-
51
-func (u *fakeUser) GetGroups() []string {
52
-	return []string{"group1"}
53
-}
54
-
55
-func newTestHelpers(t *testing.T) (*tools.FakeEtcdClient, tools.EtcdHelper, *REST, *StatusREST) {
56
-	fakeEtcdClient := tools.NewFakeEtcdClient(t)
57
-	fakeEtcdClient.TestIndex = true
58
-	helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec, etcdtest.PathPrefix())
59
-	imageStreamStorage, imageStreamStatusStorage := imagestreametcd.NewREST(helper, testDefaultRegistry, &fakeSubjectAccessReviewRegistry{})
60
-	imageStreamRegistry := imagestream.NewRegistry(imageStreamStorage, imageStreamStatusStorage)
61
-	storage, statusStorage := NewREST(imageStreamRegistry)
62
-	return fakeEtcdClient, helper, storage, statusStorage
63
-}
64
-
65
-func TestListImageRepositories(t *testing.T) {
66
-	fakeEtcdClient, _, rest, _ := newTestHelpers(t)
67
-
68
-	fakeEtcdClient.ChangeIndex = 1
69
-	fakeEtcdClient.Data["/imagerepositories/default"] = tools.EtcdResponseWithError{
70
-		R: &etcd.Response{},
71
-		E: fakeEtcdClient.NewError(tools.EtcdErrorCodeNotFound),
72
-	}
73
-
74
-	obj, err := rest.List(kapi.NewDefaultContext(), labels.Everything(), fields.Everything())
75
-	if err != nil {
76
-		t.Fatalf("unexpected error: %v", err)
77
-	}
78
-	if len(obj.(*api.ImageRepositoryList).Items) != 0 {
79
-		t.Errorf("Unexpected non-empty list: %#v", obj)
80
-	}
81
-	if obj.(*api.ImageRepositoryList).ResourceVersion != "1" {
82
-		t.Errorf("Unexpected resource version: %#v", obj)
83
-	}
84
-}
85
-
86
-func TestListImageRepositoriesError(t *testing.T) {
87
-	fakeEtcdClient, _, rest, _ := newTestHelpers(t)
88
-
89
-	fakeEtcdClient.Err = fmt.Errorf("foo")
90
-
91
-	obj, err := rest.List(kapi.NewDefaultContext(), labels.Everything(), fields.Everything())
92
-	if err != fakeEtcdClient.Err {
93
-		t.Errorf("Expected %v, Got %v", fakeEtcdClient.Err, err)
94
-	}
95
-	if obj != nil {
96
-		t.Errorf("Unexpected non-nil list: %#v", obj)
97
-	}
98
-}
99
-
100
-func TestListImageRepositoriesPopulatedList(t *testing.T) {
101
-	fakeEtcdClient, _, rest, _ := newTestHelpers(t)
102
-
103
-	fakeEtcdClient.Data["/imagerepositories/default"] = tools.EtcdResponseWithError{
104
-		R: &etcd.Response{
105
-			Node: &etcd.Node{
106
-				Nodes: []*etcd.Node{
107
-					{Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: "foo"}})},
108
-					{Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: "bar"}})},
109
-				},
110
-			},
111
-		},
112
-	}
113
-
114
-	obj, err := rest.List(kapi.NewDefaultContext(), labels.Everything(), fields.Everything())
115
-	if err != nil {
116
-		t.Fatalf("unexpected error: %v", err)
117
-	}
118
-
119
-	list := obj.(*api.ImageRepositoryList)
120
-	expected := api.ImageRepositoryList{
121
-		Items: []api.ImageRepository{
122
-			{ObjectMeta: kapi.ObjectMeta{Name: "foo"}},
123
-			{ObjectMeta: kapi.ObjectMeta{Name: "bar"}},
124
-		},
125
-	}
126
-	if !kapi.Semantic.DeepEqual(list, &expected) {
127
-		t.Errorf("unexpected list - diff: %s", util.ObjectDiff(expected, list))
128
-	}
129
-}
130
-
131
-func TestGetImageStreamError(t *testing.T) {
132
-	fakeEtcdClient, _, rest, _ := newTestHelpers(t)
133
-	fakeEtcdClient.Err = fmt.Errorf("foo")
134
-
135
-	obj, err := rest.Get(kapi.NewDefaultContext(), "image1")
136
-	if err != fakeEtcdClient.Err {
137
-		t.Errorf("Expected %#v, got %#v", fakeEtcdClient.Err, err)
138
-	}
139
-	if obj != nil {
140
-		t.Errorf("Unexpected non-nil obj: %#v", obj)
141
-	}
142
-}
143
-
144
-func TestGetImageRepositoryOK(t *testing.T) {
145
-	fakeEtcdClient, _, rest, _ := newTestHelpers(t)
146
-
147
-	streamName := "foo"
148
-	fakeEtcdClient.Set("/imagerepositories/default/foo", runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: streamName}}), 0)
149
-
150
-	obj, err := rest.Get(kapi.NewDefaultContext(), streamName)
151
-	if err != nil {
152
-		t.Fatalf("Unexpected non-nil error: %#v", err)
153
-	}
154
-	if obj == nil {
155
-		t.Fatalf("Unexpected nil stream")
156
-	}
157
-	repo := obj.(*api.ImageRepository)
158
-	if e, a := streamName, repo.Name; e != a {
159
-		t.Errorf("Expected %#v, got %#v", e, a)
160
-	}
161
-}
162
-
163
-func TestCreateImageRepositoryOK(t *testing.T) {
164
-	_, helper, rest, _ := newTestHelpers(t)
165
-
166
-	repo := &api.ImageRepository{ObjectMeta: kapi.ObjectMeta{Name: "foo"}}
167
-	ctx := kapi.WithUser(kapi.NewDefaultContext(), &fakeUser{})
168
-	_, err := rest.Create(ctx, repo)
169
-	if err != nil {
170
-		t.Fatalf("Unexpected non-nil error: %#v", err)
171
-	}
172
-
173
-	actual := &api.ImageRepository{}
174
-	if err := helper.ExtractObj("/imagerepositories/default/foo", actual, false); err != nil {
175
-		t.Fatalf("unexpected extraction error: %v", err)
176
-	}
177
-	if actual.Name != repo.Name {
178
-		t.Errorf("unexpected repo: %#v", actual)
179
-	}
180
-	if len(actual.UID) == 0 {
181
-		t.Errorf("expected repo UID to be set: %#v", actual)
182
-	}
183
-	if actual.CreationTimestamp.IsZero() {
184
-		t.Error("Unexpected zero CreationTimestamp")
185
-	}
186
-	if actual.DockerImageRepository != "" {
187
-		t.Errorf("unexpected DockerImageRepository: %#v", repo)
188
-	}
189
-}
190
-
191
-func TestCreateRegistryErrorSaving(t *testing.T) {
192
-	fakeEtcdClient, _, rest, _ := newTestHelpers(t)
193
-	fakeEtcdClient.Err = fmt.Errorf("foo")
194
-
195
-	ctx := kapi.WithUser(kapi.NewDefaultContext(), &fakeUser{})
196
-	_, err := rest.Create(ctx, &api.ImageRepository{ObjectMeta: kapi.ObjectMeta{Name: "foo"}})
197
-	if err != fakeEtcdClient.Err {
198
-		t.Fatalf("Unexpected non-nil error: %#v", err)
199
-	}
200
-}
201
-
202
-func TestUpdateImageRepositoryMissingID(t *testing.T) {
203
-	_, _, rest, _ := newTestHelpers(t)
204
-	obj, created, err := rest.Update(kapi.NewDefaultContext(), &api.ImageRepository{})
205
-	if obj != nil || created {
206
-		t.Fatalf("Expected nil, got %v", obj)
207
-	}
208
-	if strings.Index(err.Error(), "Name parameter required") == -1 {
209
-		t.Errorf("Expected 'Name parameter required' error, got %v", err)
210
-	}
211
-}
212
-
213
-func TestUpdateImageRepositoryErrorSaving(t *testing.T) {
214
-	fakeEtcdClient, _, rest, _ := newTestHelpers(t)
215
-	fakeEtcdClient.Err = fmt.Errorf("foo")
216
-
217
-	_, created, err := rest.Update(kapi.NewDefaultContext(), &api.ImageRepository{ObjectMeta: kapi.ObjectMeta{Name: "bar"}})
218
-	if err != fakeEtcdClient.Err || created {
219
-		t.Fatalf("Unexpected non-nil error: %#v", err)
220
-	}
221
-}
222
-
223
-func TestUpdateImageRepositoryOK(t *testing.T) {
224
-	fakeEtcdClient, _, rest, _ := newTestHelpers(t)
225
-	fakeEtcdClient.Data["/imagerepositories/default/bar"] = tools.EtcdResponseWithError{
226
-		R: &etcd.Response{
227
-			Node: &etcd.Node{
228
-				Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{
229
-					ObjectMeta: kapi.ObjectMeta{Name: "bar", Namespace: "default"},
230
-				}),
231
-				ModifiedIndex: 2,
232
-			},
233
-		},
234
-	}
235
-
236
-	ctx := kapi.WithUser(kapi.NewDefaultContext(), &fakeUser{})
237
-	obj, created, err := rest.Update(ctx, &api.ImageRepository{ObjectMeta: kapi.ObjectMeta{Name: "bar", ResourceVersion: "1"}})
238
-	if !errors.IsConflict(err) {
239
-		t.Fatalf("unexpected non-error: %v", err)
240
-	}
241
-	obj, created, err = rest.Update(ctx, &api.ImageRepository{ObjectMeta: kapi.ObjectMeta{Name: "bar", ResourceVersion: "2"}})
242
-	if err != nil || created {
243
-		t.Fatalf("Unexpected non-nil error: %#v", err)
244
-	}
245
-	repo, ok := obj.(*api.ImageRepository)
246
-	if !ok {
247
-		t.Errorf("Expected image repository, got %#v", obj)
248
-	}
249
-	if repo.Name != "bar" {
250
-		t.Errorf("Unexpected repo returned: %#v", repo)
251
-	}
252
-}
253
-
254
-func TestDeleteImageRepository(t *testing.T) {
255
-	fakeEtcdClient, _, rest, _ := newTestHelpers(t)
256
-	fakeEtcdClient.Data["/imagerepositories/default/foo"] = tools.EtcdResponseWithError{
257
-		R: &etcd.Response{
258
-			Node: &etcd.Node{
259
-				Value: runtime.EncodeOrDie(latest.Codec, &api.ImageRepository{
260
-					ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "default"},
261
-				}),
262
-				ModifiedIndex: 2,
263
-			},
264
-		},
265
-	}
266
-
267
-	obj, err := rest.Delete(kapi.NewDefaultContext(), "foo", nil)
268
-	if err != nil {
269
-		t.Fatalf("Unexpected non-nil error: %#v", err)
270
-	}
271
-	status, ok := obj.(*kapi.Status)
272
-	if !ok {
273
-		t.Fatalf("Expected status, got %#v", obj)
274
-	}
275
-	if status.Status != kapi.StatusSuccess {
276
-		t.Errorf("Expected status=success, got %#v", status)
277
-	}
278
-}
279
-
280
-func TestUpdateImageRepositoryConflictingNamespace(t *testing.T) {
281
-	fakeEtcdClient, _, rest, _ := newTestHelpers(t)
282
-	fakeEtcdClient.Data["/imagerepositories/legal-name/bar"] = tools.EtcdResponseWithError{
283
-		R: &etcd.Response{
284
-			Node: &etcd.Node{
285
-				Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{
286
-					ObjectMeta: kapi.ObjectMeta{Name: "bar", Namespace: "default"},
287
-				}),
288
-				ModifiedIndex: 2,
289
-			},
290
-		},
291
-	}
292
-
293
-	ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "legal-name"), &fakeUser{})
294
-	obj, created, err := rest.Update(ctx, &api.ImageRepository{
295
-		ObjectMeta: kapi.ObjectMeta{Name: "bar", Namespace: "some-value", ResourceVersion: "2"},
296
-	})
297
-
298
-	if obj != nil || created {
299
-		t.Error("Expected a nil obj, but we got a value")
300
-	}
301
-
302
-	checkExpectedNamespaceError(t, err)
303
-}
304
-
305
-func checkExpectedNamespaceError(t *testing.T, err error) {
306
-	expectedError := "the namespace of the provided object does not match the namespace sent on the request"
307
-	if err == nil {
308
-		t.Fatalf("Expected '" + expectedError + "', but we didn't get one")
309
-	}
310
-	if !strings.Contains(err.Error(), expectedError) {
311
-		t.Errorf("Expected '"+expectedError+"' error, got '%v'", err.Error())
312
-	}
313
-
314
-}
315 1
deleted file mode 100644
... ...
@@ -1,29 +0,0 @@
1
-package imagerepositorymapping
2
-
3
-import (
4
-	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
5
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
6
-	"github.com/openshift/origin/pkg/image/api"
7
-	"github.com/openshift/origin/pkg/image/registry/imagestreammapping"
8
-)
9
-
10
-type REST struct {
11
-	imageStreamMappingRegistry imagestreammapping.Registry
12
-}
13
-
14
-func NewREST(r imagestreammapping.Registry) *REST {
15
-	return &REST{r}
16
-}
17
-
18
-func (r *REST) New() runtime.Object {
19
-	return &api.ImageRepositoryMapping{}
20
-}
21
-
22
-func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) {
23
-	var mapping api.ImageStreamMapping
24
-	irm := obj.(*api.ImageRepositoryMapping)
25
-	if err := kapi.Scheme.Convert(irm, &mapping); err != nil {
26
-		return nil, err
27
-	}
28
-	return r.imageStreamMappingRegistry.CreateImageStreamMapping(ctx, &mapping)
29
-}
30 1
deleted file mode 100644
... ...
@@ -1,568 +0,0 @@
1
-package imagerepositorymapping
2
-
3
-import (
4
-	"fmt"
5
-	"reflect"
6
-	"strings"
7
-	"testing"
8
-
9
-	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
10
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
11
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
12
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
13
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
14
-	"github.com/coreos/go-etcd/etcd"
15
-
16
-	"github.com/openshift/origin/pkg/api/latest"
17
-	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
18
-	"github.com/openshift/origin/pkg/authorization/registry/subjectaccessreview"
19
-	"github.com/openshift/origin/pkg/image/api"
20
-	"github.com/openshift/origin/pkg/image/registry/image"
21
-	imageetcd "github.com/openshift/origin/pkg/image/registry/image/etcd"
22
-	"github.com/openshift/origin/pkg/image/registry/imagestream"
23
-	imagestreametcd "github.com/openshift/origin/pkg/image/registry/imagestream/etcd"
24
-	"github.com/openshift/origin/pkg/image/registry/imagestreammapping"
25
-)
26
-
27
-var testDefaultRegistry = imagestream.DefaultRegistryFunc(func() (string, bool) { return "defaultregistry:5000", true })
28
-
29
-type fakeSubjectAccessReviewRegistry struct {
30
-}
31
-
32
-var _ subjectaccessreview.Registry = &fakeSubjectAccessReviewRegistry{}
33
-
34
-func (f *fakeSubjectAccessReviewRegistry) CreateSubjectAccessReview(ctx kapi.Context, subjectAccessReview *authorizationapi.SubjectAccessReview) (*authorizationapi.SubjectAccessReviewResponse, error) {
35
-	return nil, nil
36
-}
37
-
38
-func setup(t *testing.T) (*tools.FakeEtcdClient, tools.EtcdHelper, *REST) {
39
-	fakeEtcdClient := tools.NewFakeEtcdClient(t)
40
-	fakeEtcdClient.TestIndex = true
41
-	helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec, etcdtest.PathPrefix())
42
-	imageStorage := imageetcd.NewREST(helper)
43
-	imageRegistry := image.NewRegistry(imageStorage)
44
-	imageStreamStorage, imageStreamStatus := imagestreametcd.NewREST(helper, testDefaultRegistry, &fakeSubjectAccessReviewRegistry{})
45
-	imageStreamRegistry := imagestream.NewRegistry(imageStreamStorage, imageStreamStatus)
46
-	imageStreamMappingStorage := imagestreammapping.NewREST(imageRegistry, imageStreamRegistry)
47
-	imageStreamMappingRegistry := imagestreammapping.NewRegistry(imageStreamMappingStorage)
48
-	storage := NewREST(imageStreamMappingRegistry)
49
-	return fakeEtcdClient, helper, storage
50
-}
51
-
52
-func validImageRepository() *api.ImageRepository {
53
-	return &api.ImageRepository{
54
-		ObjectMeta: kapi.ObjectMeta{
55
-			Name: "test",
56
-		},
57
-	}
58
-}
59
-
60
-func validNewMappingWithDockerImageRepository() *api.ImageRepositoryMapping {
61
-	return &api.ImageRepositoryMapping{
62
-		DockerImageRepository: "localhost:5000/someproject/somerepo",
63
-		Image: api.Image{
64
-			ObjectMeta: kapi.ObjectMeta{
65
-				Name: "imageID1",
66
-			},
67
-			DockerImageReference: "localhost:5000/someproject/somerepo:imageID1",
68
-			DockerImageMetadata: api.DockerImage{
69
-				Config: api.DockerConfig{
70
-					Cmd:          []string{"ls", "/"},
71
-					Env:          []string{"a=1"},
72
-					ExposedPorts: map[string]struct{}{"1234/tcp": {}},
73
-					Memory:       1234,
74
-					CPUShares:    99,
75
-					WorkingDir:   "/workingDir",
76
-				},
77
-			},
78
-		},
79
-		Tag: "latest",
80
-	}
81
-}
82
-
83
-func validNewMappingWithName() *api.ImageRepositoryMapping {
84
-	return &api.ImageRepositoryMapping{
85
-		ObjectMeta: kapi.ObjectMeta{
86
-			Namespace: "default",
87
-			Name:      "somerepo",
88
-		},
89
-		Image: api.Image{
90
-			ObjectMeta: kapi.ObjectMeta{
91
-				Name: "imageID1",
92
-			},
93
-			DockerImageReference: "localhost:5000/default/somerepo:imageID1",
94
-			DockerImageMetadata: api.DockerImage{
95
-				Config: api.DockerConfig{
96
-					Cmd:          []string{"ls", "/"},
97
-					Env:          []string{"a=1"},
98
-					ExposedPorts: map[string]struct{}{"1234/tcp": {}},
99
-					Memory:       1234,
100
-					CPUShares:    99,
101
-					WorkingDir:   "/workingDir",
102
-				},
103
-			},
104
-		},
105
-		Tag: "latest",
106
-	}
107
-}
108
-
109
-func TestCreateConflictingNamespace(t *testing.T) {
110
-	_, _, storage := setup(t)
111
-
112
-	mapping := validNewMappingWithName()
113
-	mapping.Namespace = "some-value"
114
-
115
-	obj, err := storage.Create(kapi.WithNamespace(kapi.NewContext(), "legal-name"), mapping)
116
-	expectedError := "the namespace of the provided object does not match the namespace sent on the request"
117
-	if err == nil {
118
-		t.Fatalf("Expected '" + expectedError + "', but we didn't get one")
119
-	}
120
-	if !strings.Contains(err.Error(), expectedError) {
121
-		t.Errorf("Expected '"+expectedError+"' error, got '%v'", err.Error())
122
-	}
123
-	if obj.(*kapi.Status) != nil {
124
-		t.Errorf("Expected a nil obj, but we got a value: %#v", obj)
125
-	}
126
-}
127
-
128
-func TestCreateErrorListingImageStreams(t *testing.T) {
129
-	fakeEtcdClient, _, storage := setup(t)
130
-	fakeEtcdClient.Data["/imagerepositories/default"] = tools.EtcdResponseWithError{
131
-		R: &etcd.Response{
132
-			Node: nil,
133
-		},
134
-		E: fmt.Errorf("123"),
135
-	}
136
-
137
-	obj, err := storage.Create(kapi.NewDefaultContext(), validNewMappingWithDockerImageRepository())
138
-	if obj.(*kapi.Status) != nil {
139
-		t.Fatalf("Unexpected non-nil obj %#v", obj)
140
-	}
141
-	if err == nil {
142
-		t.Fatal("Unexpected nil err")
143
-	}
144
-	if err.Error() != "123" {
145
-		t.Errorf("Unexpeted error, got %#v", err)
146
-	}
147
-}
148
-
149
-func TestCreateImageStreamNotFound(t *testing.T) {
150
-	fakeEtcdClient, _, storage := setup(t)
151
-	fakeEtcdClient.Data["/imagerepositories/default"] = tools.EtcdResponseWithError{
152
-		R: &etcd.Response{
153
-			Node: &etcd.Node{
154
-				Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{
155
-					ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "bar"},
156
-				}),
157
-			},
158
-		},
159
-	}
160
-
161
-	obj, err := storage.Create(kapi.NewDefaultContext(), validNewMappingWithDockerImageRepository())
162
-	if obj.(*kapi.Status) != nil {
163
-		t.Errorf("Unexpected non-nil obj %#v", obj)
164
-	}
165
-	if err == nil {
166
-		t.Fatal("Unexpected nil err")
167
-	}
168
-	if !errors.IsInvalid(err) {
169
-		t.Fatalf("Expected 'invalid' err, got: %#v", err)
170
-	}
171
-}
172
-
173
-func TestCreateSuccessWithDockerImageRepository(t *testing.T) {
174
-	fakeEtcdClient, helper, storage := setup(t)
175
-
176
-	initialStream := &api.ImageStream{
177
-		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "somerepo"},
178
-		Spec: api.ImageStreamSpec{
179
-			DockerImageRepository: "localhost:5000/someproject/somerepo",
180
-		},
181
-	}
182
-
183
-	fakeEtcdClient.Data["/imagerepositories/default"] = tools.EtcdResponseWithError{
184
-		R: &etcd.Response{
185
-			Node: &etcd.Node{
186
-				Nodes: []*etcd.Node{
187
-					{
188
-						Value:         runtime.EncodeOrDie(latest.Codec, initialStream),
189
-						ModifiedIndex: 1,
190
-					},
191
-				},
192
-			},
193
-		},
194
-	}
195
-	fakeEtcdClient.Data["/imagerepositories/default/somerepo"] = tools.EtcdResponseWithError{
196
-		R: &etcd.Response{
197
-			Node: &etcd.Node{
198
-				Value:         runtime.EncodeOrDie(latest.Codec, initialStream),
199
-				ModifiedIndex: 1,
200
-			},
201
-		},
202
-	}
203
-
204
-	mapping := validNewMappingWithDockerImageRepository()
205
-	_, err := storage.Create(kapi.NewDefaultContext(), mapping)
206
-	if err != nil {
207
-		t.Fatalf("Unexpected error creating mapping: %#v", err)
208
-	}
209
-
210
-	image := &api.Image{}
211
-	if err := helper.ExtractObj("/images/imageID1", image, false); err != nil {
212
-		t.Errorf("Unexpected error retrieving image: %#v", err)
213
-	}
214
-	if e, a := mapping.Image.DockerImageReference, image.DockerImageReference; e != a {
215
-		t.Errorf("Expected %s, got %s", e, a)
216
-	}
217
-	if !reflect.DeepEqual(mapping.Image.DockerImageMetadata, image.DockerImageMetadata) {
218
-		t.Errorf("Expected %#v, got %#v", mapping.Image, image)
219
-	}
220
-
221
-	repo := &api.ImageStream{}
222
-	if err := helper.ExtractObj("/imagerepositories/default/somerepo", repo, false); err != nil {
223
-		t.Errorf("Unexpected non-nil err: %#v", err)
224
-	}
225
-	if e, a := "imageID1", repo.Status.Tags["latest"].Items[0].Image; e != a {
226
-		t.Errorf("unexpected repo: %#v\n%#v", repo, image)
227
-	}
228
-}
229
-
230
-func TestCreateSuccessWithMismatchedNames(t *testing.T) {
231
-	fakeEtcdClient, helper, storage := setup(t)
232
-
233
-	initialStream := &api.ImageStream{
234
-		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "repo1"},
235
-		Spec: api.ImageStreamSpec{
236
-			DockerImageRepository: "localhost:5000/someproject/somerepo",
237
-		},
238
-	}
239
-
240
-	fakeEtcdClient.Data["/imagerepositories/default"] = tools.EtcdResponseWithError{
241
-		R: &etcd.Response{
242
-			Node: &etcd.Node{
243
-				Nodes: []*etcd.Node{
244
-					{
245
-						Value:         runtime.EncodeOrDie(latest.Codec, initialStream),
246
-						ModifiedIndex: 1,
247
-					},
248
-				},
249
-			},
250
-		},
251
-	}
252
-	fakeEtcdClient.Data["/imagerepositories/default/repo1"] = tools.EtcdResponseWithError{
253
-		R: &etcd.Response{
254
-			Node: &etcd.Node{
255
-				Value:         runtime.EncodeOrDie(latest.Codec, initialStream),
256
-				ModifiedIndex: 1,
257
-			},
258
-		},
259
-	}
260
-
261
-	mapping := validNewMappingWithDockerImageRepository()
262
-	_, err := storage.Create(kapi.NewDefaultContext(), mapping)
263
-	if err != nil {
264
-		t.Fatalf("Unexpected error creating mapping: %#v", err)
265
-	}
266
-
267
-	image := &api.Image{}
268
-	if err := helper.ExtractObj("/images/imageID1", image, false); err != nil {
269
-		t.Errorf("Unexpected error retrieving image: %#v", err)
270
-	}
271
-	if e, a := mapping.Image.DockerImageReference, image.DockerImageReference; e != a {
272
-		t.Errorf("Expected %s, got %s", e, a)
273
-	}
274
-	if !reflect.DeepEqual(mapping.Image.DockerImageMetadata, image.DockerImageMetadata) {
275
-		t.Errorf("Expected %#v, got %#v", mapping.Image, image)
276
-	}
277
-
278
-	repo := &api.ImageStream{}
279
-	if err := helper.ExtractObj("/imagerepositories/default/repo1", repo, false); err != nil {
280
-		t.Errorf("Unexpected non-nil err: %#v", err)
281
-	}
282
-	if e, a := "localhost:5000/someproject/somerepo:imageID1", repo.Status.Tags["latest"].Items[0].DockerImageReference; e != a {
283
-		t.Errorf("unexpected repo: %#v\n%#v", repo, image)
284
-	}
285
-	if e, a := "imageID1", repo.Status.Tags["latest"].Items[0].Image; e != a {
286
-		t.Errorf("unexpected repo: %#v\n%#v", repo, image)
287
-	}
288
-}
289
-
290
-func TestCreateSuccessWithName(t *testing.T) {
291
-	fakeEtcdClient, helper, storage := setup(t)
292
-
293
-	initialStream := &api.ImageStream{
294
-		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "somerepo"},
295
-	}
296
-
297
-	fakeEtcdClient.Data["/imagerepositories/default/somerepo"] = tools.EtcdResponseWithError{
298
-		R: &etcd.Response{
299
-			Node: &etcd.Node{
300
-				Value:         runtime.EncodeOrDie(latest.Codec, initialStream),
301
-				ModifiedIndex: 1,
302
-			},
303
-		},
304
-	}
305
-
306
-	mapping := validNewMappingWithName()
307
-	_, err := storage.Create(kapi.NewDefaultContext(), mapping)
308
-	if err != nil {
309
-		t.Fatalf("Unexpected error creating mapping: %#v", err)
310
-	}
311
-
312
-	image := &api.Image{}
313
-	if err := helper.ExtractObj("/images/imageID1", image, false); err != nil {
314
-		t.Errorf("Unexpected error retrieving image: %#v", err)
315
-	}
316
-	if e, a := mapping.Image.DockerImageReference, image.DockerImageReference; e != a {
317
-		t.Errorf("Expected %s, got %s", e, a)
318
-	}
319
-	if !reflect.DeepEqual(mapping.Image.DockerImageMetadata, image.DockerImageMetadata) {
320
-		t.Errorf("Expected %#v, got %#v", mapping.Image, image)
321
-	}
322
-
323
-	repo := &api.ImageStream{}
324
-	if err := helper.ExtractObj("/imagerepositories/default/somerepo", repo, false); err != nil {
325
-		t.Errorf("Unexpected non-nil err: %#v", err)
326
-	}
327
-	if e, a := "imageID1", repo.Status.Tags["latest"].Items[0].Image; e != a {
328
-		t.Errorf("Expected %s, got %s", e, a)
329
-	}
330
-}
331
-
332
-func TestAddExistingImageWithNewTag(t *testing.T) {
333
-	imageID := "8d812da98d6dd61620343f1a5bf6585b34ad6ed16e5c5f7c7216a525d6aeb772"
334
-	existingRepo := &api.ImageStream{
335
-		ObjectMeta: kapi.ObjectMeta{
336
-			Name:      "somerepo",
337
-			Namespace: "default",
338
-		},
339
-		Spec: api.ImageStreamSpec{
340
-			DockerImageRepository: "localhost:5000/someproject/somerepo",
341
-			/*
342
-				Tags: map[string]api.TagReference{
343
-					"existingTag": {
344
-						From: &kapi.ObjectReference{
345
-							Kind: "ImageStreamTag",
346
-
347
-						Tag: "existingTag", Reference: imageID},
348
-				},
349
-			*/
350
-		},
351
-		Status: api.ImageStreamStatus{
352
-			Tags: map[string]api.TagEventList{
353
-				"existingTag": {Items: []api.TagEvent{{DockerImageReference: "localhost:5000/someproject/somerepo:" + imageID}}},
354
-			},
355
-		},
356
-	}
357
-
358
-	existingImage := &api.Image{
359
-		ObjectMeta: kapi.ObjectMeta{
360
-			Name: imageID,
361
-		},
362
-		DockerImageReference: "localhost:5000/someproject/somerepo:" + imageID,
363
-		DockerImageMetadata: api.DockerImage{
364
-			Config: api.DockerConfig{
365
-				Cmd:          []string{"ls", "/"},
366
-				Env:          []string{"a=1"},
367
-				ExposedPorts: map[string]struct{}{"1234/tcp": {}},
368
-				Memory:       1234,
369
-				CPUShares:    99,
370
-				WorkingDir:   "/workingDir",
371
-			},
372
-		},
373
-	}
374
-
375
-	fakeEtcdClient, helper, storage := setup(t)
376
-	fakeEtcdClient.Data["/imagerepositories/default"] = tools.EtcdResponseWithError{
377
-		R: &etcd.Response{
378
-			Node: &etcd.Node{
379
-				Nodes: []*etcd.Node{
380
-					{
381
-						Value:         runtime.EncodeOrDie(latest.Codec, existingRepo),
382
-						ModifiedIndex: 1,
383
-					},
384
-				},
385
-			},
386
-		},
387
-	}
388
-	fakeEtcdClient.Data["/imagerepositories/default/somerepo"] = tools.EtcdResponseWithError{
389
-		R: &etcd.Response{
390
-			Node: &etcd.Node{
391
-				Value:         runtime.EncodeOrDie(latest.Codec, existingRepo),
392
-				ModifiedIndex: 1,
393
-			},
394
-		},
395
-	}
396
-	fakeEtcdClient.Data["/images/default/"+imageID] = tools.EtcdResponseWithError{
397
-		R: &etcd.Response{
398
-			Node: &etcd.Node{
399
-				Value:         runtime.EncodeOrDie(latest.Codec, existingImage),
400
-				ModifiedIndex: 1,
401
-			},
402
-		},
403
-	}
404
-
405
-	mapping := api.ImageRepositoryMapping{
406
-		DockerImageRepository: "localhost:5000/someproject/somerepo",
407
-		Image: *existingImage,
408
-		Tag:   "latest",
409
-	}
410
-	_, err := storage.Create(kapi.NewDefaultContext(), &mapping)
411
-	if err != nil {
412
-		t.Errorf("Unexpected error creating mapping: %#v", err)
413
-	}
414
-
415
-	image := &api.Image{}
416
-	if err := helper.ExtractObj("/images/"+imageID, image, false); err != nil {
417
-		t.Errorf("Unexpected error retrieving image: %#v", err)
418
-	}
419
-	if e, a := mapping.Image.DockerImageReference, image.DockerImageReference; e != a {
420
-		t.Errorf("Expected %s, got %s", e, a)
421
-	}
422
-	if !reflect.DeepEqual(mapping.Image.DockerImageMetadata, image.DockerImageMetadata) {
423
-		t.Errorf("Expected %#v, got %#v", mapping.Image, image)
424
-	}
425
-
426
-	repo := &api.ImageStream{}
427
-	if err := helper.ExtractObj("/imagerepositories/default/somerepo", repo, false); err != nil {
428
-		t.Errorf("Unexpected non-nil err: %#v", err)
429
-	}
430
-	/*
431
-		if e, a := "", repo.Spec.Tags["latest"].Reference; e != a {
432
-			t.Errorf("Expected %s, got %s", e, a)
433
-		}
434
-	*/
435
-	if e, a := 2, len(repo.Status.Tags); e != a {
436
-		t.Fatalf("repo.Status.Tags length: expected %d, got %d: %#v", e, a, repo.Status.Tags)
437
-	}
438
-	if e, a := 1, len(repo.Status.Tags["existingTag"].Items); e != a {
439
-		t.Errorf("repo.Status.Tags['existingTag']: expected '%v', got '%v': %#v", e, a, repo.Status.Tags["existingTag"].Items)
440
-	}
441
-	if e, a := "localhost:5000/someproject/somerepo:"+imageID, repo.Status.Tags["existingTag"].Items[0].DockerImageReference; e != a {
442
-		t.Errorf("existingTag history: expected image %s, got %s", e, a)
443
-	}
444
-	if e, a := 1, len(repo.Status.Tags["latest"].Items); e != a {
445
-		t.Errorf("repo.Status.Tags['latest']: expected '%v', got '%v'", e, a)
446
-	}
447
-	if e, a := "localhost:5000/someproject/somerepo:"+imageID, repo.Status.Tags["latest"].Items[0].DockerImageReference; e != a {
448
-		t.Errorf("latest history: expected image %s, got %s", e, a)
449
-	}
450
-	if e, a := imageID, repo.Status.Tags["latest"].Items[0].Image; e != a {
451
-		t.Errorf("Expected %s, got %s", e, a)
452
-	}
453
-
454
-	event := api.LatestTaggedImage(repo, "")
455
-	if event == nil {
456
-		t.Fatalf("unexpected nil event")
457
-	}
458
-	if event.DockerImageReference != "localhost:5000/someproject/somerepo:"+imageID || event.Image != imageID {
459
-		t.Errorf("unexpected latest tagged image: %#v", event)
460
-	}
461
-}
462
-
463
-func TestAddExistingImageAndTag(t *testing.T) {
464
-	existingRepo := &api.ImageStream{
465
-		ObjectMeta: kapi.ObjectMeta{
466
-			Name:      "somerepo",
467
-			Namespace: "default",
468
-		},
469
-		Spec: api.ImageStreamSpec{
470
-			DockerImageRepository: "localhost:5000/someproject/somerepo",
471
-			/*
472
-				Tags: map[string]api.TagReference{
473
-					"existingTag": {Tag: "existingTag", Reference: "existingImage"},
474
-				},
475
-			*/
476
-		},
477
-		Status: api.ImageStreamStatus{
478
-			Tags: map[string]api.TagEventList{
479
-				"existingTag": {Items: []api.TagEvent{{DockerImageReference: "existingImage"}}},
480
-			},
481
-		},
482
-	}
483
-
484
-	existingImage := &api.Image{
485
-		ObjectMeta: kapi.ObjectMeta{
486
-			Name: "existingImage",
487
-		},
488
-		DockerImageReference: "localhost:5000/someproject/somerepo:imageID1",
489
-		DockerImageMetadata: api.DockerImage{
490
-			Config: api.DockerConfig{
491
-				Cmd:          []string{"ls", "/"},
492
-				Env:          []string{"a=1"},
493
-				ExposedPorts: map[string]struct{}{"1234/tcp": {}},
494
-				Memory:       1234,
495
-				CPUShares:    99,
496
-				WorkingDir:   "/workingDir",
497
-			},
498
-		},
499
-	}
500
-
501
-	fakeEtcdClient, helper, storage := setup(t)
502
-	fakeEtcdClient.Data["/imagerepositories/default"] = tools.EtcdResponseWithError{
503
-		R: &etcd.Response{
504
-			Node: &etcd.Node{
505
-				Nodes: []*etcd.Node{
506
-					{
507
-						Value:         runtime.EncodeOrDie(latest.Codec, existingRepo),
508
-						ModifiedIndex: 1,
509
-					},
510
-				},
511
-			},
512
-		},
513
-	}
514
-	fakeEtcdClient.Data["/imagerepositories/default/somerepo"] = tools.EtcdResponseWithError{
515
-		R: &etcd.Response{
516
-			Node: &etcd.Node{
517
-				Value:         runtime.EncodeOrDie(latest.Codec, existingRepo),
518
-				ModifiedIndex: 1,
519
-			},
520
-		},
521
-	}
522
-	fakeEtcdClient.Data["/images/default/existingImage"] = tools.EtcdResponseWithError{
523
-		R: &etcd.Response{
524
-			Node: &etcd.Node{
525
-				Value:         runtime.EncodeOrDie(latest.Codec, existingImage),
526
-				ModifiedIndex: 1,
527
-			},
528
-		},
529
-	}
530
-
531
-	mapping := api.ImageRepositoryMapping{
532
-		DockerImageRepository: "localhost:5000/someproject/somerepo",
533
-		Image: *existingImage,
534
-		Tag:   "existingTag",
535
-	}
536
-	_, err := storage.Create(kapi.NewDefaultContext(), &mapping)
537
-	if err != nil {
538
-		t.Fatalf("Unexpected error creating mapping: %#v", err)
539
-	}
540
-
541
-	image := &api.Image{}
542
-	if err := helper.ExtractObj("/images/existingImage", image, false); err != nil {
543
-		t.Fatalf("Unexpected error retrieving image: %#v", err)
544
-	}
545
-	if e, a := mapping.Image.DockerImageReference, image.DockerImageReference; e != a {
546
-		t.Errorf("Expected %s, got %s", e, a)
547
-	}
548
-	if !reflect.DeepEqual(mapping.Image.DockerImageMetadata, image.DockerImageMetadata) {
549
-		t.Errorf("Expected %#v, got %#v", mapping.Image, image)
550
-	}
551
-
552
-	repo := &api.ImageStream{}
553
-	if err := helper.ExtractObj("/imagerepositories/default/somerepo", repo, false); err != nil {
554
-		t.Fatalf("Unexpected non-nil err: %#v", err)
555
-	}
556
-	// Tags aren't changed during mapping creation
557
-	/*
558
-		if e, a := "existingImage", repo.Spec.Tags["existingTag"].Reference; e != a {
559
-			t.Errorf("Expected %s, got %s", e, a)
560
-		}
561
-	*/
562
-	if e, a := 1, len(repo.Status.Tags); e != a {
563
-		t.Errorf("repo.Status.Tags length: expected %d, got %d", e, a)
564
-	}
565
-	if e, a := mapping.DockerImageRepository+":imageID1", repo.Status.Tags["existingTag"].Items[0].DockerImageReference; e != a {
566
-		t.Errorf("unexpected repo: %#v", repo)
567
-	}
568
-}
569 1
deleted file mode 100644
... ...
@@ -1,45 +0,0 @@
1
-package imagerepositorytag
2
-
3
-import (
4
-	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
5
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
6
-
7
-	"github.com/openshift/origin/pkg/image/api"
8
-	"github.com/openshift/origin/pkg/image/registry/imagestreamtag"
9
-)
10
-
11
-// REST implements the RESTStorage interface for ImageRepositoryTag.
12
-type REST struct {
13
-	imageStreamTagRegistry imagestreamtag.Registry
14
-}
15
-
16
-// NewREST returns a new REST.
17
-func NewREST(r imagestreamtag.Registry) *REST {
18
-	return &REST{r}
19
-}
20
-
21
-// New is only implemented to make REST implement RESTStorage
22
-func (r *REST) New() runtime.Object {
23
-	return &api.Image{}
24
-}
25
-
26
-// Get retrieves an image that has been tagged by repo and tag. `id` is of the format
27
-// <repo name>:<tag>.
28
-func (r *REST) Get(ctx kapi.Context, id string) (runtime.Object, error) {
29
-	ist, err := r.imageStreamTagRegistry.GetImageStreamTag(ctx, id)
30
-	if err != nil {
31
-		return nil, err
32
-	}
33
-	irt := api.ImageRepositoryTag{}
34
-	if err := kapi.Scheme.Convert(ist, &irt); err != nil {
35
-		return nil, err
36
-	}
37
-	return &irt, nil
38
-}
39
-
40
-// Delete removes a tag from a repo. `id` is of the format <repo name>:<tag>.
41
-// The associated image that the tag points to is *not* deleted.
42
-// The tag history remains intact and is not deleted.
43
-func (r *REST) Delete(ctx kapi.Context, id string) (runtime.Object, error) {
44
-	return r.imageStreamTagRegistry.DeleteImageStreamTag(ctx, id)
45
-}
46 1
deleted file mode 100644
... ...
@@ -1,358 +0,0 @@
1
-package imagerepositorytag
2
-
3
-import (
4
-	"reflect"
5
-	"testing"
6
-
7
-	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
8
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
9
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user"
10
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
11
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools"
12
-	"github.com/GoogleCloudPlatform/kubernetes/pkg/tools/etcdtest"
13
-	"github.com/coreos/go-etcd/etcd"
14
-
15
-	"github.com/openshift/origin/pkg/api/latest"
16
-	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
17
-	"github.com/openshift/origin/pkg/authorization/registry/subjectaccessreview"
18
-	"github.com/openshift/origin/pkg/image/api"
19
-	"github.com/openshift/origin/pkg/image/registry/image"
20
-	imageetcd "github.com/openshift/origin/pkg/image/registry/image/etcd"
21
-	"github.com/openshift/origin/pkg/image/registry/imagestream"
22
-	imagestreametcd "github.com/openshift/origin/pkg/image/registry/imagestream/etcd"
23
-	"github.com/openshift/origin/pkg/image/registry/imagestreamtag"
24
-)
25
-
26
-var testDefaultRegistry = imagestream.DefaultRegistryFunc(func() (string, bool) { return "defaultregistry:5000", true })
27
-
28
-type fakeSubjectAccessReviewRegistry struct {
29
-}
30
-
31
-var _ subjectaccessreview.Registry = &fakeSubjectAccessReviewRegistry{}
32
-
33
-func (f *fakeSubjectAccessReviewRegistry) CreateSubjectAccessReview(ctx kapi.Context, subjectAccessReview *authorizationapi.SubjectAccessReview) (*authorizationapi.SubjectAccessReviewResponse, error) {
34
-	return nil, nil
35
-}
36
-
37
-type fakeUser struct {
38
-}
39
-
40
-var _ user.Info = &fakeUser{}
41
-
42
-func (u *fakeUser) GetName() string {
43
-	return "user"
44
-}
45
-
46
-func (u *fakeUser) GetUID() string {
47
-	return "uid"
48
-}
49
-
50
-func (u *fakeUser) GetGroups() []string {
51
-	return []string{"group1"}
52
-}
53
-
54
-func setup(t *testing.T) (*tools.FakeEtcdClient, tools.EtcdHelper, *REST) {
55
-	fakeEtcdClient := tools.NewFakeEtcdClient(t)
56
-	fakeEtcdClient.TestIndex = true
57
-	helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec, etcdtest.PathPrefix())
58
-	imageStorage := imageetcd.NewREST(helper)
59
-	imageRegistry := image.NewRegistry(imageStorage)
60
-	imageStreamStorage, imageStreamStatus := imagestreametcd.NewREST(helper, testDefaultRegistry, &fakeSubjectAccessReviewRegistry{})
61
-	imageStreamRegistry := imagestream.NewRegistry(imageStreamStorage, imageStreamStatus)
62
-	imageStreamTagStorage := imagestreamtag.NewREST(imageRegistry, imageStreamRegistry)
63
-	imageStreamTagRegistry := imagestreamtag.NewRegistry(imageStreamTagStorage)
64
-	storage := NewREST(imageStreamTagRegistry)
65
-	return fakeEtcdClient, helper, storage
66
-}
67
-
68
-type statusError interface {
69
-	Status() kapi.Status
70
-}
71
-
72
-func TestGetImageRepositoryTag(t *testing.T) {
73
-	tests := map[string]struct {
74
-		image           *api.Image
75
-		repo            *api.ImageStream
76
-		expectError     bool
77
-		errorTargetKind string
78
-		errorTargetID   string
79
-	}{
80
-		"happy path": {
81
-			image: &api.Image{ObjectMeta: kapi.ObjectMeta{Name: "10"}, DockerImageReference: "foo/bar/baz"},
82
-			repo: &api.ImageStream{
83
-				Spec: api.ImageStreamSpec{
84
-					Tags: map[string]api.TagReference{
85
-						"latest": {
86
-							Annotations: map[string]string{
87
-								"color": "blue",
88
-								"size":  "large",
89
-							},
90
-						},
91
-					},
92
-				},
93
-				Status: api.ImageStreamStatus{
94
-					Tags: map[string]api.TagEventList{
95
-						"latest": {Items: []api.TagEvent{{DockerImageReference: "test", Image: "10"}}},
96
-					},
97
-				},
98
-			},
99
-		},
100
-		"image = ''": {
101
-			repo: &api.ImageStream{Status: api.ImageStreamStatus{
102
-				Tags: map[string]api.TagEventList{
103
-					"latest": {Items: []api.TagEvent{{DockerImageReference: "test", Image: ""}}},
104
-				},
105
-			}},
106
-			expectError:     true,
107
-			errorTargetKind: "imageStreamTag",
108
-			errorTargetID:   "test:latest",
109
-		},
110
-		"missing image": {
111
-			repo: &api.ImageStream{Status: api.ImageStreamStatus{
112
-				Tags: map[string]api.TagEventList{
113
-					"latest": {Items: []api.TagEvent{{DockerImageReference: "test", Image: "10"}}},
114
-				},
115
-			}},
116
-			expectError:     true,
117
-			errorTargetKind: "image",
118
-			errorTargetID:   "10",
119
-		},
120
-		"missing repo": {
121
-			expectError:     true,
122
-			errorTargetKind: "imageStream",
123
-			errorTargetID:   "test",
124
-		},
125
-		"missing tag": {
126
-			image: &api.Image{ObjectMeta: kapi.ObjectMeta{Name: "10"}, DockerImageReference: "foo/bar/baz"},
127
-			repo: &api.ImageStream{Status: api.ImageStreamStatus{
128
-				Tags: map[string]api.TagEventList{
129
-					"other": {Items: []api.TagEvent{{DockerImageReference: "test", Image: "10"}}},
130
-				},
131
-			}},
132
-			expectError:     true,
133
-			errorTargetKind: "imageStreamTag",
134
-			errorTargetID:   "test:latest",
135
-		},
136
-	}
137
-
138
-	for name, testCase := range tests {
139
-		fakeEtcdClient, _, storage := setup(t)
140
-
141
-		if testCase.image != nil {
142
-			fakeEtcdClient.Data["/images/"+testCase.image.Name] = tools.EtcdResponseWithError{
143
-				R: &etcd.Response{
144
-					Node: &etcd.Node{
145
-						Value:         runtime.EncodeOrDie(latest.Codec, testCase.image),
146
-						ModifiedIndex: 1,
147
-					},
148
-				},
149
-			}
150
-		} else {
151
-			fakeEtcdClient.Data["/images/10"] = tools.EtcdResponseWithError{
152
-				R: &etcd.Response{
153
-					Node: nil,
154
-				},
155
-				E: tools.EtcdErrorNotFound,
156
-			}
157
-		}
158
-
159
-		if testCase.repo != nil {
160
-			fakeEtcdClient.Data["/imagerepositories/default/test"] = tools.EtcdResponseWithError{
161
-				R: &etcd.Response{
162
-					Node: &etcd.Node{
163
-						Value:         runtime.EncodeOrDie(latest.Codec, testCase.repo),
164
-						ModifiedIndex: 1,
165
-					},
166
-				},
167
-			}
168
-		} else {
169
-			fakeEtcdClient.Data["/imagerepositories/default/test"] = tools.EtcdResponseWithError{
170
-				R: &etcd.Response{
171
-					Node: nil,
172
-				},
173
-				E: tools.EtcdErrorNotFound,
174
-			}
175
-		}
176
-
177
-		obj, err := storage.Get(kapi.NewDefaultContext(), "test:latest")
178
-		gotErr := err != nil
179
-		if e, a := testCase.expectError, gotErr; e != a {
180
-			t.Fatalf("%s: Expected err=%v: got %v: %v", name, e, a, err)
181
-		}
182
-		if testCase.expectError {
183
-			if !errors.IsNotFound(err) {
184
-				t.Fatalf("%s: unexpected error type: %v", name, err)
185
-			}
186
-			status := err.(statusError).Status()
187
-			if status.Details.Kind != testCase.errorTargetKind || status.Details.ID != testCase.errorTargetID {
188
-				t.Errorf("%s: unexpected status: %#v", name, status)
189
-			}
190
-		} else {
191
-			actual := obj.(*api.ImageRepositoryTag)
192
-			if e, a := "default", actual.Namespace; e != a {
193
-				t.Errorf("%s: name: expected %v, got %v", name, e, a)
194
-			}
195
-			if e, a := "test:latest", actual.Name; e != a {
196
-				t.Errorf("%s: name: expected %v, got %v", name, e, a)
197
-			}
198
-			if e, a := map[string]string{"size": "large", "color": "blue"}, actual.Annotations; !reflect.DeepEqual(e, a) {
199
-				t.Errorf("%s: annotations: expected %v, got %v", name, e, a)
200
-			}
201
-		}
202
-	}
203
-}
204
-
205
-func TestDeleteImageRepositoryTag(t *testing.T) {
206
-	tests := map[string]struct {
207
-		repo        *api.ImageStream
208
-		expectError bool
209
-	}{
210
-		"repo not found": {
211
-			expectError: true,
212
-		},
213
-		"nil tag map": {
214
-			repo: &api.ImageStream{
215
-				ObjectMeta: kapi.ObjectMeta{
216
-					Namespace: "default",
217
-					Name:      "test",
218
-				},
219
-			},
220
-			expectError: true,
221
-		},
222
-		"missing tag": {
223
-			repo: &api.ImageStream{
224
-				ObjectMeta: kapi.ObjectMeta{
225
-					Namespace: "default",
226
-					Name:      "test",
227
-				},
228
-				Spec: api.ImageStreamSpec{
229
-					Tags: map[string]api.TagReference{
230
-						"other": {
231
-							From: &kapi.ObjectReference{
232
-								Kind: "ImageStreamTag",
233
-								Name: "test:foo",
234
-							},
235
-						},
236
-					},
237
-				},
238
-			},
239
-			expectError: true,
240
-		},
241
-		"happy path": {
242
-			repo: &api.ImageStream{
243
-				ObjectMeta: kapi.ObjectMeta{
244
-					Namespace: "default",
245
-					Name:      "test",
246
-				},
247
-				Spec: api.ImageStreamSpec{
248
-					Tags: map[string]api.TagReference{
249
-						"another": {
250
-							From: &kapi.ObjectReference{
251
-								Kind: "ImageStreamTag",
252
-								Name: "test:foo",
253
-							},
254
-						},
255
-						"latest": {
256
-							From: &kapi.ObjectReference{
257
-								Kind: "ImageStreamTag",
258
-								Name: "test:bar",
259
-							},
260
-						},
261
-					},
262
-				},
263
-				Status: api.ImageStreamStatus{
264
-					DockerImageRepository: "registry.default.local/default/test",
265
-					Tags: map[string]api.TagEventList{
266
-						"another": {
267
-							Items: []api.TagEvent{
268
-								{
269
-									DockerImageReference: "registry.default.local/default/test@sha256:381151ac5b7f775e8371e489f3479b84a4c004c90ceddb2ad80b6877215a892f",
270
-									Image:                "sha256:381151ac5b7f775e8371e489f3479b84a4c004c90ceddb2ad80b6877215a892f",
271
-								},
272
-							},
273
-						},
274
-						"foo": {
275
-							Items: []api.TagEvent{
276
-								{
277
-									DockerImageReference: "registry.default.local/default/test@sha256:381151ac5b7f775e8371e489f3479b84a4c004c90ceddb2ad80b6877215a892f",
278
-									Image:                "sha256:381151ac5b7f775e8371e489f3479b84a4c004c90ceddb2ad80b6877215a892f",
279
-								},
280
-							},
281
-						},
282
-						"latest": {
283
-							Items: []api.TagEvent{
284
-								{
285
-									DockerImageReference: "registry.default.local/default/test@sha256:381151ac5b7f775e8371e489f3479b84a4c004c90ceddb2ad80b6877215a892f",
286
-									Image:                "sha256:381151ac5b7f775e8371e489f3479b84a4c004c90ceddb2ad80b6877215a892f",
287
-								},
288
-							},
289
-						},
290
-						"bar": {
291
-							Items: []api.TagEvent{
292
-								{
293
-									DockerImageReference: "registry.default.local/default/test@sha256:381151ac5b7f775e8371e489f3479b84a4c004c90ceddb2ad80b6877215a892f",
294
-									Image:                "sha256:381151ac5b7f775e8371e489f3479b84a4c004c90ceddb2ad80b6877215a892f",
295
-								},
296
-							},
297
-						},
298
-					},
299
-				},
300
-			},
301
-		},
302
-	}
303
-
304
-	for name, testCase := range tests {
305
-		fakeEtcdClient, helper, storage := setup(t)
306
-		if testCase.repo != nil {
307
-			fakeEtcdClient.Data["/imagerepositories/default/test"] = tools.EtcdResponseWithError{
308
-				R: &etcd.Response{
309
-					Node: &etcd.Node{
310
-						Value:         runtime.EncodeOrDie(latest.Codec, testCase.repo),
311
-						ModifiedIndex: 1,
312
-					},
313
-				},
314
-			}
315
-		} else {
316
-			fakeEtcdClient.Data["/imagerepositories/default/test"] = tools.EtcdResponseWithError{
317
-				R: &etcd.Response{
318
-					Node: nil,
319
-				},
320
-				E: tools.EtcdErrorNotFound,
321
-			}
322
-		}
323
-
324
-		ctx := kapi.WithUser(kapi.NewDefaultContext(), &fakeUser{})
325
-		obj, err := storage.Delete(ctx, "test:latest")
326
-		gotError := err != nil
327
-		if e, a := testCase.expectError, gotError; e != a {
328
-			t.Fatalf("%s: expectError=%t, gotError=%t: %s", name, e, a, err)
329
-		}
330
-		if testCase.expectError {
331
-			continue
332
-		}
333
-
334
-		if obj == nil {
335
-			t.Fatalf("%s: unexpected nil response", name)
336
-		}
337
-		expectedStatus := &kapi.Status{Status: kapi.StatusSuccess}
338
-		if e, a := expectedStatus, obj; !reflect.DeepEqual(e, a) {
339
-			t.Errorf("%s: expected %#v, got %#v", name, e, a)
340
-		}
341
-
342
-		updatedRepo := &api.ImageStream{}
343
-		if err := helper.ExtractObj("/imagerepositories/default/test", updatedRepo, false); err != nil {
344
-			t.Fatalf("%s: error retrieving updated repo: %s", name, err)
345
-		}
346
-		expected := map[string]api.TagReference{
347
-			"another": {
348
-				From: &kapi.ObjectReference{
349
-					Kind: "ImageStreamTag",
350
-					Name: "test:foo",
351
-				},
352
-			},
353
-		}
354
-		if e, a := expected, updatedRepo.Spec.Tags; !reflect.DeepEqual(e, a) {
355
-			t.Errorf("%s: tags: expected %v, got %v", name, e, a)
356
-		}
357
-	}
358
-}
... ...
@@ -21,8 +21,7 @@ type REST struct {
21 21
 
22 22
 // NewREST returns a new REST.
23 23
 func NewREST(h tools.EtcdHelper, defaultRegistry imagestream.DefaultRegistry, subjectAccessReviewRegistry subjectaccessreview.Registry) (*REST, *StatusREST) {
24
-	//TODO change to imageStreams at release time
25
-	prefix := "/imagerepositories"
24
+	prefix := "/imagestreams"
26 25
 	store := etcdgeneric.Etcd{
27 26
 		NewFunc:     func() runtime.Object { return &api.ImageStream{} },
28 27
 		NewListFunc: func() runtime.Object { return &api.ImageStreamList{} },
... ...
@@ -121,7 +121,7 @@ func TestListImageStreamsError(t *testing.T) {
121 121
 func TestListImageStreamsEmptyList(t *testing.T) {
122 122
 	fakeEtcdClient, helper := newHelper(t)
123 123
 	fakeEtcdClient.ChangeIndex = 1
124
-	fakeEtcdClient.Data["/imagerepositories/default"] = tools.EtcdResponseWithError{
124
+	fakeEtcdClient.Data["/imagestreams/default"] = tools.EtcdResponseWithError{
125 125
 		R: &etcd.Response{},
126 126
 		E: fakeEtcdClient.NewError(tools.EtcdErrorCodeNotFound),
127 127
 	}
... ...
@@ -143,7 +143,7 @@ func TestListImageStreamsPopulatedList(t *testing.T) {
143 143
 	fakeEtcdClient, helper := newHelper(t)
144 144
 	storage, _ := NewREST(helper, noDefaultRegistry, &fakeSubjectAccessReviewRegistry{})
145 145
 
146
-	fakeEtcdClient.Data["/imagerepositories/default"] = tools.EtcdResponseWithError{
146
+	fakeEtcdClient.Data["/imagestreams/default"] = tools.EtcdResponseWithError{
147 147
 		R: &etcd.Response{
148 148
 			Node: &etcd.Node{
149 149
 				Nodes: []*etcd.Node{
... ...
@@ -195,7 +195,7 @@ func TestCreateImageStreamOK(t *testing.T) {
195 195
 	}
196 196
 
197 197
 	actual := &api.ImageStream{}
198
-	if err := helper.ExtractObj("/imagerepositories/default/foo", actual, false); err != nil {
198
+	if err := helper.ExtractObj("/imagestreams/default/foo", actual, false); err != nil {
199 199
 		t.Fatalf("unexpected extraction error: %v", err)
200 200
 	}
201 201
 	if actual.Name != stream.Name {
... ...
@@ -248,7 +248,7 @@ func TestCreateImageStreamSpecTagsFromSet(t *testing.T) {
248 248
 		if len(otherNamespace) == 0 {
249 249
 			otherNamespace = "default"
250 250
 		}
251
-		fakeEtcdClient.Data[fmt.Sprintf("/imagerepositories/%s/other", otherNamespace)] = tools.EtcdResponseWithError{
251
+		fakeEtcdClient.Data[fmt.Sprintf("/imagestreams/%s/other", otherNamespace)] = tools.EtcdResponseWithError{
252 252
 			R: &etcd.Response{
253 253
 				Node: &etcd.Node{
254 254
 					Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{
... ...
@@ -305,7 +305,7 @@ func TestCreateImageStreamSpecTagsFromSet(t *testing.T) {
305 305
 		}
306 306
 
307 307
 		actual := &api.ImageStream{}
308
-		if err := helper.ExtractObj("/imagerepositories/default/foo", actual, false); err != nil {
308
+		if err := helper.ExtractObj("/imagestreams/default/foo", actual, false); err != nil {
309 309
 			t.Fatalf("%s: unexpected extraction error: %v", name, err)
310 310
 		}
311 311
 		if e, a := fmt.Sprintf("%s/other:latest", otherNamespace), actual.Status.Tags["other"].Items[0].DockerImageReference; e != a {
... ...
@@ -352,7 +352,7 @@ func TestUpdateRegistryErrorSaving(t *testing.T) {
352 352
 
353 353
 func TestUpdateImageStreamOK(t *testing.T) {
354 354
 	fakeEtcdClient, helper := newHelper(t)
355
-	fakeEtcdClient.Data["/imagerepositories/default/bar"] = tools.EtcdResponseWithError{
355
+	fakeEtcdClient.Data["/imagestreams/default/bar"] = tools.EtcdResponseWithError{
356 356
 		R: &etcd.Response{
357 357
 			Node: &etcd.Node{
358 358
 				Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{
... ...
@@ -414,7 +414,7 @@ func TestUpdateImageStreamSpecTagsFromSet(t *testing.T) {
414 414
 		}
415 415
 		storage, _ := NewREST(helper, noDefaultRegistry, sarRegistry)
416 416
 
417
-		fakeEtcdClient.Data["/imagerepositories/default/foo"] = tools.EtcdResponseWithError{
417
+		fakeEtcdClient.Data["/imagestreams/default/foo"] = tools.EtcdResponseWithError{
418 418
 			R: &etcd.Response{
419 419
 				Node: &etcd.Node{
420 420
 					Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{
... ...
@@ -429,7 +429,7 @@ func TestUpdateImageStreamSpecTagsFromSet(t *testing.T) {
429 429
 		if len(otherNamespace) == 0 {
430 430
 			otherNamespace = "default"
431 431
 		}
432
-		fakeEtcdClient.Data[fmt.Sprintf("/imagerepositories/%s/other", otherNamespace)] = tools.EtcdResponseWithError{
432
+		fakeEtcdClient.Data[fmt.Sprintf("/imagestreams/%s/other", otherNamespace)] = tools.EtcdResponseWithError{
433 433
 			R: &etcd.Response{
434 434
 				Node: &etcd.Node{
435 435
 					Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{
... ...
@@ -486,7 +486,7 @@ func TestUpdateImageStreamSpecTagsFromSet(t *testing.T) {
486 486
 		}
487 487
 
488 488
 		actual := &api.ImageStream{}
489
-		if err := helper.ExtractObj("/imagerepositories/default/foo", actual, false); err != nil {
489
+		if err := helper.ExtractObj("/imagestreams/default/foo", actual, false); err != nil {
490 490
 			t.Fatalf("%s: unexpected extraction error: %v", name, err)
491 491
 		}
492 492
 		if e, a := fmt.Sprintf("%s/other:latest", otherNamespace), actual.Status.Tags["other"].Items[0].DockerImageReference; e != a {
... ...
@@ -497,7 +497,7 @@ func TestUpdateImageStreamSpecTagsFromSet(t *testing.T) {
497 497
 
498 498
 func TestDeleteImageStream(t *testing.T) {
499 499
 	fakeEtcdClient, helper := newHelper(t)
500
-	fakeEtcdClient.Data["/imagerepositories/default/foo"] = tools.EtcdResponseWithError{
500
+	fakeEtcdClient.Data["/imagestreams/default/foo"] = tools.EtcdResponseWithError{
501 501
 		R: &etcd.Response{
502 502
 			Node: &etcd.Node{
503 503
 				Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{
... ...
@@ -524,7 +524,7 @@ func TestDeleteImageStream(t *testing.T) {
524 524
 
525 525
 func TestUpdateImageStreamConflictingNamespace(t *testing.T) {
526 526
 	fakeEtcdClient, helper := newHelper(t)
527
-	fakeEtcdClient.Data["/imagerepositories/legal-name/bar"] = tools.EtcdResponseWithError{
527
+	fakeEtcdClient.Data["/imagestreams/legal-name/bar"] = tools.EtcdResponseWithError{
528 528
 		R: &etcd.Response{
529 529
 			Node: &etcd.Node{
530 530
 				Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{
... ...
@@ -980,7 +980,7 @@ func TestEtcdListImageStreamsInDifferentNamespaces(t *testing.T) {
980 980
 	fakeClient := tools.NewFakeEtcdClient(t)
981 981
 	namespaceAlfa := kapi.WithNamespace(kapi.NewContext(), "alfa")
982 982
 	namespaceBravo := kapi.WithNamespace(kapi.NewContext(), "bravo")
983
-	fakeClient.Data["/imagerepositories/alfa"] = tools.EtcdResponseWithError{
983
+	fakeClient.Data["/imagestreams/alfa"] = tools.EtcdResponseWithError{
984 984
 		R: &etcd.Response{
985 985
 			Node: &etcd.Node{
986 986
 				Nodes: []*etcd.Node{
... ...
@@ -992,7 +992,7 @@ func TestEtcdListImageStreamsInDifferentNamespaces(t *testing.T) {
992 992
 		},
993 993
 		E: nil,
994 994
 	}
995
-	fakeClient.Data["/imagerepositories/bravo"] = tools.EtcdResponseWithError{
995
+	fakeClient.Data["/imagestreams/bravo"] = tools.EtcdResponseWithError{
996 996
 		R: &etcd.Response{
997 997
 			Node: &etcd.Node{
998 998
 				Nodes: []*etcd.Node{
... ...
@@ -1030,8 +1030,8 @@ func TestEtcdGetImageStreamInDifferentNamespaces(t *testing.T) {
1030 1030
 	fakeClient := tools.NewFakeEtcdClient(t)
1031 1031
 	namespaceAlfa := kapi.WithNamespace(kapi.NewContext(), "alfa")
1032 1032
 	namespaceBravo := kapi.WithNamespace(kapi.NewContext(), "bravo")
1033
-	fakeClient.Set("/imagerepositories/alfa/foo", runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: "foo"}}), 0)
1034
-	fakeClient.Set("/imagerepositories/bravo/foo", runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: "foo"}}), 0)
1033
+	fakeClient.Set("/imagestreams/alfa/foo", runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: "foo"}}), 0)
1034
+	fakeClient.Set("/imagestreams/bravo/foo", runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: "foo"}}), 0)
1035 1035
 	registry := NewTestEtcd(fakeClient)
1036 1036
 
1037 1037
 	alfaFoo, err := registry.GetImageStream(namespaceAlfa, "foo")
... ...
@@ -145,20 +145,21 @@ func (s Strategy) tagsChanged(old, stream *api.ImageStream) fielderrors.Validati
145 145
 		if oldRef, ok := oldTags[tag]; ok && !tagRefChanged(oldRef, tagRef, stream.Namespace) {
146 146
 			continue
147 147
 		}
148
-		if len(tagRef.DockerImageReference) > 0 {
148
+
149
+		if tagRef.From == nil {
150
+			continue
151
+		}
152
+
153
+		if tagRef.From.Kind == "DockerImage" && len(tagRef.From.Name) > 0 {
149 154
 			event, err := tagReferenceToTagEvent(stream, tagRef, "")
150 155
 			if err != nil {
151
-				errs = append(errs, fielderrors.NewFieldInvalid(fmt.Sprintf("spec.tags[%s].dockerImageReference", tag), tagRef.DockerImageReference, err.Error()))
156
+				errs = append(errs, fielderrors.NewFieldInvalid(fmt.Sprintf("spec.tags[%s].from", tag), tagRef.From, err.Error()))
152 157
 				continue
153 158
 			}
154 159
 			api.AddTagEventToImageStream(stream, tag, *event)
155 160
 			continue
156 161
 		}
157 162
 
158
-		if tagRef.From == nil {
159
-			continue
160
-		}
161
-
162 163
 		tagRefStreamName, tagOrID, err := parseFromReference(stream, tagRef.From)
163 164
 		if err != nil {
164 165
 			errs = append(errs, fielderrors.NewFieldInvalid(fmt.Sprintf("spec.tags[%s].from.name", tag), tagRef.From.Name, "must be of the form <tag>, <repo>:<tag>, <id>, or <repo>@<id>"))
... ...
@@ -208,14 +209,13 @@ func (s Strategy) tagsChanged(old, stream *api.ImageStream) fielderrors.Validati
208 208
 }
209 209
 
210 210
 func tagReferenceToTagEvent(stream *api.ImageStream, tagRef api.TagReference, tagOrID string) (*api.TagEvent, error) {
211
-	if len(tagRef.DockerImageReference) > 0 {
211
+	switch tagRef.From.Kind {
212
+	case "DockerImage":
212 213
 		return &api.TagEvent{
213 214
 			Created:              util.Now(),
214
-			DockerImageReference: tagRef.DockerImageReference,
215
+			DockerImageReference: tagRef.From.Name,
215 216
 		}, nil
216
-	}
217 217
 
218
-	switch tagRef.From.Kind {
219 218
 	case "ImageStreamImage":
220 219
 		ref, err := api.DockerImageReferenceForStream(stream)
221 220
 		if err != nil {
... ...
@@ -235,10 +235,6 @@ func tagReferenceToTagEvent(stream *api.ImageStream, tagRef api.TagReference, ta
235 235
 }
236 236
 
237 237
 func tagRefChanged(old, next api.TagReference, streamNamespace string) bool {
238
-	if len(next.DockerImageReference) > 0 {
239
-		// DockerImageReference possibly changed
240
-		return next.DockerImageReference != old.DockerImageReference
241
-	}
242 238
 	if next.From == nil {
243 239
 		// both fields in next are empty
244 240
 		return false
... ...
@@ -121,7 +121,10 @@ func TestTagVerifier(t *testing.T) {
121 121
 		"nil from": {
122 122
 			newTags: map[string]api.TagReference{
123 123
 				api.DefaultImageTag: {
124
-					DockerImageReference: "registry/old/stream:latest",
124
+					From: &kapi.ObjectReference{
125
+						Kind: "DockerImage",
126
+						Name: "registry/old/stream:latest",
127
+					},
125 128
 				},
126 129
 			},
127 130
 			expectSar: false,
... ...
@@ -304,7 +307,14 @@ func TestTagsChanged(t *testing.T) {
304 304
 		"single tag update, preserves history": {
305 305
 			stream:   "registry:5000/ns/stream",
306 306
 			previous: map[string]api.TagReference{},
307
-			tags:     map[string]api.TagReference{"t1": {DockerImageReference: "registry:5000/ns/stream:t1"}},
307
+			tags: map[string]api.TagReference{
308
+				"t1": {
309
+					From: &kapi.ObjectReference{
310
+						Kind: "DockerImage",
311
+						Name: "registry:5000/ns/stream:t1",
312
+					},
313
+				},
314
+			},
308 315
 			existingTagHistory: map[string]api.TagEventList{
309 316
 				"t2": {Items: []api.TagEvent{
310 317
 					{
... ...
@@ -335,16 +345,33 @@ func TestTagsChanged(t *testing.T) {
335 335
 			expectedTagHistory: map[string]api.TagEventList{},
336 336
 		},
337 337
 		"tag to missing ignored on create": {
338
-			stream:             "registry:5000/ns/stream",
339
-			tags:               map[string]api.TagReference{"t1": {DockerImageReference: "t2"}},
338
+			stream: "registry:5000/ns/stream",
339
+			tags: map[string]api.TagReference{
340
+				"t1": {
341
+					From: &kapi.ObjectReference{
342
+						Kind: "DockerImage",
343
+						Name: "t2",
344
+					},
345
+				},
346
+			},
340 347
 			existingTagHistory: make(map[string]api.TagEventList),
341 348
 			expectedTagHistory: map[string]api.TagEventList{},
342 349
 		},
343 350
 		"new tags, no history": {
344 351
 			stream: "registry:5000/ns/stream",
345 352
 			tags: map[string]api.TagReference{
346
-				"t1": {DockerImageReference: "registry:5000/ns/stream:t1"},
347
-				"t2": {DockerImageReference: "registry:5000/ns/stream@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
353
+				"t1": {
354
+					From: &kapi.ObjectReference{
355
+						Kind: "DockerImage",
356
+						Name: "registry:5000/ns/stream:t1",
357
+					},
358
+				},
359
+				"t2": {
360
+					From: &kapi.ObjectReference{
361
+						Kind: "DockerImage",
362
+						Name: "registry:5000/ns/stream@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
363
+					},
364
+				},
348 365
 			},
349 366
 			existingTagHistory: make(map[string]api.TagEventList),
350 367
 			expectedTagHistory: map[string]api.TagEventList{
... ...
@@ -364,12 +391,32 @@ func TestTagsChanged(t *testing.T) {
364 364
 		"no-op": {
365 365
 			stream: "registry:5000/ns/stream",
366 366
 			previous: map[string]api.TagReference{
367
-				"t1": {DockerImageReference: "v1image1"},
368
-				"t2": {DockerImageReference: "@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
367
+				"t1": {
368
+					From: &kapi.ObjectReference{
369
+						Kind: "DockerImage",
370
+						Name: "v1image1",
371
+					},
372
+				},
373
+				"t2": {
374
+					From: &kapi.ObjectReference{
375
+						Kind: "DockerImage",
376
+						Name: "@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
377
+					},
378
+				},
369 379
 			},
370 380
 			tags: map[string]api.TagReference{
371
-				"t1": {DockerImageReference: "v1image1"},
372
-				"t2": {DockerImageReference: "@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
381
+				"t1": {
382
+					From: &kapi.ObjectReference{
383
+						Kind: "DockerImage",
384
+						Name: "v1image1",
385
+					},
386
+				},
387
+				"t2": {
388
+					From: &kapi.ObjectReference{
389
+						Kind: "DockerImage",
390
+						Name: "@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
391
+					},
392
+				},
373 393
 			},
374 394
 			existingTagHistory: map[string]api.TagEventList{
375 395
 				"t1": {Items: []api.TagEvent{
... ...
@@ -403,13 +450,38 @@ func TestTagsChanged(t *testing.T) {
403 403
 		"new tag copies existing history": {
404 404
 			stream: "registry:5000/ns/stream",
405 405
 			previous: map[string]api.TagReference{
406
-				"t1": {DockerImageReference: "t1"},
407
-				"t3": {DockerImageReference: "@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
406
+				"t1": {
407
+					From: &kapi.ObjectReference{
408
+						Kind: "DockerImage",
409
+						Name: "t1",
410
+					},
411
+				},
412
+				"t3": {
413
+					From: &kapi.ObjectReference{
414
+						Kind: "DockerImage",
415
+						Name: "@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
416
+					},
417
+				},
408 418
 			},
409 419
 			tags: map[string]api.TagReference{
410
-				"t1": {DockerImageReference: "registry:5000/ns/stream:v1image1"},
411
-				"t2": {DockerImageReference: "registry:5000/ns/stream:v1image1"},
412
-				"t3": {DockerImageReference: "@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
420
+				"t1": {
421
+					From: &kapi.ObjectReference{
422
+						Kind: "DockerImage",
423
+						Name: "registry:5000/ns/stream:v1image1",
424
+					},
425
+				},
426
+				"t2": {
427
+					From: &kapi.ObjectReference{
428
+						Kind: "DockerImage",
429
+						Name: "registry:5000/ns/stream:v1image1",
430
+					},
431
+				},
432
+				"t3": {
433
+					From: &kapi.ObjectReference{
434
+						Kind: "DockerImage",
435
+						Name: "@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
436
+					},
437
+				},
413 438
 			},
414 439
 			existingTagHistory: map[string]api.TagEventList{
415 440
 				"t1": {Items: []api.TagEvent{
... ...
@@ -634,13 +706,13 @@ func TestTagRefChanged(t *testing.T) {
634 634
 			expected: false,
635 635
 		},
636 636
 		"same ref": {
637
-			old:      api.TagReference{DockerImageReference: "foo"},
638
-			next:     api.TagReference{DockerImageReference: "foo"},
637
+			old:      api.TagReference{From: &kapi.ObjectReference{Kind: "DockerImage", Name: "foo"}},
638
+			next:     api.TagReference{From: &kapi.ObjectReference{Kind: "DockerImage", Name: "foo"}},
639 639
 			expected: false,
640 640
 		},
641 641
 		"different ref": {
642
-			old:      api.TagReference{DockerImageReference: "foo"},
643
-			next:     api.TagReference{DockerImageReference: "bar"},
642
+			old:      api.TagReference{From: &kapi.ObjectReference{Kind: "DockerImage", Name: "foo"}},
643
+			next:     api.TagReference{From: &kapi.ObjectReference{Kind: "DockerImage", Name: "bar"}},
644 644
 			expected: true,
645 645
 		},
646 646
 		"no kind, no name": {
... ...
@@ -95,9 +95,6 @@ func (r *REST) Get(ctx kapi.Context, id string) (runtime.Object, error) {
95 95
 		if err != nil {
96 96
 			return nil, err
97 97
 		}
98
-		isi := api.ImageStreamImage{Image: *imageWithMetadata}
99
-		isi.ImageName = imageName
100
-		isi.Namespace = kapi.NamespaceValue(ctx)
101 98
 
102 99
 		if d, err := digest.ParseDigest(imageName); err == nil {
103 100
 			imageName = d.Hex()
... ...
@@ -105,7 +102,15 @@ func (r *REST) Get(ctx kapi.Context, id string) (runtime.Object, error) {
105 105
 		if len(imageName) > 7 {
106 106
 			imageName = imageName[:7]
107 107
 		}
108
-		isi.Name = fmt.Sprintf("%s@%s", name, imageName)
108
+
109
+		isi := api.ImageStreamImage{
110
+			ObjectMeta: kapi.ObjectMeta{
111
+				Namespace: kapi.NamespaceValue(ctx),
112
+				Name:      fmt.Sprintf("%s@%s", name, imageName),
113
+			},
114
+			Image: *imageWithMetadata,
115
+		}
116
+
109 117
 		return &isi, nil
110 118
 	case 0:
111 119
 		return nil, errors.NewNotFound("imageStreamImage", imageID)
... ...
@@ -232,7 +232,7 @@ func TestGet(t *testing.T) {
232 232
 		fakeEtcdClient, _, storage := setup(t)
233 233
 
234 234
 		if test.repo != nil {
235
-			fakeEtcdClient.Data["/imagerepositories/default/repo"] = tools.EtcdResponseWithError{
235
+			fakeEtcdClient.Data["/imagestreams/default/repo"] = tools.EtcdResponseWithError{
236 236
 				R: &etcd.Response{
237 237
 					Node: &etcd.Node{
238 238
 						Value: runtime.EncodeOrDie(latest.Codec, test.repo),
... ...
@@ -240,7 +240,7 @@ func TestGet(t *testing.T) {
240 240
 				},
241 241
 			}
242 242
 		} else {
243
-			fakeEtcdClient.Data["/imagerepositories/default/repo"] = tools.EtcdResponseWithError{
243
+			fakeEtcdClient.Data["/imagestreams/default/repo"] = tools.EtcdResponseWithError{
244 244
 				R: &etcd.Response{
245 245
 					Node: nil,
246 246
 				},
... ...
@@ -282,10 +282,10 @@ func TestGet(t *testing.T) {
282 282
 		if e, a := test.input, imageStreamImage.Name; e != a {
283 283
 			t.Errorf("%s: name: expected %q, got %q", name, e, a)
284 284
 		}
285
-		if e, a := "2d24f826cb16146e2016ff349a8a33ed5830f3b938d45c0f82943f4ab8c097e7", imageStreamImage.DockerImageMetadata.ID; e != a {
285
+		if e, a := "2d24f826cb16146e2016ff349a8a33ed5830f3b938d45c0f82943f4ab8c097e7", imageStreamImage.Image.DockerImageMetadata.ID; e != a {
286 286
 			t.Errorf("%s: id: expected %q, got %q", name, e, a)
287 287
 		}
288
-		if e, a := "43bd710ec89a", imageStreamImage.DockerImageMetadata.ContainerConfig.Hostname; e != a {
288
+		if e, a := "43bd710ec89a", imageStreamImage.Image.DockerImageMetadata.ContainerConfig.Hostname; e != a {
289 289
 			t.Errorf("%s: container config hostname: expected %q, got %q", name, e, a)
290 290
 		}
291 291
 	}
... ...
@@ -101,7 +101,7 @@ func TestCreateConflictingNamespace(t *testing.T) {
101 101
 
102 102
 func TestCreateImageStreamNotFoundWithName(t *testing.T) {
103 103
 	fakeEtcdClient, _, storage := setup(t)
104
-	fakeEtcdClient.ExpectNotFoundGet("/imagerepositories/default/somerepo")
104
+	fakeEtcdClient.ExpectNotFoundGet("/imagestreams/default/somerepo")
105 105
 
106 106
 	obj, err := storage.Create(kapi.NewDefaultContext(), validNewMappingWithName())
107 107
 	if obj != nil {
... ...
@@ -132,7 +132,7 @@ func TestCreateSuccessWithName(t *testing.T) {
132 132
 		ObjectMeta: kapi.ObjectMeta{Namespace: "default", Name: "somerepo"},
133 133
 	}
134 134
 
135
-	fakeEtcdClient.Data["/imagerepositories/default/somerepo"] = tools.EtcdResponseWithError{
135
+	fakeEtcdClient.Data["/imagestreams/default/somerepo"] = tools.EtcdResponseWithError{
136 136
 		R: &etcd.Response{
137 137
 			Node: &etcd.Node{
138 138
 				Value:         runtime.EncodeOrDie(latest.Codec, initialRepo),
... ...
@@ -159,7 +159,7 @@ func TestCreateSuccessWithName(t *testing.T) {
159 159
 	}
160 160
 
161 161
 	repo := &api.ImageStream{}
162
-	if err := helper.ExtractObj("/imagerepositories/default/somerepo", repo, false); err != nil {
162
+	if err := helper.ExtractObj("/imagestreams/default/somerepo", repo, false); err != nil {
163 163
 		t.Errorf("Unexpected non-nil err: %#v", err)
164 164
 	}
165 165
 	if e, a := "imageID1", repo.Status.Tags["latest"].Items[0].Image; e != a {
... ...
@@ -212,7 +212,7 @@ func TestAddExistingImageWithNewTag(t *testing.T) {
212 212
 	}
213 213
 
214 214
 	fakeEtcdClient, _, storage := setup(t)
215
-	fakeEtcdClient.Data["/imagerepositories/default"] = tools.EtcdResponseWithError{
215
+	fakeEtcdClient.Data["/imagestreams/default"] = tools.EtcdResponseWithError{
216 216
 		R: &etcd.Response{
217 217
 			Node: &etcd.Node{
218 218
 				Nodes: []*etcd.Node{
... ...
@@ -224,7 +224,7 @@ func TestAddExistingImageWithNewTag(t *testing.T) {
224 224
 			},
225 225
 		},
226 226
 	}
227
-	fakeEtcdClient.Data["/imagerepositories/default/somerepo"] = tools.EtcdResponseWithError{
227
+	fakeEtcdClient.Data["/imagestreams/default/somerepo"] = tools.EtcdResponseWithError{
228 228
 		R: &etcd.Response{
229 229
 			Node: &etcd.Node{
230 230
 				Value:         runtime.EncodeOrDie(latest.Codec, existingRepo),
... ...
@@ -291,7 +291,7 @@ func TestAddExistingImageAndTag(t *testing.T) {
291 291
 	}
292 292
 
293 293
 	fakeEtcdClient, _, storage := setup(t)
294
-	fakeEtcdClient.Data["/imagerepositories/default"] = tools.EtcdResponseWithError{
294
+	fakeEtcdClient.Data["/imagestreams/default"] = tools.EtcdResponseWithError{
295 295
 		R: &etcd.Response{
296 296
 			Node: &etcd.Node{
297 297
 				Nodes: []*etcd.Node{
... ...
@@ -303,7 +303,7 @@ func TestAddExistingImageAndTag(t *testing.T) {
303 303
 			},
304 304
 		},
305 305
 	}
306
-	fakeEtcdClient.Data["/imagerepositories/default/somerepo"] = tools.EtcdResponseWithError{
306
+	fakeEtcdClient.Data["/imagestreams/default/somerepo"] = tools.EtcdResponseWithError{
307 307
 		R: &etcd.Response{
308 308
 			Node: &etcd.Node{
309 309
 				Value:         runtime.EncodeOrDie(latest.Codec, existingRepo),
... ...
@@ -385,7 +385,7 @@ func TestTrackingTags(t *testing.T) {
385 385
 		},
386 386
 	}
387 387
 
388
-	if err := etcdHelper.CreateObj("/imagerepositories/default/stream", &stream, nil, 0); err != nil {
388
+	if err := etcdHelper.CreateObj("/imagestreams/default/stream", &stream, nil, 0); err != nil {
389 389
 		t.Fatalf("Unable to create stream: %v", err)
390 390
 	}
391 391
 
... ...
@@ -410,7 +410,7 @@ func TestTrackingTags(t *testing.T) {
410 410
 		t.Fatalf("Unexpected error creating mapping: %v", err)
411 411
 	}
412 412
 
413
-	if err := etcdHelper.ExtractObj("/imagerepositories/default/stream", &stream, false); err != nil {
413
+	if err := etcdHelper.ExtractObj("/imagestreams/default/stream", &stream, false); err != nil {
414 414
 		t.Fatalf("error extracting updated stream: %v", err)
415 415
 	}
416 416
 
... ...
@@ -88,11 +88,12 @@ func (r *REST) Get(ctx kapi.Context, id string) (runtime.Object, error) {
88 88
 	}
89 89
 
90 90
 	ist := api.ImageStreamTag{
91
-		Image:     *imageWithMetadata,
92
-		ImageName: imageWithMetadata.Name,
91
+		ObjectMeta: kapi.ObjectMeta{
92
+			Namespace: kapi.NamespaceValue(ctx),
93
+			Name:      id,
94
+		},
95
+		Image: *imageWithMetadata,
93 96
 	}
94
-	ist.Namespace = kapi.NamespaceValue(ctx)
95
-	ist.Name = id
96 97
 	return &ist, nil
97 98
 }
98 99
 
... ...
@@ -211,7 +211,7 @@ func TestGetImageStreamTag(t *testing.T) {
211 211
 		}
212 212
 
213 213
 		if testCase.repo != nil {
214
-			fakeEtcdClient.Data["/imagerepositories/default/test"] = tools.EtcdResponseWithError{
214
+			fakeEtcdClient.Data["/imagestreams/default/test"] = tools.EtcdResponseWithError{
215 215
 				R: &etcd.Response{
216 216
 					Node: &etcd.Node{
217 217
 						Value:         runtime.EncodeOrDie(latest.Codec, testCase.repo),
... ...
@@ -220,7 +220,7 @@ func TestGetImageStreamTag(t *testing.T) {
220 220
 				},
221 221
 			}
222 222
 		} else {
223
-			fakeEtcdClient.Data["/imagerepositories/default/test"] = tools.EtcdResponseWithError{
223
+			fakeEtcdClient.Data["/imagestreams/default/test"] = tools.EtcdResponseWithError{
224 224
 				R: &etcd.Response{
225 225
 					Node: nil,
226 226
 				},
... ...
@@ -249,7 +249,7 @@ func TestGetImageStreamTag(t *testing.T) {
249 249
 			if e, a := "test:latest", actual.Name; e != a {
250 250
 				t.Errorf("%s: name: expected %v, got %v", name, e, a)
251 251
 			}
252
-			if e, a := map[string]string{"size": "large", "color": "blue"}, actual.Annotations; !reflect.DeepEqual(e, a) {
252
+			if e, a := map[string]string{"size": "large", "color": "blue"}, actual.Image.Annotations; !reflect.DeepEqual(e, a) {
253 253
 				t.Errorf("%s: annotations: expected %v, got %v", name, e, a)
254 254
 			}
255 255
 		}
... ...
@@ -358,7 +358,7 @@ func TestDeleteImageStreamTag(t *testing.T) {
358 358
 	for name, testCase := range tests {
359 359
 		fakeEtcdClient, helper, storage := setup(t)
360 360
 		if testCase.repo != nil {
361
-			fakeEtcdClient.Data["/imagerepositories/default/test"] = tools.EtcdResponseWithError{
361
+			fakeEtcdClient.Data["/imagestreams/default/test"] = tools.EtcdResponseWithError{
362 362
 				R: &etcd.Response{
363 363
 					Node: &etcd.Node{
364 364
 						Value:         runtime.EncodeOrDie(latest.Codec, testCase.repo),
... ...
@@ -367,7 +367,7 @@ func TestDeleteImageStreamTag(t *testing.T) {
367 367
 				},
368 368
 			}
369 369
 		} else {
370
-			fakeEtcdClient.Data["/imagerepositories/default/test"] = tools.EtcdResponseWithError{
370
+			fakeEtcdClient.Data["/imagestreams/default/test"] = tools.EtcdResponseWithError{
371 371
 				R: &etcd.Response{
372 372
 					Node: nil,
373 373
 				},
... ...
@@ -394,7 +394,7 @@ func TestDeleteImageStreamTag(t *testing.T) {
394 394
 		}
395 395
 
396 396
 		updatedRepo := &api.ImageStream{}
397
-		if err := helper.ExtractObj("/imagerepositories/default/test", updatedRepo, false); err != nil {
397
+		if err := helper.ExtractObj("/imagestreams/default/test", updatedRepo, false); err != nil {
398 398
 			t.Fatalf("%s: error retrieving updated repo: %s", name, err)
399 399
 		}
400 400
 		expected := map[string]api.TagReference{
401 401
deleted file mode 100644
... ...
@@ -1,66 +0,0 @@
1
-{
2
-  "kind": "ImageStreamMapping",
3
-  "apiVersion": "v1beta3",
4
-  "metadata": {
5
-    "name": "test",
6
-    "creationTimestamp": null
7
-  },
8
-  "image": {
9
-    "metadata": {
10
-      "name": "abcd1234",
11
-      "creationTimestamp": null
12
-    },
13
-    "dockerImageReference": "openshift/ruby-19-centos:latest",
14
-    "dockerImageMetadata": {
15
-      "kind": "DockerImage",
16
-      "apiVersion": "1.0",
17
-      "Id": "7dbbbc6cb29d5abc29b722c06d5209a499fa97cd655c59793540d00933ab4e45",
18
-      "Parent": "dde5ee6a036d5d2c69240413fa8f3bb9bb1fea25166996eadf42e2f113736401",
19
-      "Created": "2014-08-08T14:36:01Z",
20
-      "Container": "72ce367abbc2862232b5e5e3485e51f096983e4e28b8dbefba9a6fd5ce0d6e48",
21
-      "ContainerConfig": {
22
-        "Hostname": "df1704c4368e",
23
-        "User": "ruby",
24
-        "ExposedPorts": {
25
-          "9292/tcp": {}
26
-        },
27
-        "Env": [
28
-          "HOME=/opt/ruby",
29
-          "PATH=/opt/ruby/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
30
-          "STI_SCRIPTS_URL=https://raw.githubusercontent.com/openshift/ruby-19-centos/master/.sti/bin",
31
-          "APP_ROOT=."
32
-        ],
33
-        "Cmd": [
34
-          "/bin/sh",
35
-          "-c",
36
-          "#(nop) CMD [/opt/ruby/bin/usage]"
37
-        ],
38
-        "Image": "dde5ee6a036d5d2c69240413fa8f3bb9bb1fea25166996eadf42e2f113736401",
39
-        "WorkingDir": "/opt/ruby/src"
40
-      },
41
-      "DockerVersion": "1.1.2-dev",
42
-      "Author": "Michal Fojtik \u003cmfojtik@redhat.com\u003e",
43
-      "Config": {
44
-        "Hostname": "df1704c4368e",
45
-        "User": "ruby",
46
-        "ExposedPorts": {
47
-          "9292/tcp": {}
48
-        },
49
-        "Env": [
50
-          "HOME=/opt/ruby",
51
-          "PATH=/opt/ruby/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
52
-          "STI_SCRIPTS_URL=https://raw.githubusercontent.com/openshift/ruby-19-centos/master/.sti/bin",
53
-          "APP_ROOT=."
54
-        ],
55
-        "Cmd": [
56
-          "/opt/ruby/bin/usage"
57
-        ],
58
-        "Image": "dde5ee6a036d5d2c69240413fa8f3bb9bb1fea25166996eadf42e2f113736401",
59
-        "WorkingDir": "/opt/ruby/src"
60
-      },
61
-      "Architecture": "amd64"
62
-    },
63
-    "dockerImageMetadataVersion": "1.0"
64
-  },
65
-  "tag": "sometag"
66
-}
67 1
\ No newline at end of file
68 2
deleted file mode 100644
... ...
@@ -1,15 +0,0 @@
1
-{
2
-  "kind": "ImageStream",
3
-  "apiVersion": "v1beta3",
4
-  "metadata": {
5
-    "name": "test",
6
-    "creationTimestamp": null,
7
-    "labels": {
8
-      "color": "blue"
9
-    }
10
-  },
11
-  "spec": {},
12
-  "status": {
13
-    "dockerImageRepository": ""
14
-  }
15
-}
16 1
\ No newline at end of file
... ...
@@ -126,7 +126,10 @@ func mockImageStream2(tag string) *imageapi.ImageStream {
126 126
 			DockerImageRepository: "registry:8080/openshift/test-image-trigger",
127 127
 			Tags: map[string]imageapi.TagReference{
128 128
 				tag: {
129
-					DockerImageReference: "registry:8080/openshift/test-image-trigger:" + tag,
129
+					From: &kapi.ObjectReference{
130
+						Kind: "DockerImage",
131
+						Name: "registry:8080/openshift/test-image-trigger:" + tag,
132
+					},
130 133
 				},
131 134
 			},
132 135
 		},
... ...
@@ -191,7 +191,7 @@ func TestImageStreamMappingCreate(t *testing.T) {
191 191
 	if err != nil {
192 192
 		t.Fatalf("Unexpected error: %v", err)
193 193
 	}
194
-	if fromTag.Name != "test:newer" || fromTag.UID == "" || fromTag.DockerImageReference != "some/other/name" {
194
+	if fromTag.Name != "test:newer" || fromTag.UID == "" || fromTag.Image.DockerImageReference != "some/other/name" {
195 195
 		t.Errorf("unexpected object: %#v", fromTag)
196 196
 	}
197 197
 
... ...
@@ -199,7 +199,7 @@ func TestImageStreamMappingCreate(t *testing.T) {
199 199
 	if err != nil {
200 200
 		t.Fatalf("Unexpected error: %v", err)
201 201
 	}
202
-	if fromTag.Name != "test:newest" || fromTag.UID == "" || fromTag.DockerImageReference != "some/other/name" {
202
+	if fromTag.Name != "test:newest" || fromTag.UID == "" || fromTag.Image.DockerImageReference != "some/other/name" {
203 203
 		t.Errorf("unexpected object: %#v", fromTag)
204 204
 	}
205 205
 
... ...
@@ -226,7 +226,7 @@ func TestImageStreamMappingCreate(t *testing.T) {
226 226
 	if err != nil {
227 227
 		t.Fatalf("Unexpected error: %v", err)
228 228
 	}
229
-	if fromTag.Name != "test:newer" || fromTag.UID == "" || fromTag.DockerImageReference != "some/other/name" {
229
+	if fromTag.Name != "test:newer" || fromTag.UID == "" || fromTag.Image.DockerImageReference != "some/other/name" {
230 230
 		t.Errorf("unexpected object: %#v", fromTag)
231 231
 	}
232 232
 
... ...
@@ -234,14 +234,14 @@ func TestImageStreamMappingCreate(t *testing.T) {
234 234
 	if err != nil {
235 235
 		t.Fatalf("Unexpected error: %v", err)
236 236
 	}
237
-	if fromTag.Name != "test:newest" || fromTag.UID == "" || fromTag.DockerImageReference != "some/other/name" {
237
+	if fromTag.Name != "test:newest" || fromTag.UID == "" || fromTag.Image.DockerImageReference != "some/other/name" {
238 238
 		t.Errorf("unexpected object: %#v", fromTag)
239 239
 	}
240 240
 	fromTag, err = clusterAdminClient.ImageStreamTags(testutil.Namespace()).Get(stream.Name, "anothertag")
241 241
 	if err != nil {
242 242
 		t.Fatalf("Unexpected error: %v", err)
243 243
 	}
244
-	if fromTag.Name != "test:anothertag" || fromTag.UID == "" || fromTag.DockerImageReference != "some/other/name" {
244
+	if fromTag.Name != "test:anothertag" || fromTag.UID == "" || fromTag.Image.DockerImageReference != "some/other/name" {
245 245
 		t.Errorf("unexpected object: %#v", fromTag)
246 246
 	}
247 247
 
... ...
@@ -211,13 +211,13 @@ middleware:
211 211
 	if e, a := fmt.Sprintf("test@%s", dgst.Hex()[:7]), image.Name; e != a {
212 212
 		t.Errorf("image name: expected %q, got %q", e, a)
213 213
 	}
214
-	if e, a := dgst.String(), image.ImageName; e != a {
214
+	if e, a := dgst.String(), image.Image.Name; e != a {
215 215
 		t.Errorf("image name: expected %q, got %q", e, a)
216 216
 	}
217
-	if e, a := fmt.Sprintf("127.0.0.1:5000/%s/%s@%s", testutil.Namespace(), stream.Name, dgst.String()), image.DockerImageReference; e != a {
217
+	if e, a := fmt.Sprintf("127.0.0.1:5000/%s/%s@%s", testutil.Namespace(), stream.Name, dgst.String()), image.Image.DockerImageReference; e != a {
218 218
 		t.Errorf("image dockerImageReference: expected %q, got %q", e, a)
219 219
 	}
220
-	if e, a := "foo", image.DockerImageMetadata.ID; e != a {
220
+	if e, a := "foo", image.Image.DockerImageMetadata.ID; e != a {
221 221
 		t.Errorf("image dockerImageMetadata.ID: expected %q, got %q", e, a)
222 222
 	}
223 223
 
... ...
@@ -59,7 +59,10 @@ func TestWebhookGithubPushWithImage(t *testing.T) {
59 59
 			DockerImageRepository: "registry:3000/integration/imageStream",
60 60
 			Tags: map[string]imageapi.TagReference{
61 61
 				"validTag": {
62
-					DockerImageReference: "registry:3000/integration/imageStream:success",
62
+					From: &kapi.ObjectReference{
63
+						Kind: "DockerImage",
64
+						Name: "registry:3000/integration/imageStream:success",
65
+					},
63 66
 				},
64 67
 			},
65 68
 		},
... ...
@@ -154,7 +157,10 @@ func TestWebhookGithubPushWithImageStream(t *testing.T) {
154 154
 			DockerImageRepository: "registry:3000/integration/imageStream",
155 155
 			Tags: map[string]imageapi.TagReference{
156 156
 				"validTag": {
157
-					DockerImageReference: "registry:3000/integration/imageStream:success",
157
+					From: &kapi.ObjectReference{
158
+						Kind: "DockerImage",
159
+						Name: "registry:3000/integration/imageStream:success",
160
+					},
158 161
 				},
159 162
 			},
160 163
 		},