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

Commit

Permalink
Introduce config metadata (#1049)
Browse files Browse the repository at this point in the history
* revamping config metadata

* fix meta config

* update istioctl

* update configs

* finish it

* commit

* fix delete command
  • Loading branch information
kyessenov authored Aug 17, 2017
1 parent aa634e9 commit e16f721
Show file tree
Hide file tree
Showing 50 changed files with 926 additions and 898 deletions.
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

0 comments on commit e16f721

Please sign in to comment.