Skip to content
This repository has been archived by the owner on Jun 14, 2018. It is now read-only.

Introduce config metadata #1049

Merged
merged 7 commits into from
Aug 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions adapter/config/aggregate/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ go_library(
name = "go_default_library",
srcs = ["config.go"],
visibility = ["//visibility:public"],
deps = [
"//model:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
],
deps = ["//model:go_default_library"],
)

go_test(
Expand Down
50 changes: 23 additions & 27 deletions adapter/config/aggregate/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ import (
"errors"
"fmt"

"github.com/golang/protobuf/proto"

"istio.io/pilot/model"
)

Expand Down Expand Up @@ -77,46 +75,44 @@ func (cr *store) ConfigDescriptor() model.ConfigDescriptor {
return cr.descriptor
}

func (cr *store) Get(typ, key string) (proto.Message, bool, string) {
func (cr *store) Get(typ, name, namespace string) (*model.Config, bool) {
store, exists := cr.stores[typ]
if !exists {
return nil, false, ""
return nil, false
}
return store.Get(typ, key)
return store.Get(typ, name, namespace)
}

func (cr *store) List(typ string) ([]model.Config, error) {
func (cr *store) List(typ, namespace string) ([]model.Config, error) {
store, exists := cr.stores[typ]
if !exists {
return nil, nil
}
return store.List(typ)
return store.List(typ, namespace)
}

func (cr *store) Delete(typ, key string) error {
func (cr *store) Delete(typ, name, namespace string) error {
store, exists := cr.stores[typ]
if !exists {
return fmt.Errorf("missing type %q", typ)
}
return store.Delete(typ, key)
return store.Delete(typ, name, namespace)
}

func (cr *store) Post(config proto.Message) (string, error) {
schema, exists := cr.descriptor.GetByMessageName(proto.MessageName(config))
func (cr *store) Create(config model.Config) (string, error) {
store, exists := cr.stores[config.Type]
if !exists {
return "", errors.New("missing type")
}
store := cr.stores[schema.Type]
return store.Post(config)
return store.Create(config)
}

func (cr *store) Put(config proto.Message, oldRevision string) (string, error) {
schema, exists := cr.descriptor.GetByMessageName(proto.MessageName(config))
func (cr *store) Update(config model.Config) (string, error) {
store, exists := cr.stores[config.Type]
if !exists {
return "", errors.New("missing type")
}
store := cr.stores[schema.Type]
return store.Put(config, oldRevision)
return store.Update(config)
}

type storeCache struct {
Expand All @@ -128,24 +124,24 @@ func (cr *storeCache) ConfigDescriptor() model.ConfigDescriptor {
return cr.store.ConfigDescriptor()
}

func (cr *storeCache) Get(typ, key string) (config proto.Message, exists bool, revision string) {
return cr.store.Get(typ, key)
func (cr *storeCache) Get(typ, name, namespace string) (config *model.Config, exists bool) {
return cr.store.Get(typ, name, namespace)
}

func (cr *storeCache) List(typ string) ([]model.Config, error) {
return cr.store.List(typ)
func (cr *storeCache) List(typ, namespace string) ([]model.Config, error) {
return cr.store.List(typ, namespace)
}

func (cr *storeCache) Post(val proto.Message) (string, error) {
return cr.store.Post(val)
func (cr *storeCache) Create(config model.Config) (string, error) {
return cr.store.Create(config)
}

func (cr *storeCache) Put(val proto.Message, revision string) (string, error) {
return cr.store.Put(val, revision)
func (cr *storeCache) Update(config model.Config) (string, error) {
return cr.store.Update(config)
}

func (cr *storeCache) Delete(typ, key string) error {
return cr.store.Delete(typ, key)
func (cr *storeCache) Delete(typ, name, namespace string) error {
return cr.store.Delete(typ, name, namespace)
}

func (cr *storeCache) HasSynced() bool {
Expand Down
2 changes: 1 addition & 1 deletion adapter/config/aggregate/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func TestStoreInvariant(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error %v", err)
}
mock.CheckMapInvariant(store, t, 10)
mock.CheckMapInvariant(store, t, "", 10)
}

func TestStoreValidation(t *testing.T) {
Expand Down
1 change: 0 additions & 1 deletion adapter/config/crd/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ go_library(
"//model:go_default_library",
"//platform/kube:go_default_library",
"@com_github_golang_glog//:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
"@com_github_hashicorp_go_multierror//:go_default_library",
"@io_k8s_apiextensions_apiserver//pkg/apis/apiextensions/v1beta1:go_default_library",
"@io_k8s_apiextensions_apiserver//pkg/client/clientset/clientset:go_default_library",
Expand Down
85 changes: 36 additions & 49 deletions adapter/config/crd/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"time"

"github.com/golang/glog"
"github.com/golang/protobuf/proto"
multierror "github.com/hashicorp/go-multierror"

apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
Expand Down Expand Up @@ -67,9 +66,6 @@ type Client struct {

// dynamic REST client for accessing config CRDs
dynamic *rest.RESTClient

// namespace is the namespace for storing CRDs
namespace string
}

// CreateRESTConfig for cluster API server, pass empty config file for in-cluster
Expand Down Expand Up @@ -109,10 +105,9 @@ func CreateRESTConfig(kubeconfig string) (config *rest.Config, err error) {
}

// NewClient creates a client to Kubernetes API using a kubeconfig file.
// namespace argument provides the namespace to store CRDs
// Use an empty value for `kubeconfig` to use the in-cluster config.
// If the kubeconfig file is empty, defaults to in-cluster config as well.
func NewClient(config string, descriptor model.ConfigDescriptor, namespace string) (*Client, error) {
func NewClient(config string, descriptor model.ConfigDescriptor) (*Client, error) {
for _, typ := range descriptor {
if _, exists := knownTypes[typ.Type]; !exists {
return nil, fmt.Errorf("missing known type for %q", typ.Type)
Expand All @@ -138,7 +133,6 @@ func NewClient(config string, descriptor model.ConfigDescriptor, namespace strin
descriptor: descriptor,
restconfig: restconfig,
dynamic: dynamic,
namespace: namespace,
}

return out, nil
Expand Down Expand Up @@ -235,136 +229,129 @@ func (cl *Client) ConfigDescriptor() model.ConfigDescriptor {
}

// Get implements store interface
func (cl *Client) Get(typ, key string) (proto.Message, bool, string) {
func (cl *Client) Get(typ, name, namespace string) (*model.Config, bool) {
schema, exists := cl.descriptor.GetByType(typ)
if !exists {
return nil, false, ""
return nil, false
}

config := knownTypes[typ].object.DeepCopyObject().(IstioObject)
err := cl.dynamic.Get().
Namespace(cl.namespace).
Namespace(namespace).
Resource(schema.Plural).
Name(configKey(typ, key)).
Name(name).
Do().Into(config)

if err != nil {
glog.Warning(err)
return nil, false, ""
return nil, false
}

out, err := schema.FromJSONMap(config.GetSpec())
out, err := convertObject(schema, config)
if err != nil {
glog.Warningf("%v for %#v", err, config.GetObjectMeta())
return nil, false, ""
glog.Warning(err)
return nil, false
}
return out, true, config.GetObjectMeta().ResourceVersion
return out, true
}

// Post implements store interface
func (cl *Client) Post(v proto.Message) (string, error) {
messageName := proto.MessageName(v)
schema, exists := cl.descriptor.GetByMessageName(messageName)
// Create implements store interface
func (cl *Client) Create(config model.Config) (string, error) {
schema, exists := cl.descriptor.GetByType(config.Type)
if !exists {
return "", fmt.Errorf("unrecognized message name %q", messageName)
return "", fmt.Errorf("unrecognized type %q", config.Type)
}

if err := schema.Validate(v); err != nil {
if err := schema.Validate(config.Spec); err != nil {
return "", multierror.Prefix(err, "validation error:")
}

out, err := modelToKube(schema, cl.namespace, v, "")
out, err := convertConfig(schema, config)
if err != nil {
return "", err
}

config := knownTypes[schema.Type].object.DeepCopyObject().(IstioObject)
obj := knownTypes[schema.Type].object.DeepCopyObject().(IstioObject)
err = cl.dynamic.Post().
Namespace(out.GetObjectMeta().Namespace).
Resource(schema.Plural).
Body(out).
Do().Into(config)
Do().Into(obj)
if err != nil {
return "", err
}

return config.GetObjectMeta().ResourceVersion, nil
return obj.GetObjectMeta().ResourceVersion, nil
}

// Put implements store interface
func (cl *Client) Put(v proto.Message, revision string) (string, error) {
messageName := proto.MessageName(v)
schema, exists := cl.descriptor.GetByMessageName(messageName)
// Update implements store interface
func (cl *Client) Update(config model.Config) (string, error) {
schema, exists := cl.descriptor.GetByType(config.Type)
if !exists {
return "", fmt.Errorf("unrecognized message name %q", messageName)
return "", fmt.Errorf("unrecognized type %q", config.Type)
}

if err := schema.Validate(v); err != nil {
if err := schema.Validate(config.Spec); err != nil {
return "", multierror.Prefix(err, "validation error:")
}

if revision == "" {
if config.ResourceVersion == "" {
return "", fmt.Errorf("revision is required")
}

out, err := modelToKube(schema, cl.namespace, v, revision)
out, err := convertConfig(schema, config)
if err != nil {
return "", err
}

config := knownTypes[schema.Type].object.DeepCopyObject().(IstioObject)
obj := knownTypes[schema.Type].object.DeepCopyObject().(IstioObject)
err = cl.dynamic.Put().
Namespace(out.GetObjectMeta().Namespace).
Resource(schema.Plural).
Name(out.GetObjectMeta().Name).
Body(out).
Do().Into(config)
Do().Into(obj)
if err != nil {
return "", err
}

return config.GetObjectMeta().ResourceVersion, nil
return obj.GetObjectMeta().ResourceVersion, nil
}

// Delete implements store interface
func (cl *Client) Delete(typ, key string) error {
func (cl *Client) Delete(typ, name, namespace string) error {
schema, exists := cl.descriptor.GetByType(typ)
if !exists {
return fmt.Errorf("missing type %q", typ)
}

return cl.dynamic.Delete().
Namespace(cl.namespace).
Namespace(namespace).
Resource(schema.Plural).
Name(configKey(typ, key)).
Name(name).
Do().Error()
}

// List implements store interface
func (cl *Client) List(typ string) ([]model.Config, error) {
func (cl *Client) List(typ, namespace string) ([]model.Config, error) {
schema, exists := cl.descriptor.GetByType(typ)
if !exists {
return nil, fmt.Errorf("missing type %q", typ)
}

list := knownTypes[schema.Type].collection.DeepCopyObject().(IstioObjectList)
errs := cl.dynamic.Get().
Namespace(cl.namespace).
Namespace(namespace).
Resource(schema.Plural).
Do().Into(list)

out := make([]model.Config, 0)
for _, item := range list.GetItems() {
data, err := schema.FromJSONMap(item.GetSpec())
obj, err := convertObject(schema, item)
if err != nil {
errs = multierror.Append(errs, err)
} else {
out = append(out, model.Config{
Type: schema.Type,
Key: schema.Key(data),
Revision: item.GetObjectMeta().ResourceVersion,
Content: data,
})
out = append(out, *obj)
}
}
return out, errs
Expand Down
18 changes: 9 additions & 9 deletions adapter/config/crd/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ func kubeconfig(t *testing.T) string {
return kubeconfig
}

func makeClient(namespace string, t *testing.T) *Client {
func makeClient(t *testing.T) *Client {
desc := append(model.IstioConfigTypes, mock.Types...)
cl, err := NewClient(kubeconfig(t), desc, namespace)
cl, err := NewClient(kubeconfig(t), desc)
if err != nil {
t.Fatal(err)
}
Expand All @@ -62,7 +62,7 @@ func makeClient(namespace string, t *testing.T) *Client {
}

// makeTempClient allocates a namespace and cleans it up on test completion
func makeTempClient(t *testing.T) (*Client, func()) {
func makeTempClient(t *testing.T) (*Client, string, func()) {
client, err := kube.CreateInterface(kubeconfig(t))
if err != nil {
t.Fatal(err)
Expand All @@ -71,21 +71,21 @@ func makeTempClient(t *testing.T) (*Client, func()) {
if err != nil {
t.Fatal(err.Error())
}
cl := makeClient(ns, t)
cl := makeClient(t)

// the rest of the test can run in parallel
t.Parallel()
return cl, func() { util.DeleteNamespace(client, ns) }
return cl, ns, func() { util.DeleteNamespace(client, ns) }
}

func TestStoreInvariant(t *testing.T) {
client, cleanup := makeTempClient(t)
client, ns, cleanup := makeTempClient(t)
defer cleanup()
mock.CheckMapInvariant(client, t, 5)
mock.CheckMapInvariant(client, t, ns, 5)
}

func TestIstioConfig(t *testing.T) {
client, cleanup := makeTempClient(t)
client, ns, cleanup := makeTempClient(t)
defer cleanup()
mock.CheckIstioConfigTypes(client, t)
mock.CheckIstioConfigTypes(client, ns, t)
}
Loading