Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Commit

Permalink
Recognise individual items in List resource
Browse files Browse the repository at this point in the history
It's not enough to be able to update images in a List resource, we
must be able to recognise them in the first place.

The Go YAML parser makes this a little tricky, because it doesn't give
you access to the bytes (like `UnmarshalJSON` does), so if we want
typed resources, we have to parse them generically and marshal them
back out to bytes.
  • Loading branch information
squaremo committed Mar 5, 2018
1 parent 91ebbe3 commit 230993c
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 1 deletion.
10 changes: 10 additions & 0 deletions cluster/kubernetes/resource/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package resource

import (
"github.com/weaveworks/flux/resource"
)

type List struct {
baseObject
Items []resource.Resource
}
10 changes: 9 additions & 1 deletion cluster/kubernetes/resource/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,15 @@ func ParseMultidoc(multidoc []byte, source string) (map[string]resource.Resource
if obj == nil {
continue
}
objs[obj.ResourceID().String()] = obj
// Lists must be treated specially, since it's the
// contained resources we are after.
if list, ok := obj.(*List); ok {
for _, item := range list.Items {
objs[item.ResourceID().String()] = item
}
} else {
objs[obj.ResourceID().String()] = obj
}
}

if err := chunks.Err(); err != nil {
Expand Down
34 changes: 34 additions & 0 deletions cluster/kubernetes/resource/load_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"reflect"
"testing"

"github.com/weaveworks/flux"
"github.com/weaveworks/flux/cluster/kubernetes/testfiles"
"github.com/weaveworks/flux/resource"
)
Expand Down Expand Up @@ -117,6 +118,39 @@ data:
}
}

func TestUnmarshalList(t *testing.T) {
doc := `---
kind: List
metadata:
name: list
items:
- kind: Deployment
metadata:
name: foo
- kind: Service
metadata:
name: bar
`
res, err := unmarshalObject("", []byte(doc))
if err != nil {
t.Fatal(err)
}
list, ok := res.(*List)
if !ok {
t.Fatal("did not parse as a list")
}
if len(list.Items) != 2 {
t.Fatalf("expected two items, got %+v", list.Items)
}
for i, id := range []flux.ResourceID{
flux.MustParseResourceID("default:deployment/foo"),
flux.MustParseResourceID("default:service/bar")} {
if list.Items[i].ResourceID() != id {
t.Errorf("At %d, expected %q, got %q", i, id, list.Items[i].ResourceID())
}
}
}

func debyte(r resource.Resource) resource.Resource {
if res, ok := r.(interface {
debyte()
Expand Down
29 changes: 29 additions & 0 deletions cluster/kubernetes/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,14 @@ func unmarshalKind(base baseObject, bytes []byte) (resource.Resource, error) {
return nil, err
}
return &ss, nil
case "List":
var raw rawList
if err := yaml.Unmarshal(bytes, &raw); err != nil {
return nil, err
}
var list List
unmarshalList(base, &raw, &list)
return &list, nil
case "":
// If there is an empty resource (due to eg an introduced comment),
// we are returning nil for the resource and nil for an error
Expand All @@ -124,6 +132,27 @@ func unmarshalKind(base baseObject, bytes []byte) (resource.Resource, error) {
}
}

type rawList struct {
Items []map[string]interface{}
}

func unmarshalList(base baseObject, raw *rawList, list *List) error {
list.baseObject = base
list.Items = make([]resource.Resource, len(raw.Items), len(raw.Items))
for i, item := range raw.Items {
bytes, err := yaml.Marshal(item)
if err != nil {
return err
}
res, err := unmarshalObject(base.source, bytes)
if err != nil {
return err
}
list.Items[i] = res
}
return nil
}

func makeUnmarshalObjectErr(source string, err error) *fluxerr.Error {
return &fluxerr.Error{
Type: fluxerr.User,
Expand Down

0 comments on commit 230993c

Please sign in to comment.