From 2edf8874a7db013ba990c56e86bc74e167b553e9 Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Mon, 12 Jun 2017 07:33:37 -0700 Subject: [PATCH 01/17] Add initial version of config api service --- config/service.proto | 280 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 config/service.proto diff --git a/config/service.proto b/config/service.proto new file mode 100644 index 0000000000..f0f093166e --- /dev/null +++ b/config/service.proto @@ -0,0 +1,280 @@ +// Copyright 2017 Istio Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package istio.config; + +import "google/rpc/status.proto"; +import "google/protobuf/struct.proto"; +import "google/api/annotations.proto"; + +// The Istio Config API service follows +// the kubenertes API server delegation and resource model. +// /apiGroup/version/objecttype/{namespace}/objectname --> +// +// It generalizes the concept of namespace to an arbitrary grouping. +// +// /apiGroup/version/objecttype/{objectGroup}/objectname +// + etcdv3 stream watch API +service IstioConfig { + // Get a single object. + rpc GetObject(GetObjectRequest) returns (GetObjectResponse) { + option (google.api.http) = { + get: "/v1/{meta.api_group}/{meta.object_type}/{meta.object_group}/{meta.name}" + }; + }; + + // Get a list of objects. + // other arguments like meta.object_group, meta.name are optional + // This lets one list all object of a type, or all object of a type + // that is within an object group. + rpc ListObjects(ListObjectsRequest) returns (ListObjectsResponse) { + option (google.api.http) = { + get: "/v1/{meta.api_group}/{meta.object_type}" // ?meta.object_group=group1}" + additional_bindings: { + get: "/v1/{meta.api_group}/{meta.object_type}/meta.object_group}" + }; + }; + }; + + // Create an object. This may result in configuration validation errors. + // Referrential integrity is not generally guranteed, however individual validators + // may decide to validate for it. + rpc CreateObject(CreateObjectRequest) returns (CreateObjectResponse) { + option (google.api.http) = { + post: "/v1/{meta.api_group}/{meta.object_type}/{meta.object_group}" + body: "source_data" + }; + }; + + // Update a single object. May return validation errors. + rpc UpdateObject(UpdateObjectRequest) returns (UpdateObjectResponse) { + option (google.api.http) = { + put: "/v1/{meta.api_group}/{meta.object_type}/{meta.object_group}/{meta.name}" + body: "source_data" + }; + }; + + // Delete a single object. May return validation errors. + rpc DeleteObject(DeleteObjectRequest) returns (google.rpc.Status) { + option (google.api.http) = { + delete: "/v1/{meta.api_group}/{meta.object_type}/{meta.object_group}/{meta.name}" + }; + }; + + // Watch method is borrowed from etcdv3 bi-directional streaming watches. + // Watch watches for events happening or that have happened. Both input and output + // are streams; the input stream is for creating and canceling watchers and the output + // stream sends events. One watch RPC can watch on multiple key roots, streaming events + // for several watches at once. + rpc Watch(stream WatchRequest) returns (stream WatchResponse) { + option (google.api.http) = { + post: "/v1/events:watch" + body: "*" + }; + } +} + +message ObjectFieldSelector { + // if true object(s) should include data. + bool data = 1; + + // if true object(s) should include source_data. + bool source_data = 2; +} + +message ListObjectsResponse { + google.rpc.Status status = 1; + + ObjectList list = 2; +} + +message ListObjectsRequest { + // meta is the metadata associated with the root where listing begins. + ObjectMeta meta = 1; + + // select selects fields to include in the result. + ObjectFieldSelector select = 2; +} + +message UpdateObjectRequest { + // meta is the metadata associated with the object. + ObjectMeta meta = 1; + + // source_data is the data as it was specified in json / yaml format. + google.protobuf.Struct source_data = 2; +} + +message UpdateObjectResponse { + google.rpc.Status status = 1; + + Object object = 2; +} + +message CreateObjectResponse { + google.rpc.Status status = 1; + + Object object = 2; +} + +message CreateObjectRequest { + // meta is the metadata associated with the object. + ObjectMeta meta = 1; + + // source_data is the data as it was specified in json / yaml format. + google.protobuf.Struct source_data = 2; +} + +message GetObjectResponse { + google.rpc.Status status = 1; + + Object object = 2; +} + +message GetObjectRequest { + // meta is the metadata associated with the object. + ObjectMeta meta = 1; + + // select selects fields to include in the result. + ObjectFieldSelector select = 2; +} + +message DeleteObjectRequest { + // meta is the metadata associated with the object. + ObjectMeta meta = 1; +} + +// Object +message Object { + // meta is the metadata associated with the object. + ObjectMeta meta = 1; + + // source_data is the data as it was specified in json / yaml format. + google.protobuf.Struct source_data = 2; + + // data is the binary encoded protobuf data + // Both representations are useful. + // For example: + // `souce_data` contains an expressions in text form + // `data` may contain parsed AST + bytes data = 3; +} + +// +message ObjectList { + // meta is the metadata associated with this list. + ObjectMeta meta = 1; + + // list of objects returned. + repeated Object objects = 2; +} + + +// ObjectMeta +message ObjectMeta { + // api_group is the top level delegation. + // All messages from an api group are handled by the same delegation handler. + string api_group = 1; + + // objectType is the type of an object. + // route-rule, metrics-type, metrics-ctor, ... + string object_type = 2; + + // objectGroup is an arbitrary hierarchical grouping of resources. + // For Mixer configuration object_group == mesh, svc:svc1, svc:svc2 ... + // For Proxy it can be mesh, destination. + string object_group = 3; + + // name of the object. + string name = 4; + + // version + // version of the object. + int64 version = 5; + + // labels + // labels associated with the object. + map labels = 6; +} + +// watchers follows etcdv3 watch pattern. +message WatchRequest { + // request_union is a request to either create a new watcher or cancel an existing watcher. + oneof request_union { + WatchCreateRequest create_request = 1; + WatchCancelRequest cancel_request = 2; + } +} + +message WatchCreateRequest { + // used to identify + ObjectMeta key = 1; + + // start watching from this revision. + int64 start_revision = 2; + + + enum FilterType { + // filter out put event. + NOPUT = 0; + // filter out delete event. + NODELETE = 1; + } + // filters filter the events at server side before it sends back to the watcher. + repeated FilterType filters = 3; +} + +message WatchCancelRequest { + // watch_id is the watcher id to cancel so that no more events are transmitted. + int64 watch_id = 1; +} + +message WatchResponse { + // watch_id is the ID of the watcher that corresponds to the response. + int64 watch_id = 1; + // created is set to true if the response is for a create watch request. + // The client should record the watch_id and expect to receive events for + // the created watcher from the same stream. + // All events sent to the created watcher will attach with the same watch_id. + bool created = 2; + // canceled is set to true if the response is for a cancel watch request. + // No further events will be sent to the canceled watcher. + bool canceled = 3; + + // if watcher could not be created or had to be aborted status is NON-OK. + google.rpc.Status status = 4; + + repeated Event events = 5; +} + +message Event { + enum EventType { + UPDATE = 0; // ADD and UPDATE + DELETE = 1; + } + // type is the kind of event. If type is a PUT, it indicates + // new data has been stored to the key. If type is a DELETE, + // it indicates the key was deleted. + EventType type = 1; + // kv holds the KeyValue for the event. + // A PUT event contains current kv pair. + // A PUT event with kv.Version=1 indicates the creation of a key. + // A DELETE/EXPIRE event contains the deleted key with + // its modification revision set to the revision of deletion. + Object kv = 2; + + // prev_kv holds the key-value pair before the event happens. + Object prev_kv = 3; +} From 002bf314fbd388647e2ac3689bdbc5f3f2ee9ba1 Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Mon, 12 Jun 2017 09:07:04 -0700 Subject: [PATCH 02/17] remove explicit google.rpc.status per style guide --- config/service.proto | 35 ++++++----------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/config/service.proto b/config/service.proto index f0f093166e..901e25d757 100644 --- a/config/service.proto +++ b/config/service.proto @@ -18,6 +18,7 @@ package istio.config; import "google/rpc/status.proto"; import "google/protobuf/struct.proto"; +import "google/protobuf/empty.proto"; import "google/api/annotations.proto"; // The Istio Config API service follows @@ -30,7 +31,7 @@ import "google/api/annotations.proto"; // + etcdv3 stream watch API service IstioConfig { // Get a single object. - rpc GetObject(GetObjectRequest) returns (GetObjectResponse) { + rpc GetObject(GetObjectRequest) returns (Object) { option (google.api.http) = { get: "/v1/{meta.api_group}/{meta.object_type}/{meta.object_group}/{meta.name}" }; @@ -40,7 +41,7 @@ service IstioConfig { // other arguments like meta.object_group, meta.name are optional // This lets one list all object of a type, or all object of a type // that is within an object group. - rpc ListObjects(ListObjectsRequest) returns (ListObjectsResponse) { + rpc ListObjects(ListObjectsRequest) returns (ObjectList) { option (google.api.http) = { get: "/v1/{meta.api_group}/{meta.object_type}" // ?meta.object_group=group1}" additional_bindings: { @@ -52,7 +53,7 @@ service IstioConfig { // Create an object. This may result in configuration validation errors. // Referrential integrity is not generally guranteed, however individual validators // may decide to validate for it. - rpc CreateObject(CreateObjectRequest) returns (CreateObjectResponse) { + rpc CreateObject(CreateObjectRequest) returns (Object) { option (google.api.http) = { post: "/v1/{meta.api_group}/{meta.object_type}/{meta.object_group}" body: "source_data" @@ -60,7 +61,7 @@ service IstioConfig { }; // Update a single object. May return validation errors. - rpc UpdateObject(UpdateObjectRequest) returns (UpdateObjectResponse) { + rpc UpdateObject(UpdateObjectRequest) returns (Object) { option (google.api.http) = { put: "/v1/{meta.api_group}/{meta.object_type}/{meta.object_group}/{meta.name}" body: "source_data" @@ -68,7 +69,7 @@ service IstioConfig { }; // Delete a single object. May return validation errors. - rpc DeleteObject(DeleteObjectRequest) returns (google.rpc.Status) { + rpc DeleteObject(DeleteObjectRequest) returns (google.protobuf.Empty) { option (google.api.http) = { delete: "/v1/{meta.api_group}/{meta.object_type}/{meta.object_group}/{meta.name}" }; @@ -95,12 +96,6 @@ message ObjectFieldSelector { bool source_data = 2; } -message ListObjectsResponse { - google.rpc.Status status = 1; - - ObjectList list = 2; -} - message ListObjectsRequest { // meta is the metadata associated with the root where listing begins. ObjectMeta meta = 1; @@ -117,18 +112,6 @@ message UpdateObjectRequest { google.protobuf.Struct source_data = 2; } -message UpdateObjectResponse { - google.rpc.Status status = 1; - - Object object = 2; -} - -message CreateObjectResponse { - google.rpc.Status status = 1; - - Object object = 2; -} - message CreateObjectRequest { // meta is the metadata associated with the object. ObjectMeta meta = 1; @@ -137,12 +120,6 @@ message CreateObjectRequest { google.protobuf.Struct source_data = 2; } -message GetObjectResponse { - google.rpc.Status status = 1; - - Object object = 2; -} - message GetObjectRequest { // meta is the metadata associated with the object. ObjectMeta meta = 1; From 92df06f023c2a032bc6bc60cac9a92a6fd554464 Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Mon, 12 Jun 2017 10:30:32 -0700 Subject: [PATCH 03/17] updated comments and fixed uri path --- config/service.proto | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/config/service.proto b/config/service.proto index 901e25d757..2dd2d24e25 100644 --- a/config/service.proto +++ b/config/service.proto @@ -14,7 +14,7 @@ syntax = "proto3"; -package istio.config; +package istio.v1.config; import "google/rpc/status.proto"; import "google/protobuf/struct.proto"; @@ -29,7 +29,7 @@ import "google/api/annotations.proto"; // // /apiGroup/version/objecttype/{objectGroup}/objectname // + etcdv3 stream watch API -service IstioConfig { +service Service { // Get a single object. rpc GetObject(GetObjectRequest) returns (Object) { option (google.api.http) = { @@ -43,9 +43,10 @@ service IstioConfig { // that is within an object group. rpc ListObjects(ListObjectsRequest) returns (ObjectList) { option (google.api.http) = { - get: "/v1/{meta.api_group}/{meta.object_type}" // ?meta.object_group=group1}" + // meta.object_group can be specified as a query parameter + get: "/v1/{meta.api_group}/{meta.object_type}" additional_bindings: { - get: "/v1/{meta.api_group}/{meta.object_type}/meta.object_group}" + get: "/v1/{meta.api_group}/{meta.object_type}/{meta.object_group}" }; }; }; From 9767050460e54e844c5d4a6e915a7cff0ff7c247 Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Mon, 12 Jun 2017 13:26:46 -0700 Subject: [PATCH 04/17] Rename ObjectMeta to Meta and Change package --- config/service.proto | 51 +++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/config/service.proto b/config/service.proto index 2dd2d24e25..2268bcd61e 100644 --- a/config/service.proto +++ b/config/service.proto @@ -14,7 +14,7 @@ syntax = "proto3"; -package istio.v1.config; +package istio.config.v1; import "google/rpc/status.proto"; import "google/protobuf/struct.proto"; @@ -51,6 +51,19 @@ service Service { }; }; + // Get a list of object types. + // Lists all object types or all object types + // within an api group. + rpc ListObjectTypes(ListObjectTypesRequest) returns (ObjectTypeList) { + option (google.api.http) = { + // meta.object_group can be specified as a query parameter + get: "/v1" + additional_bindings: { + get: "/v1/{meta.api_group}" + }; + }; + }; + // Create an object. This may result in configuration validation errors. // Referrential integrity is not generally guranteed, however individual validators // may decide to validate for it. @@ -97,9 +110,14 @@ message ObjectFieldSelector { bool source_data = 2; } +message ListObjectTypesRequest { + // meta is the metadata associated with the root where listing begins. + Meta meta = 1; +} + message ListObjectsRequest { // meta is the metadata associated with the root where listing begins. - ObjectMeta meta = 1; + Meta meta = 1; // select selects fields to include in the result. ObjectFieldSelector select = 2; @@ -107,7 +125,7 @@ message ListObjectsRequest { message UpdateObjectRequest { // meta is the metadata associated with the object. - ObjectMeta meta = 1; + Meta meta = 1; // source_data is the data as it was specified in json / yaml format. google.protobuf.Struct source_data = 2; @@ -115,7 +133,7 @@ message UpdateObjectRequest { message CreateObjectRequest { // meta is the metadata associated with the object. - ObjectMeta meta = 1; + Meta meta = 1; // source_data is the data as it was specified in json / yaml format. google.protobuf.Struct source_data = 2; @@ -123,7 +141,7 @@ message CreateObjectRequest { message GetObjectRequest { // meta is the metadata associated with the object. - ObjectMeta meta = 1; + Meta meta = 1; // select selects fields to include in the result. ObjectFieldSelector select = 2; @@ -131,13 +149,13 @@ message GetObjectRequest { message DeleteObjectRequest { // meta is the metadata associated with the object. - ObjectMeta meta = 1; + Meta meta = 1; } // Object message Object { // meta is the metadata associated with the object. - ObjectMeta meta = 1; + Meta meta = 1; // source_data is the data as it was specified in json / yaml format. google.protobuf.Struct source_data = 2; @@ -150,18 +168,25 @@ message Object { bytes data = 3; } -// +message ObjectTypeList { + // meta is the metadata associated with this list. + Meta meta = 1; + + // list of objects returned. + repeated Meta object_types = 2; +} + message ObjectList { // meta is the metadata associated with this list. - ObjectMeta meta = 1; + Meta meta = 1; // list of objects returned. repeated Object objects = 2; } -// ObjectMeta -message ObjectMeta { +// Meta +message Meta { // api_group is the top level delegation. // All messages from an api group are handled by the same delegation handler. string api_group = 1; @@ -198,7 +223,7 @@ message WatchRequest { message WatchCreateRequest { // used to identify - ObjectMeta key = 1; + Meta key = 1; // start watching from this revision. int64 start_revision = 2; @@ -249,7 +274,7 @@ message Event { // kv holds the KeyValue for the event. // A PUT event contains current kv pair. // A PUT event with kv.Version=1 indicates the creation of a key. - // A DELETE/EXPIRE event contains the deleted key with + // A DELETE event contains the deleted key with // its modification revision set to the revision of deletion. Object kv = 2; From e78028a267b4c86a9f8bafc9b6bfb4facdcd1aeb Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Mon, 12 Jun 2017 13:31:07 -0700 Subject: [PATCH 05/17] move service into v1 --- config/{ => v1}/service.proto | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename config/{ => v1}/service.proto (100%) diff --git a/config/service.proto b/config/v1/service.proto similarity index 100% rename from config/service.proto rename to config/v1/service.proto From 73527c0d6efccd90db78c90b49bead5656fefb00 Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Mon, 12 Jun 2017 14:16:26 -0700 Subject: [PATCH 06/17] version --> revision --- config/v1/service.proto | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/config/v1/service.proto b/config/v1/service.proto index 2268bcd61e..71e996e6a9 100644 --- a/config/v1/service.proto +++ b/config/v1/service.proto @@ -203,9 +203,9 @@ message Meta { // name of the object. string name = 4; - // version - // version of the object. - int64 version = 5; + // revision + // revision of the repository, the last time Object was updated. + int64 revision = 5; // labels // labels associated with the object. @@ -228,7 +228,6 @@ message WatchCreateRequest { // start watching from this revision. int64 start_revision = 2; - enum FilterType { // filter out put event. NOPUT = 0; From aaca5ee699b5dd88a4f916dc986f7ed5ea4c30a6 Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Mon, 12 Jun 2017 15:57:56 -0700 Subject: [PATCH 07/17] change version/group --> group/version --- config/v1/service.proto | 52 ++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/config/v1/service.proto b/config/v1/service.proto index 71e996e6a9..b78d252c54 100644 --- a/config/v1/service.proto +++ b/config/v1/service.proto @@ -28,12 +28,15 @@ import "google/api/annotations.proto"; // It generalizes the concept of namespace to an arbitrary grouping. // // /apiGroup/version/objecttype/{objectGroup}/objectname +// +// api_group = /mixer/v1 or +// api_group = /proxy/v1 // + etcdv3 stream watch API service Service { // Get a single object. rpc GetObject(GetObjectRequest) returns (Object) { option (google.api.http) = { - get: "/v1/{meta.api_group}/{meta.object_type}/{meta.object_group}/{meta.name}" + get: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}/{meta.name}" }; }; @@ -44,9 +47,9 @@ service Service { rpc ListObjects(ListObjectsRequest) returns (ObjectList) { option (google.api.http) = { // meta.object_group can be specified as a query parameter - get: "/v1/{meta.api_group}/{meta.object_type}" + get: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}" additional_bindings: { - get: "/v1/{meta.api_group}/{meta.object_type}/{meta.object_group}" + get: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}" }; }; }; @@ -56,10 +59,9 @@ service Service { // within an api group. rpc ListObjectTypes(ListObjectTypesRequest) returns (ObjectTypeList) { option (google.api.http) = { - // meta.object_group can be specified as a query parameter - get: "/v1" + get: "/{meta.api_group}/{meta.api_group_version}" additional_bindings: { - get: "/v1/{meta.api_group}" + get: "/" }; }; }; @@ -69,7 +71,7 @@ service Service { // may decide to validate for it. rpc CreateObject(CreateObjectRequest) returns (Object) { option (google.api.http) = { - post: "/v1/{meta.api_group}/{meta.object_type}/{meta.object_group}" + post: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}" body: "source_data" }; }; @@ -77,7 +79,7 @@ service Service { // Update a single object. May return validation errors. rpc UpdateObject(UpdateObjectRequest) returns (Object) { option (google.api.http) = { - put: "/v1/{meta.api_group}/{meta.object_type}/{meta.object_group}/{meta.name}" + put: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}/{meta.name}" body: "source_data" }; }; @@ -85,7 +87,7 @@ service Service { // Delete a single object. May return validation errors. rpc DeleteObject(DeleteObjectRequest) returns (google.protobuf.Empty) { option (google.api.http) = { - delete: "/v1/{meta.api_group}/{meta.object_type}/{meta.object_group}/{meta.name}" + delete: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}/{meta.name}" }; }; @@ -96,13 +98,13 @@ service Service { // for several watches at once. rpc Watch(stream WatchRequest) returns (stream WatchResponse) { option (google.api.http) = { - post: "/v1/events:watch" + post: "/events/v1:watch" body: "*" }; } } -message ObjectFieldSelector { +message ObjectFieldInclude { // if true object(s) should include data. bool data = 1; @@ -120,7 +122,7 @@ message ListObjectsRequest { Meta meta = 1; // select selects fields to include in the result. - ObjectFieldSelector select = 2; + ObjectFieldInclude incl = 2; } message UpdateObjectRequest { @@ -143,8 +145,8 @@ message GetObjectRequest { // meta is the metadata associated with the object. Meta meta = 1; - // select selects fields to include in the result. - ObjectFieldSelector select = 2; + // incl(ude) selects fields to include in the result. + ObjectFieldInclude incl = 2; } message DeleteObjectRequest { @@ -163,8 +165,8 @@ message Object { // data is the binary encoded protobuf data // Both representations are useful. // For example: - // `souce_data` contains an expressions in text form - // `data` may contain parsed AST + // If `souce_data` contains an expressions in text form + // `data` may contain a parsed AST bytes data = 3; } @@ -189,27 +191,35 @@ message ObjectList { message Meta { // api_group is the top level delegation. // All messages from an api group are handled by the same delegation handler. + // api group itself is versioned. string api_group = 1; + // every api group is independently versioned. + string api_group_version = 2; + // objectType is the type of an object. // route-rule, metrics-type, metrics-ctor, ... - string object_type = 2; + string object_type = 3; // objectGroup is an arbitrary hierarchical grouping of resources. // For Mixer configuration object_group == mesh, svc:svc1, svc:svc2 ... // For Proxy it can be mesh, destination. - string object_group = 3; + string object_group = 4; // name of the object. - string name = 4; + string name = 5; + + // uid assigned to the object. Only used when a new object is created + // in the same place as before. + string uid = 6; // revision // revision of the repository, the last time Object was updated. - int64 revision = 5; + int64 revision = 7; // labels // labels associated with the object. - map labels = 6; + map labels = 8; } // watchers follows etcdv3 watch pattern. From 7297a290c84d38aa5ac39ad402b6c9ee06201b5f Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Tue, 13 Jun 2017 10:53:02 -0700 Subject: [PATCH 08/17] convert 2 bools to enum for responseType --- config/v1/service.proto | 107 ++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 47 deletions(-) diff --git a/config/v1/service.proto b/config/v1/service.proto index b78d252c54..beb7f3c5cf 100644 --- a/config/v1/service.proto +++ b/config/v1/service.proto @@ -1,5 +1,5 @@ // Copyright 2017 Istio Authors -// +// vim: set expandtab ts=2 sw=2: // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -35,9 +35,9 @@ import "google/api/annotations.proto"; service Service { // Get a single object. rpc GetObject(GetObjectRequest) returns (Object) { - option (google.api.http) = { - get: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}/{meta.name}" - }; + option (google.api.http) = { + get: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}/{meta.name}" + }; }; // Get a list of objects. @@ -45,50 +45,50 @@ service Service { // This lets one list all object of a type, or all object of a type // that is within an object group. rpc ListObjects(ListObjectsRequest) returns (ObjectList) { - option (google.api.http) = { - // meta.object_group can be specified as a query parameter - get: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}" - additional_bindings: { - get: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}" - }; - }; + option (google.api.http) = { + // meta.object_group can be specified as a query parameter + get: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}" + additional_bindings: { + get: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}" + }; + }; }; // Get a list of object types. // Lists all object types or all object types // within an api group. rpc ListObjectTypes(ListObjectTypesRequest) returns (ObjectTypeList) { - option (google.api.http) = { - get: "/{meta.api_group}/{meta.api_group_version}" - additional_bindings: { - get: "/" - }; - }; + option (google.api.http) = { + get: "/{meta.api_group}/{meta.api_group_version}" + additional_bindings: { + get: "/" + }; + }; }; // Create an object. This may result in configuration validation errors. // Referrential integrity is not generally guranteed, however individual validators // may decide to validate for it. rpc CreateObject(CreateObjectRequest) returns (Object) { - option (google.api.http) = { - post: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}" - body: "source_data" - }; + option (google.api.http) = { + post: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}" + body: "source_data" + }; }; // Update a single object. May return validation errors. rpc UpdateObject(UpdateObjectRequest) returns (Object) { - option (google.api.http) = { - put: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}/{meta.name}" - body: "source_data" - }; + option (google.api.http) = { + put: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}/{meta.name}" + body: "source_data" + }; }; // Delete a single object. May return validation errors. rpc DeleteObject(DeleteObjectRequest) returns (google.protobuf.Empty) { - option (google.api.http) = { - delete: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}/{meta.name}" - }; + option (google.api.http) = { + delete: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}/{meta.name}" + }; }; // Watch method is borrowed from etcdv3 bi-directional streaming watches. @@ -97,11 +97,11 @@ service Service { // stream sends events. One watch RPC can watch on multiple key roots, streaming events // for several watches at once. rpc Watch(stream WatchRequest) returns (stream WatchResponse) { - option (google.api.http) = { - post: "/events/v1:watch" - body: "*" + option (google.api.http) = { + post: "/events/v1:watch" + body: "*" }; - } + }; } message ObjectFieldInclude { @@ -121,7 +121,8 @@ message ListObjectsRequest { // meta is the metadata associated with the root where listing begins. Meta meta = 1; - // select selects fields to include in the result. + // incl(ude) selects fields to include in the result. + // `include` is a reserved word. so not used here. ObjectFieldInclude incl = 2; } @@ -146,6 +147,7 @@ message GetObjectRequest { Meta meta = 1; // incl(ude) selects fields to include in the result. + // `include` is a reserved word. so not used here. ObjectFieldInclude incl = 2; } @@ -191,11 +193,11 @@ message ObjectList { message Meta { // api_group is the top level delegation. // All messages from an api group are handled by the same delegation handler. - // api group itself is versioned. + // api group itself is versioned. string api_group = 1; - // every api group is independently versioned. - string api_group_version = 2; + // every api group is independently versioned. + string api_group_version = 2; // objectType is the type of an object. // route-rule, metrics-type, metrics-ctor, ... @@ -209,9 +211,9 @@ message Meta { // name of the object. string name = 5; - // uid assigned to the object. Only used when a new object is created - // in the same place as before. - string uid = 6; + // uid assigned to the object. Only used when a new object is created + // in the same place as before. + string uid = 6; // revision // revision of the repository, the last time Object was updated. @@ -253,22 +255,33 @@ message WatchCancelRequest { int64 watch_id = 1; } -message WatchResponse { - // watch_id is the ID of the watcher that corresponds to the response. - int64 watch_id = 1; - // created is set to true if the response is for a create watch request. +enum WatchResponseType { + // Reponse only contains data. + DATA = 0; + + // If the response is for a create watch request. // The client should record the watch_id and expect to receive events for // the created watcher from the same stream. // All events sent to the created watcher will attach with the same watch_id. - bool created = 2; + WATCH_CREATED = 1; + // canceled is set to true if the response is for a cancel watch request. // No further events will be sent to the canceled watcher. - bool canceled = 3; + WATCH_CANCELED = 2; +} + +message WatchResponse { + // watch_id is the ID of the watcher that corresponds to the response. + int64 watch_id = 1; + + // response_type specifies if this message is responding to + // a watch creation request, watch removal request + WatchResponseType response_type = 2; // if watcher could not be created or had to be aborted status is NON-OK. - google.rpc.Status status = 4; + google.rpc.Status status = 3; - repeated Event events = 5; + repeated Event events = 4; } message Event { From 34927ca74c033d1449b558ee9d4d3409e8cfa8d4 Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Wed, 14 Jun 2017 18:07:57 -0700 Subject: [PATCH 09/17] Separate Watcher in a different service. Add initial subtree with watch subscription response --- config/v1/service.proto | 61 ++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/config/v1/service.proto b/config/v1/service.proto index beb7f3c5cf..659795315a 100644 --- a/config/v1/service.proto +++ b/config/v1/service.proto @@ -90,12 +90,17 @@ service Service { delete: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}/{meta.name}" }; }; - +}; + + +// Watcher service is designed to efficiently watch mutiple subtrees of the resource tree. +service Watcher { // Watch method is borrowed from etcdv3 bi-directional streaming watches. // Watch watches for events happening or that have happened. Both input and output // are streams; the input stream is for creating and canceling watchers and the output // stream sends events. One watch RPC can watch on multiple key roots, streaming events // for several watches at once. + // The watch creation call will result in returning the current state of the subtree rpc Watch(stream WatchRequest) returns (stream WatchResponse) { option (google.api.http) = { post: "/events/v1:watch" @@ -234,10 +239,11 @@ message WatchRequest { } message WatchCreateRequest { - // used to identify - Meta key = 1; + // used to identify the watched subtree + Meta subtree = 1; // start watching from this revision. + // if not specified "now" is used. int64 start_revision = 2; enum FilterType { @@ -255,34 +261,45 @@ message WatchCancelRequest { int64 watch_id = 1; } -enum WatchResponseType { - // Reponse only contains data. - DATA = 0; +// Indicates that watch was successfully canceled. +message WatchCanceled { +} - // If the response is for a create watch request. - // The client should record the watch_id and expect to receive events for - // the created watcher from the same stream. - // All events sent to the created watcher will attach with the same watch_id. - WATCH_CREATED = 1; +// Indicates that a watch was successfully created. +message WatchCreated { + // returns the initial_state of the specified subtree. Watch stream will begin + // at the revision. + repeated Object initial_state = 1; +} - // canceled is set to true if the response is for a cancel watch request. - // No further events will be sent to the canceled watcher. - WATCH_CANCELED = 2; +// WatchEvents indicates that this message contains events from the watch stream. +message WatchEvents { + // returns events for the specified watch id. + repeated Event events = 4; } message WatchResponse { // watch_id is the ID of the watcher that corresponds to the response. int64 watch_id = 1; - // response_type specifies if this message is responding to - // a watch creation request, watch removal request - WatchResponseType response_type = 2; - // if watcher could not be created or had to be aborted status is NON-OK. - google.rpc.Status status = 3; - - repeated Event events = 4; -} + // client should not look at other fields if status is not OK and remove + // watch_id from the watch set. + google.rpc.Status status = 2; + + oneof response_union { + // Watch was successfully created. Client should record the watch_id for this watch. + // The response also contains the current state of the watched subtree. + WatchCreated created = 3; + + // response contains events from a watched subtree. + WatchEvents events = 4; + + // a previous watch was successfully canceled. + // No further events will be sent to the canceled watcher. + WatchCanceled canceled = 5; + }; +}; message Event { enum EventType { From 16f13e860145a63899863d8a860cc3aba3cec554 Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Thu, 15 Jun 2017 15:53:00 -0700 Subject: [PATCH 10/17] Review comments --- config/v1/service.proto | 71 +++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 41 deletions(-) diff --git a/config/v1/service.proto b/config/v1/service.proto index 659795315a..0cb432fc27 100644 --- a/config/v1/service.proto +++ b/config/v1/service.proto @@ -14,15 +14,15 @@ syntax = "proto3"; -package istio.config.v1; +package istio.galley.v1; import "google/rpc/status.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/empty.proto"; import "google/api/annotations.proto"; -// The Istio Config API service follows -// the kubenertes API server delegation and resource model. +// Galley follows +// the Kubenertes API server delegation and resource model. // /apiGroup/version/objecttype/{namespace}/objectname --> // // It generalizes the concept of namespace to an arbitrary grouping. @@ -31,8 +31,7 @@ import "google/api/annotations.proto"; // // api_group = /mixer/v1 or // api_group = /proxy/v1 -// + etcdv3 stream watch API -service Service { +service Galley { // Get a single object. rpc GetObject(GetObjectRequest) returns (Object) { option (google.api.http) = { @@ -41,8 +40,8 @@ service Service { }; // Get a list of objects. - // other arguments like meta.object_group, meta.name are optional - // This lets one list all object of a type, or all object of a type + // Other arguments like meta.object_group, meta.name are optional + // This lets the caller list all objects of a type, or all objects of a type // that is within an object group. rpc ListObjects(ListObjectsRequest) returns (ObjectList) { option (google.api.http) = { @@ -67,9 +66,8 @@ service Service { }; // Create an object. This may result in configuration validation errors. - // Referrential integrity is not generally guranteed, however individual validators - // may decide to validate for it. - rpc CreateObject(CreateObjectRequest) returns (Object) { + // Referential integrity should be maximally enforced, except where not possible or desirable. + rpc CreateObject(ObjectRequest) returns (Object) { option (google.api.http) = { post: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}" body: "source_data" @@ -77,7 +75,7 @@ service Service { }; // Update a single object. May return validation errors. - rpc UpdateObject(UpdateObjectRequest) returns (Object) { + rpc UpdateObject(ObjectRequest) returns (Object) { option (google.api.http) = { put: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}/{meta.name}" body: "source_data" @@ -95,12 +93,11 @@ service Service { // Watcher service is designed to efficiently watch mutiple subtrees of the resource tree. service Watcher { - // Watch method is borrowed from etcdv3 bi-directional streaming watches. // Watch watches for events happening or that have happened. Both input and output - // are streams; the input stream is for creating and canceling watchers and the output + // are streams; the input stream is for creating and cancelling watchers and the output // stream sends events. One watch RPC can watch on multiple key roots, streaming events // for several watches at once. - // The watch creation call will result in returning the current state of the subtree + // The watch creation call will result in returning the current state of the subtree. rpc Watch(stream WatchRequest) returns (stream WatchResponse) { option (google.api.http) = { post: "/events/v1:watch" @@ -128,23 +125,22 @@ message ListObjectsRequest { // incl(ude) selects fields to include in the result. // `include` is a reserved word. so not used here. - ObjectFieldInclude incl = 2; + ObjectFieldInclude include_fields= 2; } -message UpdateObjectRequest { +message ObjectRequest { // meta is the metadata associated with the object. Meta meta = 1; - - // source_data is the data as it was specified in json / yaml format. - google.protobuf.Struct source_data = 2; -} -message CreateObjectRequest { - // meta is the metadata associated with the object. - Meta meta = 1; - + // oneof source_data or data + // Note: an actual oneof is not used here because + // grpc gateway does not handle oneoff in request body + // source_data is the data as it was specified in json / yaml format. google.protobuf.Struct source_data = 2; + + // data is protos encoded as bytes only specify + bytes data = 3; } message GetObjectRequest { @@ -153,7 +149,7 @@ message GetObjectRequest { // incl(ude) selects fields to include in the result. // `include` is a reserved word. so not used here. - ObjectFieldInclude incl = 2; + ObjectFieldInclude include_fields= 2; } message DeleteObjectRequest { @@ -172,7 +168,7 @@ message Object { // data is the binary encoded protobuf data // Both representations are useful. // For example: - // If `souce_data` contains an expressions in text form + // If `source_data` contains an expressions in text form // `data` may contain a parsed AST bytes data = 3; } @@ -220,18 +216,19 @@ message Meta { // in the same place as before. string uid = 6; - // revision // revision of the repository, the last time Object was updated. int64 revision = 7; - // labels // labels associated with the object. map labels = 8; } -// watchers follows etcdv3 watch pattern. +// WatchRequest creates on cancels a watch. +// Create and cancel are part of the same message because the WatchRequest message +// is used in a streaming API. The client may add new watchers and remove old watchers +// on an existing stream. message WatchRequest { - // request_union is a request to either create a new watcher or cancel an existing watcher. + // request_union indicates whether to create a new watcher or cancel an existing watcher. oneof request_union { WatchCreateRequest create_request = 1; WatchCancelRequest cancel_request = 2; @@ -242,18 +239,10 @@ message WatchCreateRequest { // used to identify the watched subtree Meta subtree = 1; - // start watching from this revision. + // start watching from this revision of the repository. + // If the requested revision is not available, the watch request should fail. // if not specified "now" is used. int64 start_revision = 2; - - enum FilterType { - // filter out put event. - NOPUT = 0; - // filter out delete event. - NODELETE = 1; - } - // filters filter the events at server side before it sends back to the watcher. - repeated FilterType filters = 3; } message WatchCancelRequest { @@ -303,7 +292,7 @@ message WatchResponse { message Event { enum EventType { - UPDATE = 0; // ADD and UPDATE + PUT = 0; // ADD and UPDATE DELETE = 1; } // type is the kind of event. If type is a PUT, it indicates From fdd5db36aa4566f672ce321b14f22b790fd8fb11 Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Thu, 15 Jun 2017 15:53:48 -0700 Subject: [PATCH 11/17] Move service definition to a new location. --- {config => galley}/v1/service.proto | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {config => galley}/v1/service.proto (100%) diff --git a/config/v1/service.proto b/galley/v1/service.proto similarity index 100% rename from config/v1/service.proto rename to galley/v1/service.proto From 6853e769e3a21e647adb4c2215858ed27dc38503 Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Fri, 16 Jun 2017 10:18:21 -0700 Subject: [PATCH 12/17] Add ObjectValidator grpc service change api_group_version -> object_type_version, --- galley/v1/service.proto | 136 +++++++++++++++++++++++++++++----------- 1 file changed, 98 insertions(+), 38 deletions(-) diff --git a/galley/v1/service.proto b/galley/v1/service.proto index 0cb432fc27..b504c874f5 100644 --- a/galley/v1/service.proto +++ b/galley/v1/service.proto @@ -27,15 +27,15 @@ import "google/api/annotations.proto"; // // It generalizes the concept of namespace to an arbitrary grouping. // -// /apiGroup/version/objecttype/{objectGroup}/objectname +// /apiGroup//objecttype/version/{objectGroup}/objectname // -// api_group = /mixer/v1 or -// api_group = /proxy/v1 +// api_group = /core/ +// api_group = /vendor1 service Galley { // Get a single object. rpc GetObject(GetObjectRequest) returns (Object) { option (google.api.http) = { - get: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}/{meta.name}" + get: "/{meta.api_group}/{meta.object_type}/{meta.object_type_version}/{meta.object_group}/{meta.name}" }; }; @@ -46,9 +46,9 @@ service Galley { rpc ListObjects(ListObjectsRequest) returns (ObjectList) { option (google.api.http) = { // meta.object_group can be specified as a query parameter - get: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}" + get: "/{meta.api_group}/{meta.object_type}/{meta.object_type_version}" additional_bindings: { - get: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}" + get: "/{meta.api_group}/{meta.object_type}/{meta.object_type_version}/{meta.object_group}" }; }; }; @@ -58,7 +58,7 @@ service Galley { // within an api group. rpc ListObjectTypes(ListObjectTypesRequest) returns (ObjectTypeList) { option (google.api.http) = { - get: "/{meta.api_group}/{meta.api_group_version}" + get: "/{meta.api_group}" additional_bindings: { get: "/" }; @@ -69,7 +69,7 @@ service Galley { // Referential integrity should be maximally enforced, except where not possible or desirable. rpc CreateObject(ObjectRequest) returns (Object) { option (google.api.http) = { - post: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}" + post: "/{meta.api_group}/{meta.object_type}/{meta.object_type_version}/{meta.object_group}" body: "source_data" }; }; @@ -77,7 +77,7 @@ service Galley { // Update a single object. May return validation errors. rpc UpdateObject(ObjectRequest) returns (Object) { option (google.api.http) = { - put: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}/{meta.name}" + put: "/{meta.api_group}/{meta.object_type}/{meta.object_type_version}/{meta.object_group}/{meta.name}" body: "source_data" }; }; @@ -85,7 +85,7 @@ service Galley { // Delete a single object. May return validation errors. rpc DeleteObject(DeleteObjectRequest) returns (google.protobuf.Empty) { option (google.api.http) = { - delete: "/{meta.api_group}/{meta.api_group_version}/{meta.object_type}/{meta.object_group}/{meta.name}" + delete: "/{meta.api_group}/{meta.object_type}/{meta.object_type_version}/{meta.object_group}/{meta.name}" }; }; }; @@ -104,28 +104,69 @@ service Watcher { body: "*" }; }; -} +}; -message ObjectFieldInclude { - // if true object(s) should include data. - bool data = 1; - // if true object(s) should include source_data. - bool source_data = 2; +// Object validator service validates objects before they are committed to storage. +// Galley maintains a map of object_types to validators. A single validator may validate many types. +// For example MixerValidator Service should validate all Mixer resources. +service ObjectValidator { + // Validate the resource and convert it to typed proto if applicable + // if Object.source_data is specified, it should be converted + // to the appropriate proto representation. + // Every attempt should be made to do a deep validation. + // If full validation requires referential integrity checks, this service should use the + // GalleyWatch Service to maintain current view of configuration. + // + // For example A Mixer rule consists of a selector expression and a named handler amongst other things. + // Mixer validator should check + // 1. expression syntax is valid + // 2. expression uses known attributes + // 3. Rule refers to a known handler + // 4. Any other semantic check that is required for full validation. + // + // It should convert untyped proto into typed proto and return binary encoding of it in Object.data. + // + // On validation failure, it should return a validation error with text. + rpc ValidateAndConvert(ValidationRequest) returns (Object) { + option (google.api.http) = { + post: "/resources/v1:validate" + body: "*" + }; + }; +}; + +message ValidationRequest { + oneof request_union { + // This object should be validated and converted to binary encoded proto. + Object object = 1; + + // If this object was deleted. + // In this case Validator should check referential integrity. + // Only metadata about the object being deleted is sent. + Meta deleted = 2; + } + + // Object should be validated against this revision of the repository. + // If validator or the object is agnostic to repository versions, this will be ignored. + // This is useful for referential integrity checking. + int64 validation_revision = 3; } message ListObjectTypesRequest { // meta is the metadata associated with the root where listing begins. Meta meta = 1; + + // paged result, set to empty on first page. + string page_token = 2; } message ListObjectsRequest { // meta is the metadata associated with the root where listing begins. Meta meta = 1; - // incl(ude) selects fields to include in the result. - // `include` is a reserved word. so not used here. - ObjectFieldInclude include_fields= 2; + // paged result, set to empty on first page. + string page_token = 2; } message ObjectRequest { @@ -133,23 +174,17 @@ message ObjectRequest { Meta meta = 1; // oneof source_data or data - // Note: an actual oneof is not used here because - // grpc gateway does not handle oneoff in request body // source_data is the data as it was specified in json / yaml format. google.protobuf.Struct source_data = 2; - // data is protos encoded as bytes only specify + // data is protos encoded as bytes. bytes data = 3; } message GetObjectRequest { // meta is the metadata associated with the object. Meta meta = 1; - - // incl(ude) selects fields to include in the result. - // `include` is a reserved word. so not used here. - ObjectFieldInclude include_fields= 2; } message DeleteObjectRequest { @@ -157,7 +192,7 @@ message DeleteObjectRequest { Meta meta = 1; } -// Object +// Object is the concrete representation of a resource. message Object { // meta is the metadata associated with the object. Meta meta = 1; @@ -179,6 +214,10 @@ message ObjectTypeList { // list of objects returned. repeated Meta object_types = 2; + + // If next_page_token is not empty, this is a paged result. + // use this value in the next request. + string next_page_token = 3; } message ObjectList { @@ -187,22 +226,25 @@ message ObjectList { // list of objects returned. repeated Object objects = 2; + + // If next_page_token is not empty, this is a paged result. + // use this value in the next request. + string next_page_token = 3; } // Meta message Meta { - // api_group is the top level delegation. - // All messages from an api group are handled by the same delegation handler. - // api group itself is versioned. + // api_group is the top level delegation and extension point. string api_group = 1; - // every api group is independently versioned. - string api_group_version = 2; - // objectType is the type of an object. - // route-rule, metrics-type, metrics-ctor, ... - string object_type = 3; + // It corresponds to a behavior being configured. + // route-rule, metrics, logs, ... + string object_type = 2; + + // every object type is independently versioned. + string object_type_version = 3; // objectGroup is an arbitrary hierarchical grouping of resources. // For Mixer configuration object_group == mesh, svc:svc1, svc:svc2 ... @@ -212,9 +254,9 @@ message Meta { // name of the object. string name = 5; - // uid assigned to the object. Only used when a new object is created + // uuid assigned to the object. Only used when a new object is created // in the same place as before. - string uid = 6; + string uuid = 6; // revision of the repository, the last time Object was updated. int64 revision = 7; @@ -259,6 +301,9 @@ message WatchCreated { // returns the initial_state of the specified subtree. Watch stream will begin // at the revision. repeated Object initial_state = 1; + + // Revision of the tree described in the initial state. + int64 current_revision = 2; } // WatchEvents indicates that this message contains events from the watch stream. @@ -267,11 +312,20 @@ message WatchEvents { repeated Event events = 4; } +// WatchProgress message is sent periodically. +message WatchProgress { + // Revision of the repository when this event was sent. + int64 current_revision = 1; +} + + +// The client should WatchResponse message WatchResponse { // watch_id is the ID of the watcher that corresponds to the response. + // watch_id does not apply to the unsolicited "Progress" message. int64 watch_id = 1; - // if watcher could not be created or had to be aborted status is NON-OK. + // if a watcher could not be created or had to be aborted status is NON-OK. // client should not look at other fields if status is not OK and remove // watch_id from the watch set. google.rpc.Status status = 2; @@ -287,9 +341,14 @@ message WatchResponse { // a previous watch was successfully canceled. // No further events will be sent to the canceled watcher. WatchCanceled canceled = 5; + + // Server sends periodic messages of progress when no actual watches fire. + // The client knows it is caught up to a certain revision of the repository. + WatchProgress progress = 6; }; }; + message Event { enum EventType { PUT = 0; // ADD and UPDATE @@ -299,6 +358,7 @@ message Event { // new data has been stored to the key. If type is a DELETE, // it indicates the key was deleted. EventType type = 1; + // kv holds the KeyValue for the event. // A PUT event contains current kv pair. // A PUT event with kv.Version=1 indicates the creation of a key. From 112c7cde63d5948705c40edfb3379ae9d897d1d1 Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Mon, 19 Jun 2017 10:46:47 -0700 Subject: [PATCH 13/17] Add batching of validation requests, useful during initial import --- galley/v1/service.proto | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/galley/v1/service.proto b/galley/v1/service.proto index b504c874f5..06d93fd855 100644 --- a/galley/v1/service.proto +++ b/galley/v1/service.proto @@ -136,8 +136,9 @@ service ObjectValidator { }; }; -message ValidationRequest { - oneof request_union { +// Validation repesents individual change to be validated. +message Validation { + oneof validation_union { // This object should be validated and converted to binary encoded proto. Object object = 1; @@ -146,9 +147,15 @@ message ValidationRequest { // Only metadata about the object being deleted is sent. Meta deleted = 2; } +} - // Object should be validated against this revision of the repository. - // If validator or the object is agnostic to repository versions, this will be ignored. +message ValidationRequest { + // Supports multiple ordered changes to be validated together. + // When a large config is pushed into Galley, batching + // validation requests is an optimization. + repeated Validation validations = 1; + // Objects should be validated against this revision of the repository. + // If the validator or the object is agnostic to repository versions, this can be ignored. // This is useful for referential integrity checking. int64 validation_revision = 3; } From e69e26606ce8e827b573957c68960b435ddb5230 Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Mon, 19 Jun 2017 15:07:01 -0700 Subject: [PATCH 14/17] add max_page_size to list requests --- galley/v1/service.proto | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/galley/v1/service.proto b/galley/v1/service.proto index 06d93fd855..8ac6c91266 100644 --- a/galley/v1/service.proto +++ b/galley/v1/service.proto @@ -166,6 +166,9 @@ message ListObjectTypesRequest { // paged result, set to empty on first page. string page_token = 2; + + // If non zero, response should have at most these number of entries. + int32 max_page_size = 3; } message ListObjectsRequest { @@ -174,6 +177,9 @@ message ListObjectsRequest { // paged result, set to empty on first page. string page_token = 2; + + // If non zero, response should have at most these number of entries. + int32 max_page_size = 3; } message ObjectRequest { From 69c7618868f346e1092f9f3776bc457aff5c8dbb Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Tue, 20 Jun 2017 12:31:49 -0700 Subject: [PATCH 15/17] Object --> ConfigObject, change names of Meta to key or query --- galley/v1/service.proto | 58 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/galley/v1/service.proto b/galley/v1/service.proto index 8ac6c91266..5c3be4dea7 100644 --- a/galley/v1/service.proto +++ b/galley/v1/service.proto @@ -33,22 +33,22 @@ import "google/api/annotations.proto"; // api_group = /vendor1 service Galley { // Get a single object. - rpc GetObject(GetObjectRequest) returns (Object) { + rpc GetObject(GetObjectRequest) returns (ConfigObject) { option (google.api.http) = { - get: "/{meta.api_group}/{meta.object_type}/{meta.object_type_version}/{meta.object_group}/{meta.name}" + get: "/{key.api_group}/{key.object_type}/{key.object_type_version}/{key.object_group}/{key.name}" }; }; // Get a list of objects. - // Other arguments like meta.object_group, meta.name are optional + // Other arguments like query.object_group, query.name are optional // This lets the caller list all objects of a type, or all objects of a type // that is within an object group. rpc ListObjects(ListObjectsRequest) returns (ObjectList) { option (google.api.http) = { // meta.object_group can be specified as a query parameter - get: "/{meta.api_group}/{meta.object_type}/{meta.object_type_version}" + get: "/{query.api_group}/{query.object_type}/{query.object_type_version}" additional_bindings: { - get: "/{meta.api_group}/{meta.object_type}/{meta.object_type_version}/{meta.object_group}" + get: "/{query.api_group}/{query.object_type}/{query.object_type_version}/{query.object_group}" }; }; }; @@ -67,17 +67,17 @@ service Galley { // Create an object. This may result in configuration validation errors. // Referential integrity should be maximally enforced, except where not possible or desirable. - rpc CreateObject(ObjectRequest) returns (Object) { + rpc CreateObject(ObjectRequest) returns (ConfigObject) { option (google.api.http) = { - post: "/{meta.api_group}/{meta.object_type}/{meta.object_type_version}/{meta.object_group}" + post: "/{key.api_group}/{key.object_type}/{key.object_type_version}/{key.object_group}" body: "source_data" }; }; // Update a single object. May return validation errors. - rpc UpdateObject(ObjectRequest) returns (Object) { + rpc UpdateObject(ObjectRequest) returns (ConfigObject) { option (google.api.http) = { - put: "/{meta.api_group}/{meta.object_type}/{meta.object_type_version}/{meta.object_group}/{meta.name}" + put: "/{key.api_group}/{key.object_type}/{key.object_type_version}/{key.object_group}/{key.name}" body: "source_data" }; }; @@ -110,7 +110,7 @@ service Watcher { // Object validator service validates objects before they are committed to storage. // Galley maintains a map of object_types to validators. A single validator may validate many types. // For example MixerValidator Service should validate all Mixer resources. -service ObjectValidator { +service ObjectValidatorAndConverter { // Validate the resource and convert it to typed proto if applicable // if Object.source_data is specified, it should be converted // to the appropriate proto representation. @@ -128,7 +128,7 @@ service ObjectValidator { // It should convert untyped proto into typed proto and return binary encoding of it in Object.data. // // On validation failure, it should return a validation error with text. - rpc ValidateAndConvert(ValidationRequest) returns (Object) { + rpc ValidateAndConvert(ValidationRequest) returns (ConfigObject) { option (google.api.http) = { post: "/resources/v1:validate" body: "*" @@ -140,7 +140,7 @@ service ObjectValidator { message Validation { oneof validation_union { // This object should be validated and converted to binary encoded proto. - Object object = 1; + ConfigObject object = 1; // If this object was deleted. // In this case Validator should check referential integrity. @@ -162,7 +162,7 @@ message ValidationRequest { message ListObjectTypesRequest { // meta is the metadata associated with the root where listing begins. - Meta meta = 1; + Meta query = 1; // paged result, set to empty on first page. string page_token = 2; @@ -173,7 +173,7 @@ message ListObjectTypesRequest { message ListObjectsRequest { // meta is the metadata associated with the root where listing begins. - Meta meta = 1; + Meta query = 1; // paged result, set to empty on first page. string page_token = 2; @@ -183,8 +183,8 @@ message ListObjectsRequest { } message ObjectRequest { - // meta is the metadata associated with the object. - Meta meta = 1; + // key associated with the requested object. + Meta key = 1; // oneof source_data or data @@ -196,17 +196,17 @@ message ObjectRequest { } message GetObjectRequest { - // meta is the metadata associated with the object. - Meta meta = 1; + // key associated with the object to fetch. + Meta key = 1; } message DeleteObjectRequest { - // meta is the metadata associated with the object. - Meta meta = 1; + // key associated with the requested object. + Meta key = 1; } -// Object is the concrete representation of a resource. -message Object { +// ConfigObject is the concrete representation of a resource. +message ConfigObject { // meta is the metadata associated with the object. Meta meta = 1; @@ -238,7 +238,7 @@ message ObjectList { Meta meta = 1; // list of objects returned. - repeated Object objects = 2; + repeated ConfigObject objects = 2; // If next_page_token is not empty, this is a paged result. // use this value in the next request. @@ -246,7 +246,7 @@ message ObjectList { } -// Meta +// Meta is the metadata associated with an object. message Meta { // api_group is the top level delegation and extension point. string api_group = 1; @@ -271,7 +271,7 @@ message Meta { // in the same place as before. string uuid = 6; - // revision of the repository, the last time Object was updated. + // revision of the repository, the last time ConfigObject was updated. int64 revision = 7; // labels associated with the object. @@ -313,9 +313,9 @@ message WatchCanceled { message WatchCreated { // returns the initial_state of the specified subtree. Watch stream will begin // at the revision. - repeated Object initial_state = 1; + repeated ConfigObject initial_state = 1; - // Revision of the tree described in the initial state. + // Revision of the repository when the initial state was produced. int64 current_revision = 2; } @@ -377,8 +377,8 @@ message Event { // A PUT event with kv.Version=1 indicates the creation of a key. // A DELETE event contains the deleted key with // its modification revision set to the revision of deletion. - Object kv = 2; + ConfigObject kv = 2; // prev_kv holds the key-value pair before the event happens. - Object prev_kv = 3; + ConfigObject prev_kv = 3; } From 4d671ada963b192ca0c3c866714bee301b2ee4ab Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Tue, 20 Jun 2017 14:22:21 -0700 Subject: [PATCH 16/17] review comments --- galley/v1/service.proto | 143 ++++------------------------------------ galley/v1/watcher.proto | 142 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 132 deletions(-) create mode 100644 galley/v1/watcher.proto diff --git a/galley/v1/service.proto b/galley/v1/service.proto index 5c3be4dea7..7c70b44e0e 100644 --- a/galley/v1/service.proto +++ b/galley/v1/service.proto @@ -1,5 +1,4 @@ // Copyright 2017 Istio Authors -// vim: set expandtab ts=2 sw=2: // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -16,21 +15,20 @@ syntax = "proto3"; package istio.galley.v1; -import "google/rpc/status.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/empty.proto"; import "google/api/annotations.proto"; // Galley follows // the Kubenertes API server delegation and resource model. -// /apiGroup/version/objecttype/{namespace}/objectname --> +// /apiGroup/version/objecttype/{namespace}/objectname // // It generalizes the concept of namespace to an arbitrary grouping. // -// /apiGroup//objecttype/version/{objectGroup}/objectname +// /apiGroup/objecttype/version/{objectGroup}/objectname // -// api_group = /core/ -// api_group = /vendor1 +// apiGroup = /core/ +// apiGroup = /vendor1 service Galley { // Get a single object. rpc GetObject(GetObjectRequest) returns (ConfigObject) { @@ -90,27 +88,10 @@ service Galley { }; }; - -// Watcher service is designed to efficiently watch mutiple subtrees of the resource tree. -service Watcher { - // Watch watches for events happening or that have happened. Both input and output - // are streams; the input stream is for creating and cancelling watchers and the output - // stream sends events. One watch RPC can watch on multiple key roots, streaming events - // for several watches at once. - // The watch creation call will result in returning the current state of the subtree. - rpc Watch(stream WatchRequest) returns (stream WatchResponse) { - option (google.api.http) = { - post: "/events/v1:watch" - body: "*" - }; - }; -}; - - // Object validator service validates objects before they are committed to storage. // Galley maintains a map of object_types to validators. A single validator may validate many types. // For example MixerValidator Service should validate all Mixer resources. -service ObjectValidatorAndConverter { +service ObjectValidatorAndTransformer { // Validate the resource and convert it to typed proto if applicable // if Object.source_data is specified, it should be converted // to the appropriate proto representation. @@ -118,7 +99,7 @@ service ObjectValidatorAndConverter { // If full validation requires referential integrity checks, this service should use the // GalleyWatch Service to maintain current view of configuration. // - // For example A Mixer rule consists of a selector expression and a named handler amongst other things. + // For example a Mixer rule consists of a selector expression and a named handler amongst other things. // Mixer validator should check // 1. expression syntax is valid // 2. expression uses known attributes @@ -128,7 +109,7 @@ service ObjectValidatorAndConverter { // It should convert untyped proto into typed proto and return binary encoding of it in Object.data. // // On validation failure, it should return a validation error with text. - rpc ValidateAndConvert(ValidationRequest) returns (ConfigObject) { + rpc ValidateAndTransform(ValidationRequest) returns (ConfigObject) { option (google.api.http) = { post: "/resources/v1:validate" body: "*" @@ -191,7 +172,10 @@ message ObjectRequest { // source_data is the data as it was specified in json / yaml format. google.protobuf.Struct source_data = 2; - // data is protos encoded as bytes. + // data is the binary encoded protobuf data + // For example: + // If `source_data` contains an expressions in text form + // `data` may contain a parsed AST bytes data = 3; } @@ -214,7 +198,6 @@ message ConfigObject { google.protobuf.Struct source_data = 2; // data is the binary encoded protobuf data - // Both representations are useful. // For example: // If `source_data` contains an expressions in text form // `data` may contain a parsed AST @@ -278,107 +261,3 @@ message Meta { map labels = 8; } -// WatchRequest creates on cancels a watch. -// Create and cancel are part of the same message because the WatchRequest message -// is used in a streaming API. The client may add new watchers and remove old watchers -// on an existing stream. -message WatchRequest { - // request_union indicates whether to create a new watcher or cancel an existing watcher. - oneof request_union { - WatchCreateRequest create_request = 1; - WatchCancelRequest cancel_request = 2; - } -} - -message WatchCreateRequest { - // used to identify the watched subtree - Meta subtree = 1; - - // start watching from this revision of the repository. - // If the requested revision is not available, the watch request should fail. - // if not specified "now" is used. - int64 start_revision = 2; -} - -message WatchCancelRequest { - // watch_id is the watcher id to cancel so that no more events are transmitted. - int64 watch_id = 1; -} - -// Indicates that watch was successfully canceled. -message WatchCanceled { -} - -// Indicates that a watch was successfully created. -message WatchCreated { - // returns the initial_state of the specified subtree. Watch stream will begin - // at the revision. - repeated ConfigObject initial_state = 1; - - // Revision of the repository when the initial state was produced. - int64 current_revision = 2; -} - -// WatchEvents indicates that this message contains events from the watch stream. -message WatchEvents { - // returns events for the specified watch id. - repeated Event events = 4; -} - -// WatchProgress message is sent periodically. -message WatchProgress { - // Revision of the repository when this event was sent. - int64 current_revision = 1; -} - - -// The client should WatchResponse -message WatchResponse { - // watch_id is the ID of the watcher that corresponds to the response. - // watch_id does not apply to the unsolicited "Progress" message. - int64 watch_id = 1; - - // if a watcher could not be created or had to be aborted status is NON-OK. - // client should not look at other fields if status is not OK and remove - // watch_id from the watch set. - google.rpc.Status status = 2; - - oneof response_union { - // Watch was successfully created. Client should record the watch_id for this watch. - // The response also contains the current state of the watched subtree. - WatchCreated created = 3; - - // response contains events from a watched subtree. - WatchEvents events = 4; - - // a previous watch was successfully canceled. - // No further events will be sent to the canceled watcher. - WatchCanceled canceled = 5; - - // Server sends periodic messages of progress when no actual watches fire. - // The client knows it is caught up to a certain revision of the repository. - WatchProgress progress = 6; - }; -}; - - -message Event { - enum EventType { - PUT = 0; // ADD and UPDATE - DELETE = 1; - } - // type is the kind of event. If type is a PUT, it indicates - // new data has been stored to the key. If type is a DELETE, - // it indicates the key was deleted. - EventType type = 1; - - // kv holds the KeyValue for the event. - // A PUT event contains current kv pair. - // A PUT event with kv.Version=1 indicates the creation of a key. - // A DELETE event contains the deleted key with - // its modification revision set to the revision of deletion. - ConfigObject kv = 2; - - // prev_kv holds the key-value pair before the event happens. - ConfigObject prev_kv = 3; -} diff --git a/galley/v1/watcher.proto b/galley/v1/watcher.proto new file mode 100644 index 0000000000..28a1f58a45 --- /dev/null +++ b/galley/v1/watcher.proto @@ -0,0 +1,142 @@ +// Copyright 2017 Istio Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package istio.galley.v1; + +import "google/rpc/status.proto"; +import "google/api/annotations.proto"; + +import "service.proto"; + +// Galley Watcher service is designed to efficiently watch mutiple subtrees of the resource tree. +service Watcher { + // Watch watches for events happening or that have happened. Both input and output + // are streams; the input stream is for creating and cancelling watchers and the output + // stream sends events. One watch RPC can watch on multiple key roots, streaming events + // for several watches at once. + // The watch creation call will result in returning the current state of the subtree. + rpc Watch(stream WatchRequest) returns (stream WatchResponse) { + option (google.api.http) = { + post: "/events/v1:watch" + body: "*" + }; + }; +}; + + +// WatchRequest creates on cancels a watch. +// Create and cancel are part of the same message because the WatchRequest message +// is used in a streaming API. The client may add new watchers and remove old watchers +// on an existing stream. +message WatchRequest { + // request_union indicates whether to create a new watcher or cancel an existing watcher. + oneof request_union { + WatchCreateRequest create_request = 1; + WatchCancelRequest cancel_request = 2; + } +} + +message WatchCreateRequest { + // used to identify the watched subtree + Meta subtree = 1; + + // start watching from this revision of the repository. + // If the requested revision is not available, the watch request should fail. + // if not specified "now" is used. + int64 start_revision = 2; +} + +message WatchCancelRequest { + // watch_id is the watcher id to cancel so that no more events are transmitted. + int64 watch_id = 1; +} + +// Indicates that watch was successfully canceled. +message WatchCanceled { +} + +// Indicates that a watch was successfully created. +message WatchCreated { + // returns the initial_state of the specified subtree. Watch stream will begin + // at the revision. + repeated ConfigObject initial_state = 1; + + // Revision of the repository when the initial state was produced. + int64 current_revision = 2; +} + +// WatchEvents indicates that this message contains events from the watch stream. +message WatchEvents { + // returns events for the specified watch id. + repeated Event events = 4; +} + +// WatchProgress message is sent periodically. +message WatchProgress { + // Revision of the repository when this event was sent. + int64 current_revision = 1; +} + + +// The client should WatchResponse +message WatchResponse { + // watch_id is the ID of the watcher that corresponds to the response. + // watch_id does not apply to the unsolicited "Progress" message. + int64 watch_id = 1; + + // if a watcher could not be created or had to be aborted status is NON-OK. + // client should not look at other fields if status is not OK and remove + // watch_id from the watch set. + google.rpc.Status status = 2; + + oneof response_union { + // Watch was successfully created. Client should record the watch_id for this watch. + // The response also contains the current state of the watched subtree. + WatchCreated created = 3; + + // response contains events from a watched subtree. + WatchEvents events = 4; + + // a previous watch was successfully canceled. + // No further events will be sent to the canceled watcher. + WatchCanceled canceled = 5; + + // Server sends periodic messages of progress when no actual watches fire. + // The client knows it is caught up to a certain revision of the repository. + WatchProgress progress = 6; + }; +}; + + +message Event { + enum EventType { + PUT = 0; // ADD and UPDATE + DELETE = 1; + } + // type is the kind of event. If type is a PUT, it indicates + // new data has been stored to the key. If type is a DELETE, + // it indicates the key was deleted. + EventType type = 1; + + // kv holds the KeyValue for the event. + // A PUT event contains current kv pair. + // A PUT event with kv.Version=1 indicates the creation of a key. + // A DELETE event contains the deleted key with + // its modification revision set to the revision of deletion. + ConfigObject kv = 2; + + // prev_kv holds the key-value pair before the event happens. + ConfigObject prev_kv = 3; +} From 308f87bd16e0ca5f247d2f2a3a3a77a0307df6cc Mon Sep 17 00:00:00 2001 From: Mandar U Jog Date: Thu, 22 Jun 2017 11:05:17 -0700 Subject: [PATCH 17/17] split into 3 files, add ValidationError message --- galley/v1/service.proto | 108 +++++++++++++++++--------------------- galley/v1/validator.proto | 89 +++++++++++++++++++++++++++++++ galley/v1/watcher.proto | 3 +- 3 files changed, 137 insertions(+), 63 deletions(-) create mode 100644 galley/v1/validator.proto diff --git a/galley/v1/service.proto b/galley/v1/service.proto index 7c70b44e0e..b6bf5d4424 100644 --- a/galley/v1/service.proto +++ b/galley/v1/service.proto @@ -15,9 +15,9 @@ syntax = "proto3"; package istio.galley.v1; -import "google/protobuf/struct.proto"; -import "google/protobuf/empty.proto"; import "google/api/annotations.proto"; +import "google/protobuf/struct.proto"; +import "google/rpc/status.proto"; // Galley follows // the Kubenertes API server delegation and resource model. @@ -28,7 +28,7 @@ import "google/api/annotations.proto"; // /apiGroup/objecttype/version/{objectGroup}/objectname // // apiGroup = /core/ -// apiGroup = /vendor1 +// apiGroup = /vendor1/ service Galley { // Get a single object. rpc GetObject(GetObjectRequest) returns (ConfigObject) { @@ -41,7 +41,7 @@ service Galley { // Other arguments like query.object_group, query.name are optional // This lets the caller list all objects of a type, or all objects of a type // that is within an object group. - rpc ListObjects(ListObjectsRequest) returns (ObjectList) { + rpc ListObjects(ListObjectsRequest) returns (ListObjectsResponse) { option (google.api.http) = { // meta.object_group can be specified as a query parameter get: "/{query.api_group}/{query.object_type}/{query.object_type_version}" @@ -54,7 +54,7 @@ service Galley { // Get a list of object types. // Lists all object types or all object types // within an api group. - rpc ListObjectTypes(ListObjectTypesRequest) returns (ObjectTypeList) { + rpc ListObjectTypes(ListObjectTypesRequest) returns (ListObjectTypesResponse) { option (google.api.http) = { get: "/{meta.api_group}" additional_bindings: { @@ -65,7 +65,7 @@ service Galley { // Create an object. This may result in configuration validation errors. // Referential integrity should be maximally enforced, except where not possible or desirable. - rpc CreateObject(ObjectRequest) returns (ConfigObject) { + rpc CreateObject(UpdateObjectRequest) returns (UpdateObjectResponse) { option (google.api.http) = { post: "/{key.api_group}/{key.object_type}/{key.object_type_version}/{key.object_group}" body: "source_data" @@ -73,7 +73,7 @@ service Galley { }; // Update a single object. May return validation errors. - rpc UpdateObject(ObjectRequest) returns (ConfigObject) { + rpc UpdateObject(UpdateObjectRequest) returns (UpdateObjectResponse) { option (google.api.http) = { put: "/{key.api_group}/{key.object_type}/{key.object_type_version}/{key.object_group}/{key.name}" body: "source_data" @@ -81,64 +81,50 @@ service Galley { }; // Delete a single object. May return validation errors. - rpc DeleteObject(DeleteObjectRequest) returns (google.protobuf.Empty) { + rpc DeleteObject(DeleteObjectRequest) returns (DeleteObjectResponse) { option (google.api.http) = { delete: "/{meta.api_group}/{meta.object_type}/{meta.object_type_version}/{meta.object_group}/{meta.name}" }; }; }; -// Object validator service validates objects before they are committed to storage. -// Galley maintains a map of object_types to validators. A single validator may validate many types. -// For example MixerValidator Service should validate all Mixer resources. -service ObjectValidatorAndTransformer { - // Validate the resource and convert it to typed proto if applicable - // if Object.source_data is specified, it should be converted - // to the appropriate proto representation. - // Every attempt should be made to do a deep validation. - // If full validation requires referential integrity checks, this service should use the - // GalleyWatch Service to maintain current view of configuration. - // - // For example a Mixer rule consists of a selector expression and a named handler amongst other things. - // Mixer validator should check - // 1. expression syntax is valid - // 2. expression uses known attributes - // 3. Rule refers to a known handler - // 4. Any other semantic check that is required for full validation. - // - // It should convert untyped proto into typed proto and return binary encoding of it in Object.data. - // - // On validation failure, it should return a validation error with text. - rpc ValidateAndTransform(ValidationRequest) returns (ConfigObject) { - option (google.api.http) = { - post: "/resources/v1:validate" - body: "*" - }; - }; -}; -// Validation repesents individual change to be validated. -message Validation { - oneof validation_union { - // This object should be validated and converted to binary encoded proto. - ConfigObject object = 1; - - // If this object was deleted. - // In this case Validator should check referential integrity. - // Only metadata about the object being deleted is sent. - Meta deleted = 2; - } +// DeleteObjectResponse is returned when an attempt is made to delete an object +// from the store. +message DeleteObjectResponse{ + // result of the operation + // if status == INVALID_ARGUMENT + // check errors for details. + google.rpc.Status status = 1; + + repeated ValidationError validation_errors = 2; +} + +// UpdateObjectResponse is returned when an attempt is made to update the store. +// ADD or UPDATE operations. +message UpdateObjectResponse { + // result of the operation + // if status == INVALID_ARGUMENT + // check errors for details. + google.rpc.Status status = 1; + + // state of the object after the change. + ConfigObject object = 2; + + // errors if st + repeated ValidationError validation_errors = 3; } -message ValidationRequest { - // Supports multiple ordered changes to be validated together. - // When a large config is pushed into Galley, batching - // validation requests is an optimization. - repeated Validation validations = 1; - // Objects should be validated against this revision of the repository. - // If the validator or the object is agnostic to repository versions, this can be ignored. - // This is useful for referential integrity checking. - int64 validation_revision = 3; +message ValidationError { + // The key of the object where error was detected. + // This may not be the object that introduced the error. + string key = 1; + // The primary field that was in error, if available. + string field = 2; + // The line number on which error occurred, if available. + int32 line_number = 3; + // Textual error message. + string error = 4; } message ListObjectTypesRequest { @@ -163,7 +149,7 @@ message ListObjectsRequest { int32 max_page_size = 3; } -message ObjectRequest { +message UpdateObjectRequest { // key associated with the requested object. Meta key = 1; @@ -204,7 +190,7 @@ message ConfigObject { bytes data = 3; } -message ObjectTypeList { +message ListObjectTypesResponse { // meta is the metadata associated with this list. Meta meta = 1; @@ -216,7 +202,7 @@ message ObjectTypeList { string next_page_token = 3; } -message ObjectList { +message ListObjectsResponse { // meta is the metadata associated with this list. Meta meta = 1; @@ -234,7 +220,7 @@ message Meta { // api_group is the top level delegation and extension point. string api_group = 1; - // objectType is the type of an object. + // object_type is the type of an object. // It corresponds to a behavior being configured. // route-rule, metrics, logs, ... string object_type = 2; @@ -242,7 +228,7 @@ message Meta { // every object type is independently versioned. string object_type_version = 3; - // objectGroup is an arbitrary hierarchical grouping of resources. + // object_group is an arbitrary hierarchical grouping of resources. // For Mixer configuration object_group == mesh, svc:svc1, svc:svc2 ... // For Proxy it can be mesh, destination. string object_group = 4; diff --git a/galley/v1/validator.proto b/galley/v1/validator.proto new file mode 100644 index 0000000000..e95a889a12 --- /dev/null +++ b/galley/v1/validator.proto @@ -0,0 +1,89 @@ +// Copyright 2017 Istio Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package istio.galley.v1; + +import "google/rpc/status.proto"; +import "google/api/annotations.proto"; + +import "service.proto"; + +// ValidatorAndTransformer service validates objects before they are committed to storage. +// Galley maintains a map of object_types to validators. A single validator may validate many types. +// For example MixerValidator service should validate all Mixer resources. +service ValidatorAndTransformer { + // Validate the resource and convert it to typed proto if applicable + // if Object.source_data is specified, it should be converted + // to the appropriate proto representation. + // Every attempt should be made to do a deep validation. + // If full validation requires referential integrity checks, this service should use the + // GalleyWatch Service to maintain current view of configuration. + // + // For example a Mixer rule consists of a selector expression and a named handler amongst other things. + // Mixer validator should check + // 1. expression syntax is valid + // 2. expression uses known attributes + // 3. Rule refers to a known handler + // 4. Any other semantic check that is required for full validation. + // + // It should convert untyped proto into typed proto and return binary encoding of it in Object.data. + // + // On validation failure, it should return a validation error with text. + rpc ValidateAndTransform(ValidationRequest) returns (ValidationResponse) { + option (google.api.http) = { + post: "/resources/v1:validate" + body: "*" + }; + }; +}; + +// Validation repesents individual change to be validated. +message Validation { + oneof validation_union { + // This object should be validated and converted to binary encoded proto. + ConfigObject object = 1; + + // If this object was deleted. + // In this case Validator should check referential integrity. + // Only metadata about the object being deleted is sent. + Meta deleted = 2; + } +} + +message ValidationRequest { + // Supports multiple ordered changes to be validated together. + // When a large config is pushed into Galley, batching + // validation requests is an optimization. + repeated Validation validations = 1; + // Objects should be validated against this revision of the repository. + // If the validator or the object is agnostic to repository versions, this can be ignored. + // This is useful for referential integrity checking. + int64 validation_revision = 3; +} + +message ValidationResponse { + // result of the operation + // if status == INVALID_ARGUMENT + // check errors for details. + google.rpc.Status status = 1; + + // state of the object after the change. + ConfigObject object = 2; + + // errors if status = INVALID_ARGUMENT + repeated ValidationError validation_errors = 3; +} + + diff --git a/galley/v1/watcher.proto b/galley/v1/watcher.proto index 28a1f58a45..e589b903ff 100644 --- a/galley/v1/watcher.proto +++ b/galley/v1/watcher.proto @@ -90,7 +90,6 @@ message WatchProgress { } -// The client should WatchResponse message WatchResponse { // watch_id is the ID of the watcher that corresponds to the response. // watch_id does not apply to the unsolicited "Progress" message. @@ -137,6 +136,6 @@ message Event { // its modification revision set to the revision of deletion. ConfigObject kv = 2; - // prev_kv holds the key-value pair before the event happens. + // prev_kv holds the key-value pair before the event happened. ConfigObject prev_kv = 3; }