From 4ce09ad811554d3fb4cb68a18360c485d00cbd76 Mon Sep 17 00:00:00 2001 From: Christopher Burnett Date: Mon, 19 Sep 2016 16:39:08 -0400 Subject: [PATCH] Adding Envoy gRPC bridge filter example (#78) --- .../front-proxy}/Dockerfile-envoy-image | 0 .../front-proxy}/Dockerfile-frontenvoy | 0 .../front-proxy}/Dockerfile-service | 0 {example => examples/front-proxy}/README.md | 0 .../front-proxy}/docker-compose.yml | 0 .../front-proxy}/front-envoy.json | 0 .../front-proxy}/service-envoy.json | 0 {example => examples/front-proxy}/service.py | 0 .../front-proxy}/start_service.sh | 0 examples/grpc-bridge/.gitignore | 2 + examples/grpc-bridge/Dockerfile-grpc | 7 + examples/grpc-bridge/Dockerfile-python | 8 + examples/grpc-bridge/README.md | 31 ++ examples/grpc-bridge/bin/.gitkeep | 0 examples/grpc-bridge/client/client.py | 78 +++++ examples/grpc-bridge/client/kv_pb2.py | 299 ++++++++++++++++++ examples/grpc-bridge/client/requirements.txt | 2 + .../grpc-bridge/config/s2s-grpc-envoy.json | 62 ++++ .../grpc-bridge/config/s2s-python-envoy.json | 74 +++++ examples/grpc-bridge/docker-compose.yml | 20 ++ examples/grpc-bridge/script/bootstrap | 10 + examples/grpc-bridge/script/build | 12 + examples/grpc-bridge/script/grpc_start | 4 + .../grpc-bridge/service/envoy-gen/kv_pb2.py | 299 ++++++++++++++++++ examples/grpc-bridge/service/gen/kv.pb.go | 203 ++++++++++++ examples/grpc-bridge/service/gen/kv_pb2.py | 299 ++++++++++++++++++ examples/grpc-bridge/service/main.go | 64 ++++ examples/grpc-bridge/service/protos/kv.proto | 25 ++ examples/grpc-bridge/service/script/gen | 18 ++ examples/grpc-bridge/service/script/start.sh | 3 + 30 files changed, 1520 insertions(+) rename {example => examples/front-proxy}/Dockerfile-envoy-image (100%) rename {example => examples/front-proxy}/Dockerfile-frontenvoy (100%) rename {example => examples/front-proxy}/Dockerfile-service (100%) rename {example => examples/front-proxy}/README.md (100%) rename {example => examples/front-proxy}/docker-compose.yml (100%) rename {example => examples/front-proxy}/front-envoy.json (100%) rename {example => examples/front-proxy}/service-envoy.json (100%) rename {example => examples/front-proxy}/service.py (100%) rename {example => examples/front-proxy}/start_service.sh (100%) create mode 100644 examples/grpc-bridge/.gitignore create mode 100644 examples/grpc-bridge/Dockerfile-grpc create mode 100644 examples/grpc-bridge/Dockerfile-python create mode 100644 examples/grpc-bridge/README.md create mode 100644 examples/grpc-bridge/bin/.gitkeep create mode 100644 examples/grpc-bridge/client/client.py create mode 100644 examples/grpc-bridge/client/kv_pb2.py create mode 100644 examples/grpc-bridge/client/requirements.txt create mode 100644 examples/grpc-bridge/config/s2s-grpc-envoy.json create mode 100644 examples/grpc-bridge/config/s2s-python-envoy.json create mode 100644 examples/grpc-bridge/docker-compose.yml create mode 100755 examples/grpc-bridge/script/bootstrap create mode 100755 examples/grpc-bridge/script/build create mode 100755 examples/grpc-bridge/script/grpc_start create mode 100644 examples/grpc-bridge/service/envoy-gen/kv_pb2.py create mode 100644 examples/grpc-bridge/service/gen/kv.pb.go create mode 100644 examples/grpc-bridge/service/gen/kv_pb2.py create mode 100644 examples/grpc-bridge/service/main.go create mode 100644 examples/grpc-bridge/service/protos/kv.proto create mode 100755 examples/grpc-bridge/service/script/gen create mode 100644 examples/grpc-bridge/service/script/start.sh diff --git a/example/Dockerfile-envoy-image b/examples/front-proxy/Dockerfile-envoy-image similarity index 100% rename from example/Dockerfile-envoy-image rename to examples/front-proxy/Dockerfile-envoy-image diff --git a/example/Dockerfile-frontenvoy b/examples/front-proxy/Dockerfile-frontenvoy similarity index 100% rename from example/Dockerfile-frontenvoy rename to examples/front-proxy/Dockerfile-frontenvoy diff --git a/example/Dockerfile-service b/examples/front-proxy/Dockerfile-service similarity index 100% rename from example/Dockerfile-service rename to examples/front-proxy/Dockerfile-service diff --git a/example/README.md b/examples/front-proxy/README.md similarity index 100% rename from example/README.md rename to examples/front-proxy/README.md diff --git a/example/docker-compose.yml b/examples/front-proxy/docker-compose.yml similarity index 100% rename from example/docker-compose.yml rename to examples/front-proxy/docker-compose.yml diff --git a/example/front-envoy.json b/examples/front-proxy/front-envoy.json similarity index 100% rename from example/front-envoy.json rename to examples/front-proxy/front-envoy.json diff --git a/example/service-envoy.json b/examples/front-proxy/service-envoy.json similarity index 100% rename from example/service-envoy.json rename to examples/front-proxy/service-envoy.json diff --git a/example/service.py b/examples/front-proxy/service.py similarity index 100% rename from example/service.py rename to examples/front-proxy/service.py diff --git a/example/start_service.sh b/examples/front-proxy/start_service.sh similarity index 100% rename from example/start_service.sh rename to examples/front-proxy/start_service.sh diff --git a/examples/grpc-bridge/.gitignore b/examples/grpc-bridge/.gitignore new file mode 100644 index 000000000000..0f1f1dfc6f0d --- /dev/null +++ b/examples/grpc-bridge/.gitignore @@ -0,0 +1,2 @@ +bin/service +.idea diff --git a/examples/grpc-bridge/Dockerfile-grpc b/examples/grpc-bridge/Dockerfile-grpc new file mode 100644 index 000000000000..b821a6ebac1b --- /dev/null +++ b/examples/grpc-bridge/Dockerfile-grpc @@ -0,0 +1,7 @@ +FROM lyft/envoy:latest + +RUN mkdir /var/log/envoy/ +COPY ./bin/service /usr/local/bin/srv +COPY ./script/grpc_start /etc/grpc_start +CMD /etc/grpc_start + diff --git a/examples/grpc-bridge/Dockerfile-python b/examples/grpc-bridge/Dockerfile-python new file mode 100644 index 000000000000..a60ad8ba9c82 --- /dev/null +++ b/examples/grpc-bridge/Dockerfile-python @@ -0,0 +1,8 @@ +FROM lyft/envoy:latest + +RUN apt-get install -y python-dev +RUN pip install grpcio requests +ADD ./client /client +RUN chmod a+x /client/client.py +RUN mkdir /var/log/envoy/ +CMD /usr/local/bin/envoy -c /etc/s2s-python-envoy.json diff --git a/examples/grpc-bridge/README.md b/examples/grpc-bridge/README.md new file mode 100644 index 000000000000..680328f2edd2 --- /dev/null +++ b/examples/grpc-bridge/README.md @@ -0,0 +1,31 @@ +# envoy-grpc + +This is an example usage of the Envoy [gRPC bridge filter](https://lyft.github.io/envoy/docs/configuration/http_filters/grpc_http1_bridge_filter.html#config-http-filters-grpc-bridge). Included is a gRPC in memory Key/Value store with a Python HTTP client. The Python client makes HTTP/1 requests through the Envoy sidecar process which are upgraded into HTTP/2 gRPC requests. Response trailers are then buffered and sent back to the client as a HTTP/1 header payload. + +## Building the Go service + +```bash +script/bootstrap +script/build +``` + +## Docker compose + +To run the docker compose file, and set up both the Python and the gRPC containers +run: + +```bash +docker-compose up --build +``` + +## Sending requests to the Key/Value store + +```bash +# set a key +docker-compose exec python /client/client.py set foo bar +=> setf foo to bar + +# get a key +docker-compose exec python /client/client.py get foo +=> bar +``` diff --git a/examples/grpc-bridge/bin/.gitkeep b/examples/grpc-bridge/bin/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/examples/grpc-bridge/client/client.py b/examples/grpc-bridge/client/client.py new file mode 100644 index 000000000000..052e532928c8 --- /dev/null +++ b/examples/grpc-bridge/client/client.py @@ -0,0 +1,78 @@ +#!/usr/bin/python + +import requests, sys +import kv_pb2 as kv +from struct import pack + +HOST = "http://localhost:9001" +HEADERS = {'content-type': 'application/grpc','Host':'grpc'} +USAGE = """ + +envoy-python-client usage: + ./client.py set - sets the and + ./client.py get - gets the value for + """ + +class KVClient(): + + def get(self, key): + r = kv.GetRequest(key=key) + + # Build the gRPC frame + data = r.SerializeToString() + data = pack('!cI', b'\0', len(data)) + data + + resp = requests.post(HOST + "/kv.KV/Get", data=data, headers=HEADERS) + + return kv.GetResponse().FromString(resp.content[5:]) + + + def set(self, key, value): + r = kv.SetRequest(key=key, value=value) + data = r.SerializeToString() + data = pack('!cI', b'\0', len(data)) + data + + return requests.post(HOST + "/kv.KV/Set", data=data, headers=HEADERS) + +def run(): + if len(sys.argv) == 1: + print(USAGE) + + sys.exit(0) + + cmd = sys.argv[1] + + client = KVClient() + + if cmd == "get": + # ensure a key was provided + if len(sys.argv) != 3: + print(USAGE) + sys.exit(1) + + # get the key to fetch + key = sys.argv[2] + + # send the request to the server + response = client.get(key) + + print(response.value) + sys.exit(0) + + elif cmd == "set": + # ensure a key and value were provided + if len(sys.argv) < 4: + print(USAGE) + sys.exit(1) + + # get the key and the full text of value + key = sys.argv[2] + value = " ".join(sys.argv[3:]) + + # send the request to the server + response = client.set(key, value) + + print("setf %s to %s" % (key, value)) + +if __name__ == '__main__': + run() diff --git a/examples/grpc-bridge/client/kv_pb2.py b/examples/grpc-bridge/client/kv_pb2.py new file mode 100644 index 000000000000..c644220be100 --- /dev/null +++ b/examples/grpc-bridge/client/kv_pb2.py @@ -0,0 +1,299 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: kv.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='kv.proto', + package='kv', + syntax='proto3', + serialized_pb=_b('\n\x08kv.proto\x12\x02kv\"\x19\n\nGetRequest\x12\x0b\n\x03key\x18\x01 \x01(\t\"\x1c\n\x0bGetResponse\x12\r\n\x05value\x18\x01 \x01(\t\"(\n\nSetRequest\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\x19\n\x0bSetResponse\x12\n\n\x02ok\x18\x01 \x01(\x08\x32T\n\x02KV\x12&\n\x03Get\x12\x0e.kv.GetRequest\x1a\x0f.kv.GetResponse\x12&\n\x03Set\x12\x0e.kv.SetRequest\x1a\x0f.kv.SetResponseb\x06proto3') +) +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + + + + +_GETREQUEST = _descriptor.Descriptor( + name='GetRequest', + full_name='kv.GetRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='kv.GetRequest.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=16, + serialized_end=41, +) + + +_GETRESPONSE = _descriptor.Descriptor( + name='GetResponse', + full_name='kv.GetResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='value', full_name='kv.GetResponse.value', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=43, + serialized_end=71, +) + + +_SETREQUEST = _descriptor.Descriptor( + name='SetRequest', + full_name='kv.SetRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='kv.SetRequest.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='value', full_name='kv.SetRequest.value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=73, + serialized_end=113, +) + + +_SETRESPONSE = _descriptor.Descriptor( + name='SetResponse', + full_name='kv.SetResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ok', full_name='kv.SetResponse.ok', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=115, + serialized_end=140, +) + +DESCRIPTOR.message_types_by_name['GetRequest'] = _GETREQUEST +DESCRIPTOR.message_types_by_name['GetResponse'] = _GETRESPONSE +DESCRIPTOR.message_types_by_name['SetRequest'] = _SETREQUEST +DESCRIPTOR.message_types_by_name['SetResponse'] = _SETRESPONSE + +GetRequest = _reflection.GeneratedProtocolMessageType('GetRequest', (_message.Message,), dict( + DESCRIPTOR = _GETREQUEST, + __module__ = 'kv_pb2' + # @@protoc_insertion_point(class_scope:kv.GetRequest) + )) +_sym_db.RegisterMessage(GetRequest) + +GetResponse = _reflection.GeneratedProtocolMessageType('GetResponse', (_message.Message,), dict( + DESCRIPTOR = _GETRESPONSE, + __module__ = 'kv_pb2' + # @@protoc_insertion_point(class_scope:kv.GetResponse) + )) +_sym_db.RegisterMessage(GetResponse) + +SetRequest = _reflection.GeneratedProtocolMessageType('SetRequest', (_message.Message,), dict( + DESCRIPTOR = _SETREQUEST, + __module__ = 'kv_pb2' + # @@protoc_insertion_point(class_scope:kv.SetRequest) + )) +_sym_db.RegisterMessage(SetRequest) + +SetResponse = _reflection.GeneratedProtocolMessageType('SetResponse', (_message.Message,), dict( + DESCRIPTOR = _SETRESPONSE, + __module__ = 'kv_pb2' + # @@protoc_insertion_point(class_scope:kv.SetResponse) + )) +_sym_db.RegisterMessage(SetResponse) + + +import grpc +from grpc.beta import implementations as beta_implementations +from grpc.beta import interfaces as beta_interfaces +from grpc.framework.common import cardinality +from grpc.framework.interfaces.face import utilities as face_utilities + + +class KVStub(object): + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.Get = channel.unary_unary( + '/kv.KV/Get', + request_serializer=GetRequest.SerializeToString, + response_deserializer=GetResponse.FromString, + ) + self.Set = channel.unary_unary( + '/kv.KV/Set', + request_serializer=SetRequest.SerializeToString, + response_deserializer=SetResponse.FromString, + ) + + +class KVServicer(object): + + def Get(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Set(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_KVServicer_to_server(servicer, server): + rpc_method_handlers = { + 'Get': grpc.unary_unary_rpc_method_handler( + servicer.Get, + request_deserializer=GetRequest.FromString, + response_serializer=GetResponse.SerializeToString, + ), + 'Set': grpc.unary_unary_rpc_method_handler( + servicer.Set, + request_deserializer=SetRequest.FromString, + response_serializer=SetResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'kv.KV', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + +class BetaKVServicer(object): + def Get(self, request, context): + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + def Set(self, request, context): + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + +class BetaKVStub(object): + def Get(self, request, timeout, metadata=None, with_call=False, protocol_options=None): + raise NotImplementedError() + Get.future = None + def Set(self, request, timeout, metadata=None, with_call=False, protocol_options=None): + raise NotImplementedError() + Set.future = None + + +def beta_create_KV_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None): + request_deserializers = { + ('kv.KV', 'Get'): GetRequest.FromString, + ('kv.KV', 'Set'): SetRequest.FromString, + } + response_serializers = { + ('kv.KV', 'Get'): GetResponse.SerializeToString, + ('kv.KV', 'Set'): SetResponse.SerializeToString, + } + method_implementations = { + ('kv.KV', 'Get'): face_utilities.unary_unary_inline(servicer.Get), + ('kv.KV', 'Set'): face_utilities.unary_unary_inline(servicer.Set), + } + server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout) + return beta_implementations.server(method_implementations, options=server_options) + + +def beta_create_KV_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None): + request_serializers = { + ('kv.KV', 'Get'): GetRequest.SerializeToString, + ('kv.KV', 'Set'): SetRequest.SerializeToString, + } + response_deserializers = { + ('kv.KV', 'Get'): GetResponse.FromString, + ('kv.KV', 'Set'): SetResponse.FromString, + } + cardinalities = { + 'Get': cardinality.Cardinality.UNARY_UNARY, + 'Set': cardinality.Cardinality.UNARY_UNARY, + } + stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size) + return beta_implementations.dynamic_stub(channel, 'kv.KV', cardinalities, options=stub_options) +# @@protoc_insertion_point(module_scope) diff --git a/examples/grpc-bridge/client/requirements.txt b/examples/grpc-bridge/client/requirements.txt new file mode 100644 index 000000000000..fd741921a101 --- /dev/null +++ b/examples/grpc-bridge/client/requirements.txt @@ -0,0 +1,2 @@ +requests==2.9.1 +grpcio diff --git a/examples/grpc-bridge/config/s2s-grpc-envoy.json b/examples/grpc-bridge/config/s2s-grpc-envoy.json new file mode 100644 index 000000000000..8397fd1aac63 --- /dev/null +++ b/examples/grpc-bridge/config/s2s-grpc-envoy.json @@ -0,0 +1,62 @@ +{ + "listeners": [ + { + "port": 9211, + "filters": [ + { + "type": "read", + "name": "http_connection_manager", + "config": { + "codec_type": "auto", + "stat_prefix": "ingress_http", + "route_config": { + "virtual_hosts": [ + { + "name": "local_service", + "domains": [ + "*" + ], + "routes": [ + { + "timeout_ms": 0, + "prefix": "/", + "content_type": "application/grpc", + "cluster": "local_service_grpc" + } + ] + } + ] + }, + "filters": [ + { + "type": "decoder", + "name": "router", + "config": {} + } + ] + } + } + ] + } + ], + "admin": { + "access_log_path": "/var/log/envoy/admin_access.log", + "port": 9901 + }, + "cluster_manager": { + "clusters": [ + { + "name": "local_service_grpc", + "connect_timeout_ms": 250, + "type": "static", + "lb_type": "round_robin", + "features": "http2", + "hosts": [ + { + "url": "tcp://127.0.0.1:8081" + } + ] + } + ] + } +} diff --git a/examples/grpc-bridge/config/s2s-python-envoy.json b/examples/grpc-bridge/config/s2s-python-envoy.json new file mode 100644 index 000000000000..02430e45866d --- /dev/null +++ b/examples/grpc-bridge/config/s2s-python-envoy.json @@ -0,0 +1,74 @@ +{ + "listeners": [ + { + "port": 9001, + "filters": [ + { + "type": "read", + "name": "http_connection_manager", + "config": { + "codec_type": "auto", + "add_user_agent": true, + "idle_timeout_s": 840, + "access_log": [ + { + "path": "/var/log/envoy/egress_http.log", + "format": "[%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH):256% %PROTOCOL%\" %RESPONSE_CODE% %FAILURE_REASON% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% \"%REQ(X-FORWARDED-FOR)%\" \"%REQ(USER-AGENT)%\" \"%REQ(X-REQUEST-ID)%\" \"%REQ(:AUTHORITY)%\" \"%UPSTREAM_HOST%\"\n" + } + ], + "stat_prefix": "egress_http", + "use_remote_address": true, + "route_config": { + "virtual_hosts": [ + { + "name": "grpc", + "domains": [ + "grpc" + ], + "routes": [ + { + "prefix": "/", + "cluster": "grpc" + } + ] + } + ] + }, + "filters": [ + { + "type": "both", + "name": "grpc_http1_bridge", + "config": {} + }, + { + "type": "decoder", + "name": "router", + "config": {} + } + ] + } + } + ] + } + ], + "admin": { + "access_log_path": "/var/log/envoy/admin_access.log", + "port": 9901 + }, + "cluster_manager": { + "clusters": [ + { + "name": "grpc", + "type": "logical_dns", + "lb_type": "round_robin", + "connect_timeout_ms": 250, + "features": "http2", + "hosts": [ + { + "url": "tcp://grpc:9211" + } + ] + } + ] + } +} diff --git a/examples/grpc-bridge/docker-compose.yml b/examples/grpc-bridge/docker-compose.yml new file mode 100644 index 000000000000..a787ac32d601 --- /dev/null +++ b/examples/grpc-bridge/docker-compose.yml @@ -0,0 +1,20 @@ +version: '2' +services: + + python: + build: + context: . + dockerfile: Dockerfile-python + volumes: + - ./config/s2s-python-envoy.json:/etc/s2s-python-envoy.json + expose: + - "9001" + + grpc: + build: + context: . + dockerfile: Dockerfile-grpc + volumes: + - ./config/s2s-grpc-envoy.json:/etc/s2s-grpc-envoy.json + expose: + - "9211" diff --git a/examples/grpc-bridge/script/bootstrap b/examples/grpc-bridge/script/bootstrap new file mode 100755 index 000000000000..3d8207cb3d68 --- /dev/null +++ b/examples/grpc-bridge/script/bootstrap @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -e + +cd $(dirname $0)/.. + +echo "fetching dependencies..." +go get golang.org/x/net/context +go get google.golang.org/grpc +echo "done" diff --git a/examples/grpc-bridge/script/build b/examples/grpc-bridge/script/build new file mode 100755 index 000000000000..d3ed6dda0575 --- /dev/null +++ b/examples/grpc-bridge/script/build @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e + +cd $(dirname $0)/.. + +export GOOS=linux +export GOARCH=amd64 +export CGO_ENABLED=0 + +go build -o ./bin/service ./service + diff --git a/examples/grpc-bridge/script/grpc_start b/examples/grpc-bridge/script/grpc_start new file mode 100755 index 000000000000..24da4de5a8cf --- /dev/null +++ b/examples/grpc-bridge/script/grpc_start @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +srv & +/usr/local/bin/envoy -c /etc/s2s-grpc-envoy.json diff --git a/examples/grpc-bridge/service/envoy-gen/kv_pb2.py b/examples/grpc-bridge/service/envoy-gen/kv_pb2.py new file mode 100644 index 000000000000..c644220be100 --- /dev/null +++ b/examples/grpc-bridge/service/envoy-gen/kv_pb2.py @@ -0,0 +1,299 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: kv.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='kv.proto', + package='kv', + syntax='proto3', + serialized_pb=_b('\n\x08kv.proto\x12\x02kv\"\x19\n\nGetRequest\x12\x0b\n\x03key\x18\x01 \x01(\t\"\x1c\n\x0bGetResponse\x12\r\n\x05value\x18\x01 \x01(\t\"(\n\nSetRequest\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\x19\n\x0bSetResponse\x12\n\n\x02ok\x18\x01 \x01(\x08\x32T\n\x02KV\x12&\n\x03Get\x12\x0e.kv.GetRequest\x1a\x0f.kv.GetResponse\x12&\n\x03Set\x12\x0e.kv.SetRequest\x1a\x0f.kv.SetResponseb\x06proto3') +) +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + + + + +_GETREQUEST = _descriptor.Descriptor( + name='GetRequest', + full_name='kv.GetRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='kv.GetRequest.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=16, + serialized_end=41, +) + + +_GETRESPONSE = _descriptor.Descriptor( + name='GetResponse', + full_name='kv.GetResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='value', full_name='kv.GetResponse.value', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=43, + serialized_end=71, +) + + +_SETREQUEST = _descriptor.Descriptor( + name='SetRequest', + full_name='kv.SetRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='kv.SetRequest.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='value', full_name='kv.SetRequest.value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=73, + serialized_end=113, +) + + +_SETRESPONSE = _descriptor.Descriptor( + name='SetResponse', + full_name='kv.SetResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ok', full_name='kv.SetResponse.ok', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=115, + serialized_end=140, +) + +DESCRIPTOR.message_types_by_name['GetRequest'] = _GETREQUEST +DESCRIPTOR.message_types_by_name['GetResponse'] = _GETRESPONSE +DESCRIPTOR.message_types_by_name['SetRequest'] = _SETREQUEST +DESCRIPTOR.message_types_by_name['SetResponse'] = _SETRESPONSE + +GetRequest = _reflection.GeneratedProtocolMessageType('GetRequest', (_message.Message,), dict( + DESCRIPTOR = _GETREQUEST, + __module__ = 'kv_pb2' + # @@protoc_insertion_point(class_scope:kv.GetRequest) + )) +_sym_db.RegisterMessage(GetRequest) + +GetResponse = _reflection.GeneratedProtocolMessageType('GetResponse', (_message.Message,), dict( + DESCRIPTOR = _GETRESPONSE, + __module__ = 'kv_pb2' + # @@protoc_insertion_point(class_scope:kv.GetResponse) + )) +_sym_db.RegisterMessage(GetResponse) + +SetRequest = _reflection.GeneratedProtocolMessageType('SetRequest', (_message.Message,), dict( + DESCRIPTOR = _SETREQUEST, + __module__ = 'kv_pb2' + # @@protoc_insertion_point(class_scope:kv.SetRequest) + )) +_sym_db.RegisterMessage(SetRequest) + +SetResponse = _reflection.GeneratedProtocolMessageType('SetResponse', (_message.Message,), dict( + DESCRIPTOR = _SETRESPONSE, + __module__ = 'kv_pb2' + # @@protoc_insertion_point(class_scope:kv.SetResponse) + )) +_sym_db.RegisterMessage(SetResponse) + + +import grpc +from grpc.beta import implementations as beta_implementations +from grpc.beta import interfaces as beta_interfaces +from grpc.framework.common import cardinality +from grpc.framework.interfaces.face import utilities as face_utilities + + +class KVStub(object): + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.Get = channel.unary_unary( + '/kv.KV/Get', + request_serializer=GetRequest.SerializeToString, + response_deserializer=GetResponse.FromString, + ) + self.Set = channel.unary_unary( + '/kv.KV/Set', + request_serializer=SetRequest.SerializeToString, + response_deserializer=SetResponse.FromString, + ) + + +class KVServicer(object): + + def Get(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Set(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_KVServicer_to_server(servicer, server): + rpc_method_handlers = { + 'Get': grpc.unary_unary_rpc_method_handler( + servicer.Get, + request_deserializer=GetRequest.FromString, + response_serializer=GetResponse.SerializeToString, + ), + 'Set': grpc.unary_unary_rpc_method_handler( + servicer.Set, + request_deserializer=SetRequest.FromString, + response_serializer=SetResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'kv.KV', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + +class BetaKVServicer(object): + def Get(self, request, context): + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + def Set(self, request, context): + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + +class BetaKVStub(object): + def Get(self, request, timeout, metadata=None, with_call=False, protocol_options=None): + raise NotImplementedError() + Get.future = None + def Set(self, request, timeout, metadata=None, with_call=False, protocol_options=None): + raise NotImplementedError() + Set.future = None + + +def beta_create_KV_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None): + request_deserializers = { + ('kv.KV', 'Get'): GetRequest.FromString, + ('kv.KV', 'Set'): SetRequest.FromString, + } + response_serializers = { + ('kv.KV', 'Get'): GetResponse.SerializeToString, + ('kv.KV', 'Set'): SetResponse.SerializeToString, + } + method_implementations = { + ('kv.KV', 'Get'): face_utilities.unary_unary_inline(servicer.Get), + ('kv.KV', 'Set'): face_utilities.unary_unary_inline(servicer.Set), + } + server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout) + return beta_implementations.server(method_implementations, options=server_options) + + +def beta_create_KV_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None): + request_serializers = { + ('kv.KV', 'Get'): GetRequest.SerializeToString, + ('kv.KV', 'Set'): SetRequest.SerializeToString, + } + response_deserializers = { + ('kv.KV', 'Get'): GetResponse.FromString, + ('kv.KV', 'Set'): SetResponse.FromString, + } + cardinalities = { + 'Get': cardinality.Cardinality.UNARY_UNARY, + 'Set': cardinality.Cardinality.UNARY_UNARY, + } + stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size) + return beta_implementations.dynamic_stub(channel, 'kv.KV', cardinalities, options=stub_options) +# @@protoc_insertion_point(module_scope) diff --git a/examples/grpc-bridge/service/gen/kv.pb.go b/examples/grpc-bridge/service/gen/kv.pb.go new file mode 100644 index 000000000000..6d7f6afa542e --- /dev/null +++ b/examples/grpc-bridge/service/gen/kv.pb.go @@ -0,0 +1,203 @@ +// Code generated by protoc-gen-go. +// source: kv.proto +// DO NOT EDIT! + +/* +Package kv is a generated protocol buffer package. + +It is generated from these files: + kv.proto + +It has these top-level messages: + GetRequest + GetResponse + SetRequest + SetResponse +*/ +package kv + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type GetRequest struct { + Key string `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` +} + +func (m *GetRequest) Reset() { *m = GetRequest{} } +func (m *GetRequest) String() string { return proto.CompactTextString(m) } +func (*GetRequest) ProtoMessage() {} +func (*GetRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +type GetResponse struct { + Value string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"` +} + +func (m *GetResponse) Reset() { *m = GetResponse{} } +func (m *GetResponse) String() string { return proto.CompactTextString(m) } +func (*GetResponse) ProtoMessage() {} +func (*GetResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +type SetRequest struct { + Key string `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` + Value string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` +} + +func (m *SetRequest) Reset() { *m = SetRequest{} } +func (m *SetRequest) String() string { return proto.CompactTextString(m) } +func (*SetRequest) ProtoMessage() {} +func (*SetRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +type SetResponse struct { + Ok bool `protobuf:"varint,1,opt,name=ok" json:"ok,omitempty"` +} + +func (m *SetResponse) Reset() { *m = SetResponse{} } +func (m *SetResponse) String() string { return proto.CompactTextString(m) } +func (*SetResponse) ProtoMessage() {} +func (*SetResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func init() { + proto.RegisterType((*GetRequest)(nil), "kv.GetRequest") + proto.RegisterType((*GetResponse)(nil), "kv.GetResponse") + proto.RegisterType((*SetRequest)(nil), "kv.SetRequest") + proto.RegisterType((*SetResponse)(nil), "kv.SetResponse") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion3 + +// Client API for KV service + +type KVClient interface { + Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) + Set(ctx context.Context, in *SetRequest, opts ...grpc.CallOption) (*SetResponse, error) +} + +type kVClient struct { + cc *grpc.ClientConn +} + +func NewKVClient(cc *grpc.ClientConn) KVClient { + return &kVClient{cc} +} + +func (c *kVClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) { + out := new(GetResponse) + err := grpc.Invoke(ctx, "/kv.KV/Get", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *kVClient) Set(ctx context.Context, in *SetRequest, opts ...grpc.CallOption) (*SetResponse, error) { + out := new(SetResponse) + err := grpc.Invoke(ctx, "/kv.KV/Set", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for KV service + +type KVServer interface { + Get(context.Context, *GetRequest) (*GetResponse, error) + Set(context.Context, *SetRequest) (*SetResponse, error) +} + +func RegisterKVServer(s *grpc.Server, srv KVServer) { + s.RegisterService(&_KV_serviceDesc, srv) +} + +func _KV_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KVServer).Get(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/kv.KV/Get", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KVServer).Get(ctx, req.(*GetRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _KV_Set_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KVServer).Set(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/kv.KV/Set", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KVServer).Set(ctx, req.(*SetRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _KV_serviceDesc = grpc.ServiceDesc{ + ServiceName: "kv.KV", + HandlerType: (*KVServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Get", + Handler: _KV_Get_Handler, + }, + { + MethodName: "Set", + Handler: _KV_Set_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: fileDescriptor0, +} + +func init() { proto.RegisterFile("kv.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 163 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0xc8, 0x2e, 0xd3, 0x2b, + 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0xca, 0x2e, 0x53, 0x92, 0xe3, 0xe2, 0x72, 0x4f, 0x2d, 0x09, + 0x4a, 0x2d, 0x2c, 0x4d, 0x2d, 0x2e, 0x11, 0x12, 0xe0, 0x62, 0xce, 0x4e, 0xad, 0x94, 0x60, 0x54, + 0x60, 0xd4, 0xe0, 0x0c, 0x02, 0x31, 0x95, 0x94, 0xb9, 0xb8, 0xc1, 0xf2, 0xc5, 0x05, 0xf9, 0x79, + 0xc5, 0xa9, 0x42, 0x22, 0x5c, 0xac, 0x65, 0x89, 0x39, 0xa5, 0xa9, 0x50, 0x25, 0x10, 0x8e, 0x92, + 0x09, 0x17, 0x57, 0x30, 0x1e, 0x43, 0x10, 0xba, 0x98, 0x90, 0x75, 0xc9, 0x72, 0x71, 0x07, 0x23, + 0x19, 0xcd, 0xc7, 0xc5, 0x94, 0x9f, 0x0d, 0xd6, 0xc5, 0x11, 0x04, 0x64, 0x19, 0x85, 0x70, 0x31, + 0x79, 0x87, 0x09, 0xa9, 0x71, 0x31, 0x03, 0xed, 0x17, 0xe2, 0xd3, 0x03, 0xba, 0x1a, 0xe1, 0x50, + 0x29, 0x7e, 0x38, 0x1f, 0xaa, 0x1b, 0xa8, 0x2e, 0x18, 0xa6, 0x2e, 0x18, 0x4d, 0x1d, 0x92, 0x2d, + 0x49, 0x6c, 0x60, 0xaf, 0x1b, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x4a, 0x17, 0xca, 0xf0, 0x06, + 0x01, 0x00, 0x00, +} diff --git a/examples/grpc-bridge/service/gen/kv_pb2.py b/examples/grpc-bridge/service/gen/kv_pb2.py new file mode 100644 index 000000000000..c644220be100 --- /dev/null +++ b/examples/grpc-bridge/service/gen/kv_pb2.py @@ -0,0 +1,299 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: kv.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='kv.proto', + package='kv', + syntax='proto3', + serialized_pb=_b('\n\x08kv.proto\x12\x02kv\"\x19\n\nGetRequest\x12\x0b\n\x03key\x18\x01 \x01(\t\"\x1c\n\x0bGetResponse\x12\r\n\x05value\x18\x01 \x01(\t\"(\n\nSetRequest\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\x19\n\x0bSetResponse\x12\n\n\x02ok\x18\x01 \x01(\x08\x32T\n\x02KV\x12&\n\x03Get\x12\x0e.kv.GetRequest\x1a\x0f.kv.GetResponse\x12&\n\x03Set\x12\x0e.kv.SetRequest\x1a\x0f.kv.SetResponseb\x06proto3') +) +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + + + + +_GETREQUEST = _descriptor.Descriptor( + name='GetRequest', + full_name='kv.GetRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='kv.GetRequest.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=16, + serialized_end=41, +) + + +_GETRESPONSE = _descriptor.Descriptor( + name='GetResponse', + full_name='kv.GetResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='value', full_name='kv.GetResponse.value', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=43, + serialized_end=71, +) + + +_SETREQUEST = _descriptor.Descriptor( + name='SetRequest', + full_name='kv.SetRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='kv.SetRequest.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='value', full_name='kv.SetRequest.value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=73, + serialized_end=113, +) + + +_SETRESPONSE = _descriptor.Descriptor( + name='SetResponse', + full_name='kv.SetResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ok', full_name='kv.SetResponse.ok', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=115, + serialized_end=140, +) + +DESCRIPTOR.message_types_by_name['GetRequest'] = _GETREQUEST +DESCRIPTOR.message_types_by_name['GetResponse'] = _GETRESPONSE +DESCRIPTOR.message_types_by_name['SetRequest'] = _SETREQUEST +DESCRIPTOR.message_types_by_name['SetResponse'] = _SETRESPONSE + +GetRequest = _reflection.GeneratedProtocolMessageType('GetRequest', (_message.Message,), dict( + DESCRIPTOR = _GETREQUEST, + __module__ = 'kv_pb2' + # @@protoc_insertion_point(class_scope:kv.GetRequest) + )) +_sym_db.RegisterMessage(GetRequest) + +GetResponse = _reflection.GeneratedProtocolMessageType('GetResponse', (_message.Message,), dict( + DESCRIPTOR = _GETRESPONSE, + __module__ = 'kv_pb2' + # @@protoc_insertion_point(class_scope:kv.GetResponse) + )) +_sym_db.RegisterMessage(GetResponse) + +SetRequest = _reflection.GeneratedProtocolMessageType('SetRequest', (_message.Message,), dict( + DESCRIPTOR = _SETREQUEST, + __module__ = 'kv_pb2' + # @@protoc_insertion_point(class_scope:kv.SetRequest) + )) +_sym_db.RegisterMessage(SetRequest) + +SetResponse = _reflection.GeneratedProtocolMessageType('SetResponse', (_message.Message,), dict( + DESCRIPTOR = _SETRESPONSE, + __module__ = 'kv_pb2' + # @@protoc_insertion_point(class_scope:kv.SetResponse) + )) +_sym_db.RegisterMessage(SetResponse) + + +import grpc +from grpc.beta import implementations as beta_implementations +from grpc.beta import interfaces as beta_interfaces +from grpc.framework.common import cardinality +from grpc.framework.interfaces.face import utilities as face_utilities + + +class KVStub(object): + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.Get = channel.unary_unary( + '/kv.KV/Get', + request_serializer=GetRequest.SerializeToString, + response_deserializer=GetResponse.FromString, + ) + self.Set = channel.unary_unary( + '/kv.KV/Set', + request_serializer=SetRequest.SerializeToString, + response_deserializer=SetResponse.FromString, + ) + + +class KVServicer(object): + + def Get(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Set(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_KVServicer_to_server(servicer, server): + rpc_method_handlers = { + 'Get': grpc.unary_unary_rpc_method_handler( + servicer.Get, + request_deserializer=GetRequest.FromString, + response_serializer=GetResponse.SerializeToString, + ), + 'Set': grpc.unary_unary_rpc_method_handler( + servicer.Set, + request_deserializer=SetRequest.FromString, + response_serializer=SetResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'kv.KV', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + +class BetaKVServicer(object): + def Get(self, request, context): + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + def Set(self, request, context): + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + +class BetaKVStub(object): + def Get(self, request, timeout, metadata=None, with_call=False, protocol_options=None): + raise NotImplementedError() + Get.future = None + def Set(self, request, timeout, metadata=None, with_call=False, protocol_options=None): + raise NotImplementedError() + Set.future = None + + +def beta_create_KV_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None): + request_deserializers = { + ('kv.KV', 'Get'): GetRequest.FromString, + ('kv.KV', 'Set'): SetRequest.FromString, + } + response_serializers = { + ('kv.KV', 'Get'): GetResponse.SerializeToString, + ('kv.KV', 'Set'): SetResponse.SerializeToString, + } + method_implementations = { + ('kv.KV', 'Get'): face_utilities.unary_unary_inline(servicer.Get), + ('kv.KV', 'Set'): face_utilities.unary_unary_inline(servicer.Set), + } + server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout) + return beta_implementations.server(method_implementations, options=server_options) + + +def beta_create_KV_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None): + request_serializers = { + ('kv.KV', 'Get'): GetRequest.SerializeToString, + ('kv.KV', 'Set'): SetRequest.SerializeToString, + } + response_deserializers = { + ('kv.KV', 'Get'): GetResponse.FromString, + ('kv.KV', 'Set'): SetResponse.FromString, + } + cardinalities = { + 'Get': cardinality.Cardinality.UNARY_UNARY, + 'Set': cardinality.Cardinality.UNARY_UNARY, + } + stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size) + return beta_implementations.dynamic_stub(channel, 'kv.KV', cardinalities, options=stub_options) +# @@protoc_insertion_point(module_scope) diff --git a/examples/grpc-bridge/service/main.go b/examples/grpc-bridge/service/main.go new file mode 100644 index 000000000000..5e9674cbe53e --- /dev/null +++ b/examples/grpc-bridge/service/main.go @@ -0,0 +1,64 @@ +package main + +import ( + "flag" + "fmt" + "log" + "net" + + "sync" + + "github.com/lyft/envoy/examples/grpc-bridge/service/gen" + "golang.org/x/net/context" + "google.golang.org/grpc" +) + +type KV struct { + sync.Mutex + store map[string]string +} + +func (k *KV) Get(ctx context.Context, in *kv.GetRequest) (*kv.GetResponse, error) { + log.Printf("get: %s", in.Key) + resp := new(kv.GetResponse) + if val, ok := k.store[in.Key]; ok { + resp.Value = val + } + + return resp, nil +} + +func (k *KV) Set(ctx context.Context, in *kv.SetRequest) (*kv.SetResponse, error) { + log.Printf("set: %s = %s", in.Key, in.Value) + k.Lock() + defer k.Unlock() + + k.store[in.Key] = in.Value + + return &kv.SetResponse{true}, nil +} + +func NewKVStore() (kv *KV) { + kv = &KV{ + store: make(map[string]string), + } + + return +} + +func main() { + port := flag.Int("port", 8081, "grpc port") + + flag.Parse() + + lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port)) + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + gs := grpc.NewServer() + kv.RegisterKVServer(gs, NewKVStore()) + + log.Printf("starting grpc on :%d\n", *port) + + gs.Serve(lis) +} diff --git a/examples/grpc-bridge/service/protos/kv.proto b/examples/grpc-bridge/service/protos/kv.proto new file mode 100644 index 000000000000..774f75683c89 --- /dev/null +++ b/examples/grpc-bridge/service/protos/kv.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; + +package kv; + +message GetRequest { + string key = 1; +} + +message GetResponse { + string value = 1; +} + +message SetRequest { + string key = 1; + string value = 2; +} + +message SetResponse { + bool ok = 1; +} + +service KV { + rpc Get(GetRequest) returns (GetResponse); + rpc Set(SetRequest) returns (SetResponse); +} \ No newline at end of file diff --git a/examples/grpc-bridge/service/script/gen b/examples/grpc-bridge/service/script/gen new file mode 100755 index 000000000000..5813e58d2055 --- /dev/null +++ b/examples/grpc-bridge/service/script/gen @@ -0,0 +1,18 @@ +#!/bin/bash + +set -e + +cd $(dirname $0)/.. + +rm -rf generated/* + +# generate the protobufs +protoc --go_out=plugins=grpc:./gen \ + -I./protos ./protos/kv.proto + +python -m grpc.tools.protoc \ + -I./protos \ + --python_out=./gen \ + --grpc_python_out=./gen ./protos/kv.proto + +cp ./gen/kv_pb2.py ../client/ diff --git a/examples/grpc-bridge/service/script/start.sh b/examples/grpc-bridge/service/script/start.sh new file mode 100644 index 000000000000..1a57f89f1836 --- /dev/null +++ b/examples/grpc-bridge/service/script/start.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +srv