Browse Source

Conflate Image and ImageDescription

These two types have the same fields and are put to the same use, so
just use one of them everywhere.

Also, use a time.Time value rather than a pointer, and fall back to
time.IsZero() to detect missing/uninitialised values. Although it's
nice to have a nullable value and rely on the JSON encoder to miss it
out or serialise it to `null`, it is also a repeating source of
confusion, since it's unusual to use a pointer to a value type.

The custom JSON marshalling is not strictly necessary (a zero time
value will roundtrip), it's tidier and matches the expectation from
clients of the API.

The latter is also the reason for naming the ID field: in the API it
is serialised as `ID`, so it is simpler to just call it that
everywhere.
Michael Bridgen 2 years ago
parent
commit
e7721cf01d

+ 1
- 1
cmd/fluxctl/list_images_cmd.go View File

@@ -90,7 +90,7 @@ func (opts *serviceShowOpts) RunE(_ *cobra.Command, args []string) error {
90 90
 				}
91 91
 				if printLine {
92 92
 					createdAt := ""
93
-					if available.CreatedAt != nil {
93
+					if !available.CreatedAt.IsZero() {
94 94
 						createdAt = available.CreatedAt.Format(time.RFC822)
95 95
 					}
96 96
 					fmt.Fprintf(out, "\t\t%s %s\t%s\n", running, tag, createdAt)

+ 3
- 3
cmd/fluxsvc/fluxsvc_test.go View File

@@ -74,7 +74,7 @@ func setup() {
74 74
 				Containers: []flux.Container{
75 75
 					flux.Container{
76 76
 						Name: "helloworld",
77
-						Current: flux.ImageDescription{
77
+						Current: flux.Image{
78 78
 							ID: imageID,
79 79
 						},
80 80
 					},
@@ -88,7 +88,7 @@ func setup() {
88 88
 				Containers: []flux.Container{
89 89
 					flux.Container{
90 90
 						Name: "helloworld",
91
-						Current: flux.ImageDescription{
91
+						Current: flux.Image{
92 92
 							ID: imageID,
93 93
 						},
94 94
 					},
@@ -99,7 +99,7 @@ func setup() {
99 99
 				Containers: []flux.Container{
100 100
 					flux.Container{
101 101
 						Name: "helloworld",
102
-						Current: flux.ImageDescription{
102
+						Current: flux.Image{
103 103
 							ID: imageID,
104 104
 						},
105 105
 					},

+ 2
- 2
daemon/daemon.go View File

@@ -318,7 +318,7 @@ func containers2containers(cs []cluster.Container) []flux.Container {
318 318
 		id, _ := flux.ParseImageID(c.Image)
319 319
 		res[i] = flux.Container{
320 320
 			Name: c.Name,
321
-			Current: flux.ImageDescription{
321
+			Current: flux.Image{
322 322
 				ID: id,
323 323
 			},
324 324
 		}
@@ -333,7 +333,7 @@ func containersWithAvailable(service cluster.Service, images release.ImageMap) (
333 333
 		available := images[repo]
334 334
 		res = append(res, flux.Container{
335 335
 			Name: c.Name,
336
-			Current: flux.ImageDescription{
336
+			Current: flux.Image{
337 337
 				ID: id,
338 338
 			},
339 339
 			Available: available,

+ 35
- 4
image.go View File

@@ -122,17 +122,48 @@ func (i ImageID) Components() (host, repo, tag string) {
122 122
 // Image can't really be a primitive string only, because we need to also
123 123
 // record information about its creation time. (maybe more in the future)
124 124
 type Image struct {
125
-	ImageID
126
-	CreatedAt *time.Time `json:",omitempty"`
125
+	ID        ImageID
126
+	CreatedAt time.Time
127 127
 }
128 128
 
129
-func ParseImage(s string, createdAt *time.Time) (Image, error) {
129
+func (im Image) MarshalJSON() ([]byte, error) {
130
+	var t string
131
+	if !im.CreatedAt.IsZero() {
132
+		t = im.CreatedAt.UTC().Format(time.RFC3339Nano)
133
+	}
134
+	encode := struct {
135
+		ID        ImageID
136
+		CreatedAt string `json:",omitempty"`
137
+	}{im.ID, t}
138
+	return json.Marshal(encode)
139
+}
140
+
141
+func (im *Image) UnmarshalJSON(b []byte) error {
142
+	unencode := struct {
143
+		ID        ImageID
144
+		CreatedAt string `json:",omitempty"`
145
+	}{}
146
+	json.Unmarshal(b, &unencode)
147
+	im.ID = unencode.ID
148
+	if unencode.CreatedAt == "" {
149
+		im.CreatedAt = time.Time{}
150
+	} else {
151
+		t, err := time.Parse(time.RFC3339, unencode.CreatedAt)
152
+		if err != nil {
153
+			return err
154
+		}
155
+		im.CreatedAt = t.UTC()
156
+	}
157
+	return nil
158
+}
159
+
160
+func ParseImage(s string, createdAt time.Time) (Image, error) {
130 161
 	id, err := ParseImageID(s)
131 162
 	if err != nil {
132 163
 		return Image{}, err
133 164
 	}
134 165
 	return Image{
135
-		ImageID:   id,
166
+		ID:        id,
136 167
 		CreatedAt: createdAt,
137 168
 	}, nil
138 169
 }

+ 3
- 3
registry/mock.go View File

@@ -8,7 +8,7 @@ import (
8 8
 )
9 9
 
10 10
 type mockClientAdapter struct {
11
-	imgs []flux.ImageDescription
11
+	imgs []flux.Image
12 12
 	err  error
13 13
 }
14 14
 
@@ -92,7 +92,7 @@ func (m *mockRegistry) GetRepository(repository Repository) ([]flux.Image, error
92 92
 	var imgs []flux.Image
93 93
 	for _, i := range m.imgs {
94 94
 		// include only if it's the same repository in the same place
95
-		if i.ImageID.NamespaceImage() == repository.NamespaceImage() {
95
+		if i.ID.NamespaceImage() == repository.NamespaceImage() {
96 96
 			imgs = append(imgs, i)
97 97
 		}
98 98
 	}
@@ -102,7 +102,7 @@ func (m *mockRegistry) GetRepository(repository Repository) ([]flux.Image, error
102 102
 func (m *mockRegistry) GetImage(repository Repository, tag string) (flux.Image, error) {
103 103
 	if len(m.imgs) > 0 {
104 104
 		for _, i := range m.imgs {
105
-			if i.String() == repository.ToImage(tag).String() {
105
+			if i.ID.String() == repository.ToImage(tag).ID.String() {
106 106
 				return i, nil
107 107
 			}
108 108
 		}

+ 7
- 7
registry/registry.go View File

@@ -128,14 +128,14 @@ type byCreatedDesc []flux.Image
128 128
 func (is byCreatedDesc) Len() int      { return len(is) }
129 129
 func (is byCreatedDesc) Swap(i, j int) { is[i], is[j] = is[j], is[i] }
130 130
 func (is byCreatedDesc) Less(i, j int) bool {
131
-	if is[i].CreatedAt == nil {
131
+	switch {
132
+	case is[i].CreatedAt.IsZero():
132 133
 		return true
133
-	}
134
-	if is[j].CreatedAt == nil {
134
+	case is[j].CreatedAt.IsZero():
135 135
 		return false
136
+	case is[i].CreatedAt.Equal(is[j].CreatedAt):
137
+		return is[i].ID.String() < is[j].ID.String()
138
+	default:
139
+		return is[i].CreatedAt.After(is[j].CreatedAt)
136 140
 	}
137
-	if is[i].CreatedAt.Equal(*is[j].CreatedAt) {
138
-		return is[i].String() < is[j].String()
139
-	}
140
-	return is[i].CreatedAt.After(*is[j].CreatedAt)
141 141
 }

+ 15
- 13
registry/registry_test.go View File

@@ -1,6 +1,7 @@
1 1
 package registry
2 2
 
3 3
 import (
4
+	"fmt"
4 5
 	"sort"
5 6
 	"strconv"
6 7
 	"testing"
@@ -16,24 +17,24 @@ var (
16 17
 	testTags    = []string{testTagStr, "anotherTag"}
17 18
 	mRemote     = NewMockRemote(img, testTags, nil)
18 19
 	mRemoteFact = NewMockRemoteFactory(mRemote, nil)
19
-	testTime, _ = time.Parse(constTime, time.RFC3339Nano)
20
+	testTime, _ = time.Parse(time.RFC3339Nano, constTime)
20 21
 )
21 22
 
22 23
 func TestRegistry_GetImage(t *testing.T) {
23 24
 	reg := NewRegistry(mRemoteFact, log.NewNopLogger())
24
-	newImg, err := reg.GetImage(testRepository, img.Tag)
25
+	newImg, err := reg.GetImage(testRepository, img.ID.Tag)
25 26
 	if err != nil {
26 27
 		t.Fatal(err)
27 28
 	}
28
-	if img.String() != newImg.String() {
29
-		t.Fatal("Expected %v, but got %v", img.String(), newImg.String())
29
+	if img.ID.String() != newImg.ID.String() {
30
+		t.Fatal("Expected %v, but got %v", img.ID.String(), newImg.ID.String())
30 31
 	}
31 32
 }
32 33
 
33 34
 func TestRegistry_GetImageFactoryErr(t *testing.T) {
34 35
 	errFact := NewMockRemoteFactory(mRemote, errors.New(""))
35 36
 	reg := NewRegistry(errFact, nil)
36
-	_, err := reg.GetImage(testRepository, img.Tag)
37
+	_, err := reg.GetImage(testRepository, img.ID.Tag)
37 38
 	if err == nil {
38 39
 		t.Fatal("Expecting error")
39 40
 	}
@@ -43,7 +44,7 @@ func TestRegistry_GetImageRemoteErr(t *testing.T) {
43 44
 	r := NewMockRemote(img, testTags, errors.New(""))
44 45
 	errFact := NewMockRemoteFactory(r, nil)
45 46
 	reg := NewRegistry(errFact, log.NewNopLogger())
46
-	_, err := reg.GetImage(testRepository, img.Tag)
47
+	_, err := reg.GetImage(testRepository, img.ID.Tag)
47 48
 	if err == nil {
48 49
 		t.Fatal("Expecting error")
49 50
 	}
@@ -92,19 +93,20 @@ func TestRegistry_GetRepositoryManifestError(t *testing.T) {
92 93
 }
93 94
 
94 95
 func TestRegistry_OrderByCreationDate(t *testing.T) {
96
+	fmt.Printf("testTime: %s\n", testTime)
95 97
 	time0 := testTime.Add(time.Second)
96 98
 	time2 := testTime.Add(-time.Second)
97
-	imA, _ := flux.ParseImage("my/Image:3", &testTime)
98
-	imB, _ := flux.ParseImage("my/Image:1", &time0)
99
-	imC, _ := flux.ParseImage("my/Image:4", &time2)
100
-	imD, _ := flux.ParseImage("my/Image:0", nil)       // test nil
101
-	imE, _ := flux.ParseImage("my/Image:2", &testTime) // test equal
99
+	imA, _ := flux.ParseImage("my/Image:3", testTime)
100
+	imB, _ := flux.ParseImage("my/Image:1", time0)
101
+	imC, _ := flux.ParseImage("my/Image:4", time2)
102
+	imD, _ := flux.ParseImage("my/Image:0", time.Time{}) // test nil
103
+	imE, _ := flux.ParseImage("my/Image:2", testTime)    // test equal
102 104
 	imgs := []flux.Image{imA, imB, imC, imD, imE}
103 105
 	sort.Sort(byCreatedDesc(imgs))
104 106
 	for i, im := range imgs {
105
-		if strconv.Itoa(i) != im.Tag {
107
+		if strconv.Itoa(i) != im.ID.Tag {
106 108
 			for j, jim := range imgs {
107
-				t.Logf("%v: %v", j, jim.String())
109
+				t.Logf("%v: %v %s", j, jim.ID.String(), jim.CreatedAt)
108 110
 			}
109 111
 			t.Fatalf("Not sorted in expected order: %#v", imgs)
110 112
 		}

+ 2
- 2
registry/remote.go View File

@@ -34,7 +34,7 @@ func (rc *remote) Tags(repository Repository) (_ []string, err error) {
34 34
 }
35 35
 
36 36
 func (rc *remote) Manifest(repository Repository, tag string) (img flux.Image, err error) {
37
-	img, err = flux.ParseImage(fmt.Sprintf("%s:%s", repository.String(), tag), nil)
37
+	img, err = flux.ParseImage(fmt.Sprintf("%s:%s", repository.String(), tag), time.Time{})
38 38
 	if err != nil {
39 39
 		return
40 40
 	}
@@ -55,7 +55,7 @@ func (rc *remote) Manifest(repository Repository, tag string) (img flux.Image, e
55 55
 	if len(history) > 0 {
56 56
 		if err = json.Unmarshal([]byte(history[0].V1Compatibility), &topmost); err == nil {
57 57
 			if !topmost.Created.IsZero() {
58
-				img.CreatedAt = &topmost.Created
58
+				img.CreatedAt = topmost.Created
59 59
 			}
60 60
 		}
61 61
 	}

+ 6
- 6
registry/remote_factory_test.go View File

@@ -18,7 +18,7 @@ import (
18 18
 func TestRemoteFactory_CreateForDockerHub(t *testing.T) {
19 19
 	// No credentials required for public Image
20 20
 	fact := NewRemoteClientFactory(Credentials{}, log.NewNopLogger(), nil, time.Second)
21
-	img, err := flux.ParseImage("alpine:latest", nil)
21
+	img, err := flux.ParseImage("alpine:latest", time.Time{})
22 22
 	testRepository = RepositoryFromImage(img)
23 23
 	if err != nil {
24 24
 		t.Fatal(err)
@@ -27,19 +27,19 @@ func TestRemoteFactory_CreateForDockerHub(t *testing.T) {
27 27
 	if err != nil {
28 28
 		t.Fatal(err)
29 29
 	}
30
-	res, err := r.Manifest(testRepository, img.Tag)
30
+	res, err := r.Manifest(testRepository, img.ID.Tag)
31 31
 	if err != nil {
32 32
 		t.Fatal(err)
33 33
 	}
34 34
 	expected := "index.docker.io/library/alpine:latest"
35
-	if res.FullID() != expected {
36
-		t.Fatal("Expected %q. Got %q", expected, res.FullID())
35
+	if res.ID.FullID() != expected {
36
+		t.Fatal("Expected %q. Got %q", expected, res.ID.FullID())
37 37
 	}
38 38
 }
39 39
 
40 40
 func TestRemoteFactory_InvalidHost(t *testing.T) {
41 41
 	fact := NewRemoteClientFactory(Credentials{}, log.NewNopLogger(), nil, time.Second)
42
-	img, err := flux.ParseImage("invalid.host/library/alpine:latest", nil)
42
+	img, err := flux.ParseImage("invalid.host/library/alpine:latest", time.Time{})
43 43
 	if err != nil {
44 44
 		t.Fatal(err)
45 45
 	}
@@ -48,7 +48,7 @@ func TestRemoteFactory_InvalidHost(t *testing.T) {
48 48
 	if err != nil {
49 49
 		t.Fatal(err)
50 50
 	}
51
-	_, err = r.Manifest(testRepository, img.Tag)
51
+	_, err = r.Manifest(testRepository, img.ID.Tag)
52 52
 	if err == nil {
53 53
 		t.Fatal("Expected error due to invalid host but got none.")
54 54
 	}

+ 5
- 5
registry/remote_test.go View File

@@ -15,7 +15,7 @@ const testImageStr = "index.docker.io/test/Image:" + testTagStr
15 15
 const constTime = "2017-01-13T16:22:58.009923189Z"
16 16
 
17 17
 var (
18
-	img, _         = flux.ParseImage(testImageStr, nil)
18
+	img, _         = flux.ParseImage(testImageStr, time.Time{})
19 19
 	testRepository = RepositoryFromImage(img)
20 20
 
21 21
 	man = schema1.SignedManifest{
@@ -38,12 +38,12 @@ func TestRemoteClient_ParseManifest(t *testing.T) {
38 38
 		client: NewMockDockerClient(manifestFunc, nil),
39 39
 	}
40 40
 	testRepository = RepositoryFromImage(img)
41
-	desc, err := c.Manifest(testRepository, img.Tag)
41
+	desc, err := c.Manifest(testRepository, img.ID.Tag)
42 42
 	if err != nil {
43 43
 		t.Fatal(err.Error())
44 44
 	}
45
-	if string(desc.FullID()) != testImageStr {
46
-		t.Fatalf("Expecting %q but got %q", testImageStr, string(desc.FullID()))
45
+	if string(desc.ID.FullID()) != testImageStr {
46
+		t.Fatalf("Expecting %q but got %q", testImageStr, string(desc.ID.FullID()))
47 47
 	}
48 48
 	if desc.CreatedAt.Format(time.RFC3339Nano) != constTime {
49 49
 		t.Fatalf("Expecting %q but got %q", constTime, desc.CreatedAt.Format(time.RFC3339Nano))
@@ -95,7 +95,7 @@ func TestRemoteClient_RemoteErrors(t *testing.T) {
95 95
 	if err == nil {
96 96
 		t.Fatal("Expected error")
97 97
 	}
98
-	_, err = c.Manifest(testRepository, img.Tag)
98
+	_, err = c.Manifest(testRepository, img.ID.Tag)
99 99
 	if err == nil {
100 100
 		t.Fatal("Expected error")
101 101
 	}

+ 7
- 5
registry/repository.go View File

@@ -1,6 +1,8 @@
1 1
 package registry
2 2
 
3 3
 import (
4
+	"time"
5
+
4 6
 	"github.com/weaveworks/flux"
5 7
 )
6 8
 
@@ -15,7 +17,7 @@ func RepositoryFromImage(img flux.Image) Repository {
15 17
 }
16 18
 
17 19
 func ParseRepository(imgStr string) (Repository, error) {
18
-	i, err := flux.ParseImage(imgStr, nil)
20
+	i, err := flux.ParseImage(imgStr, time.Time{})
19 21
 	if err != nil {
20 22
 		return Repository{}, err
21 23
 	}
@@ -25,19 +27,19 @@ func ParseRepository(imgStr string) (Repository, error) {
25 27
 }
26 28
 
27 29
 func (r Repository) NamespaceImage() string {
28
-	return r.img.NamespaceImage()
30
+	return r.img.ID.NamespaceImage()
29 31
 }
30 32
 
31 33
 func (r Repository) Host() string {
32
-	return r.img.Host
34
+	return r.img.ID.Host
33 35
 }
34 36
 
35 37
 func (r Repository) String() string {
36
-	return r.img.HostNamespaceImage()
38
+	return r.img.ID.HostNamespaceImage()
37 39
 }
38 40
 
39 41
 func (r Repository) ToImage(tag string) flux.Image {
40 42
 	newImage := r.img
41
-	newImage.Tag = tag
43
+	newImage.ID.Tag = tag
42 44
 	return newImage
43 45
 }

+ 7
- 18
release/images.go View File

@@ -3,6 +3,7 @@ package release
3 3
 import (
4 4
 	"fmt"
5 5
 	"strings"
6
+	"time"
6 7
 
7 8
 	"github.com/pkg/errors"
8 9
 
@@ -35,19 +36,7 @@ func CollectAvailableImages(reg registry.Registry, services []cluster.Service) (
35 36
 		if err != nil {
36 37
 			return nil, errors.Wrapf(err, "fetching image metadata for %s", repo)
37 38
 		}
38
-		res := make([]flux.ImageDescription, len(imageRepo))
39
-		for i, im := range imageRepo {
40
-			id, err := flux.ParseImageID(im.String())
41
-			if err != nil {
42
-				// registry returned an invalid image id
43
-				return nil, err
44
-			}
45
-			res[i] = flux.ImageDescription{
46
-				ID:        id,
47
-				CreatedAt: im.CreatedAt,
48
-			}
49
-		}
50
-		images[repo] = res
39
+		images[repo] = imageRepo
51 40
 	}
52 41
 	return images, nil
53 42
 }
@@ -57,7 +46,7 @@ func CollectAvailableImages(reg registry.Registry, services []cluster.Service) (
57 46
 // available images are in descending order of latestness.) If no such
58 47
 // image exists, returns nil, and the caller can decide whether that's
59 48
 // an error or not.
60
-func (m ImageMap) LatestImage(repo string) *flux.ImageDescription {
49
+func (m ImageMap) LatestImage(repo string) *flux.Image {
61 50
 	for _, image := range m[repo] {
62 51
 		_, _, tag := image.ID.Components()
63 52
 		if strings.EqualFold(tag, "latest") {
@@ -69,7 +58,7 @@ func (m ImageMap) LatestImage(repo string) *flux.ImageDescription {
69 58
 }
70 59
 
71 60
 // For keeping track of which images are available
72
-type ImageMap map[string][]flux.ImageDescription
61
+type ImageMap map[string][]flux.Image
73 62
 
74 63
 // Create a map of images. It will check that each image exists.
75 64
 func ExactImages(reg registry.Registry, images []flux.ImageID) (ImageMap, error) {
@@ -83,7 +72,7 @@ func ExactImages(reg registry.Registry, images []flux.ImageID) (ImageMap, error)
83 72
 		if !exist {
84 73
 			return m, errors.Wrap(flux.ErrInvalidImageID, fmt.Sprintf("image %q does not exist", id))
85 74
 		}
86
-		m[id.Repository()] = []flux.ImageDescription{flux.ImageDescription{ID: id}}
75
+		m[id.Repository()] = []flux.Image{flux.Image{ID: id}}
87 76
 	}
88 77
 	return m, nil
89 78
 }
@@ -92,12 +81,12 @@ func ExactImages(reg registry.Registry, images []flux.ImageID) (ImageMap, error)
92 81
 // Return true if exist, false otherwise
93 82
 func imageExists(reg registry.Registry, imageID flux.ImageID) (bool, error) {
94 83
 	// Use this method to parse the image, because it is safe. I.e. it will error and inform the user if it is malformed.
95
-	img, err := flux.ParseImage(imageID.String(), nil)
84
+	img, err := flux.ParseImage(imageID.String(), time.Time{})
96 85
 	if err != nil {
97 86
 		return false, err
98 87
 	}
99 88
 	// Get a specific image.
100
-	_, err = reg.GetImage(registry.RepositoryFromImage(img), img.Tag)
89
+	_, err = reg.GetImage(registry.RepositoryFromImage(img), img.ID.Tag)
101 90
 	if err != nil {
102 91
 		return false, nil
103 92
 	}

+ 8
- 8
release/releaser_test.go View File

@@ -76,12 +76,12 @@ var (
76 76
 	timeNow       = time.Now()
77 77
 	mockRegistry  = registry.NewMockRegistry([]flux.Image{
78 78
 		flux.Image{
79
-			ImageID:   newImageID,
80
-			CreatedAt: &timeNow,
79
+			ID:        newImageID,
80
+			CreatedAt: timeNow,
81 81
 		},
82 82
 		flux.Image{
83
-			ImageID:   newLockedID,
84
-			CreatedAt: &timeNow,
83
+			ID:        newLockedID,
84
+			CreatedAt: timeNow,
85 85
 		},
86 86
 	}, nil)
87 87
 )
@@ -294,12 +294,12 @@ func Test_ImageStatus(t *testing.T) {
294 294
 
295 295
 	upToDateRegistry := registry.NewMockRegistry([]flux.Image{
296 296
 		flux.Image{
297
-			ImageID:   oldImageID,
298
-			CreatedAt: &timeNow,
297
+			ID:        oldImageID,
298
+			CreatedAt: timeNow,
299 299
 		},
300 300
 		flux.Image{
301
-			ImageID:   sidecarImageID,
302
-			CreatedAt: &timeNow,
301
+			ID:        sidecarImageID,
302
+			CreatedAt: timeNow,
303 303
 		},
304 304
 	}, nil)
305 305
 

+ 12
- 5
remote/mock.go View File

@@ -96,7 +96,7 @@ func PlatformTestBattery(t *testing.T, wrap func(mock Platform) Platform) {
96 96
 	services := flux.ServiceIDSet{}
97 97
 	services.Add(serviceList)
98 98
 
99
-	now := time.Now()
99
+	now := time.Now().UTC()
100 100
 
101 101
 	imageID, _ := flux.ParseImageID("quay.io/example.com/frob:v0.4.5")
102 102
 	serviceAnswer := []flux.ServiceStatus{
@@ -106,9 +106,9 @@ func PlatformTestBattery(t *testing.T, wrap func(mock Platform) Platform) {
106 106
 			Containers: []flux.Container{
107 107
 				flux.Container{
108 108
 					Name: "frobnicator",
109
-					Current: flux.ImageDescription{
109
+					Current: flux.Image{
110 110
 						ID:        imageID,
111
-						CreatedAt: &now,
111
+						CreatedAt: now,
112 112
 					},
113 113
 				},
114 114
 			},
@@ -118,8 +118,15 @@ func PlatformTestBattery(t *testing.T, wrap func(mock Platform) Platform) {
118 118
 
119 119
 	imagesAnswer := []flux.ImageStatus{
120 120
 		flux.ImageStatus{
121
-			ID:         flux.ServiceID("barfoo/yello"),
122
-			Containers: []flux.Container{},
121
+			ID: flux.ServiceID("barfoo/yello"),
122
+			Containers: []flux.Container{
123
+				{
124
+					Name: "flubnicator",
125
+					Current: flux.Image{
126
+						ID: imageID,
127
+					},
128
+				},
129
+			},
123 130
 		},
124 131
 	}
125 132
 

+ 2
- 8
service.go View File

@@ -5,7 +5,6 @@ import (
5 5
 	"net/http"
6 6
 	"sort"
7 7
 	"strings"
8
-	"time"
9 8
 
10 9
 	"github.com/pkg/errors"
11 10
 )
@@ -160,13 +159,8 @@ type ServiceStatus struct {
160 159
 
161 160
 type Container struct {
162 161
 	Name      string
163
-	Current   ImageDescription
164
-	Available []ImageDescription
165
-}
166
-
167
-type ImageDescription struct {
168
-	ID        ImageID
169
-	CreatedAt *time.Time `json:",omitempty"`
162
+	Current   Image
163
+	Available []Image
170 164
 }
171 165
 
172 166
 // TODO: How similar should this be to the `get-config` result?

Loading…
Cancel
Save