diff --git a/endpoints/getting-started-grpc/Dockerfile b/endpoints/getting-started-grpc/Dockerfile new file mode 100644 index 00000000000..facd78e7d43 --- /dev/null +++ b/endpoints/getting-started-grpc/Dockerfile @@ -0,0 +1,21 @@ +# The Google Cloud Platform Python runtime is based on Debian Jessie +# You can read more about the runtime at: +# https://github.com/GoogleCloudPlatform/python-runtime +FROM gcr.io/google_appengine/python + +# Create a virtualenv for dependencies. This isolates these packages from +# system-level packages. +RUN virtualenv /env + +# Setting these environment variables are the same as running +# source /env/bin/activate. +ENV VIRTUAL_ENV -p python3.5 /env +ENV PATH /env/bin:$PATH + +COPY requirements.txt /app/ +RUN pip install --requirement /app/requirements.txt +COPY . /app/ + +ENTRYPOINT [] + +CMD ["python", "/app/greeter_server.py"] diff --git a/endpoints/getting-started-grpc/README.md b/endpoints/getting-started-grpc/README.md new file mode 100644 index 00000000000..3025af616d8 --- /dev/null +++ b/endpoints/getting-started-grpc/README.md @@ -0,0 +1,178 @@ +# Endpoints Getting Started with gRPC & Python Quickstart + +It is assumed that you have a working Python environment and a Google +Cloud account and [SDK](https://cloud.google.com/sdk/) configured. + +1. Install dependencies using virtualenv: + + ```bash + virtualenv -p python3 env + source env/bin/activate + pip install -r requirements.txt + ``` + +1. Test running the code, optional: + + ```bash + # Run the server: + python greeter_server.py + + # Open another command line tab and enter the virtual environment: + source env/bin/activate + + # In the new command line tab, run the client: + python greeter_client.py + ``` + +1. The gRPC Services have already been generated. If you change the proto, or + just wish to regenerate these files, run: + + ```bash + python -m grpc_tools.protoc -I protos --python_out=. --grpc_python_out=. protos/helloworld.proto + ``` + +1. Generate the `out.pb` from the proto file: + + ```bash + python -m grpc_tools.protoc --include_imports --include_source_info -I protos protos/helloworld.proto --descriptor_set_out out.pb + ``` + +1. Edit, `api_config.yaml`. Replace `MY_PROJECT_ID` with your project id. + +1. Deploy your service config to Service Management: + + ```bash + gcloud service-management deploy out.pb api_config.yaml + # The Config ID should be printed out, looks like: 2017-02-01r0, remember this + + # Set your project ID as a variable to make commands easier: + GCLOUD_PROJECT= + + # Print out your Config ID again, in case you missed it: + gcloud service-management configs list --service hellogrpc.endpoints.${GCLOUD_PROJECT}.cloud.goog + ``` + +1. Also get an API key from the Console's API Manager for use in the + client later. (https://console.cloud.google.com/apis/credentials) + +1. Enable the Cloud Build API: + + ```bash + gcloud service-management enable cloudbuild.googleapis.com + ``` + +1. Build a docker image for your gRPC server, and store it in your Registry: + + ```bash + gcloud container builds submit --tag gcr.io/${GCLOUD_PROJECT}/python-grpc-hello:1.0 . + ``` + +1. Either deploy to GCE (below) or GKE (further down). + +### GCE + +1. Enable the Compute Engine API: + + ```bash + gcloud service-management enable compute-component.googleapis.com + ``` + +1. Create your instance and ssh in: + + ```bash + gcloud compute instances create grpc-host --image-family gci-stable --image-project google-containers --tags=http-server + gcloud compute ssh grpc-host + ``` + +1. Set some variables to make commands easier: + + ```bash + GCLOUD_PROJECT=$(curl -s "http://metadata.google.internal/computeMetadata/v1/project/project-id" -H "Metadata-Flavor: Google") + SERVICE_NAME=hellogrpc.endpoints.${GCLOUD_PROJECT}.cloud.goog + SERVICE_CONFIG_ID= + ``` + +1. Pull your credentials to access Container Registry, and run your gRPC server + container: + + ```bash + /usr/share/google/dockercfg_update.sh + docker run -d --name=grpc-hello gcr.io/${GCLOUD_PROJECT}/python-grpc-hello:1.0 + ``` + +1. Run the Endpoints proxy: + + ```bash + docker run --detach --name=esp \ + -p 80:9000 \ + --link=grpc-hello:grpc-hello \ + gcr.io/endpoints-release/endpoints-runtime:1 \ + -s ${SERVICE_NAME} \ + -v ${SERVICE_CONFIG_ID} \ + -P 9000 \ + -a grpc://grpc-hello:50051 + ``` + +1. Back on your local machine, get the external IP of your GCE instance: + + ```bash + gcloud compute instances list + ``` + +1. Run the client: + + ```bash + python greeter_client.py --host=:80 --api_key= + ``` + +1. Cleanup: + + ```bash + gcloud compute instances delete grpc-host + ``` + +### GKE + +1. Create a cluster. You can specify a different zone than us-central1-a if you + want: + + ```bash + gcloud container clusters create my-cluster --zone=us-central1-a + ``` + +1. Edit `container-engine.yaml`. Replace `SERVICE_NAME`, `SERVICE_CONFIG_ID`, + and `GCLOUD_PROJECT` with your values: + + `SERVICE_NAME` is equal to hellogrpc.endpoints.GCLOUD_PROJECT.cloud.goog, + replacing GCLOUD_PROJECT with your project ID. + + `SERVICE_CONFIG_ID` can be found by running the following command, replacing + GCLOUD_PROJECT with your project ID. + + ```bash + gcloud service-management configs list --service hellogrpc.endpoints.GCLOUD_PROJECT.cloud.goog + ``` + +1. Deploy to GKE: + + ```bash + kubectl create -f ./container-engine.yaml + ``` + +1. Get IP of load balancer, run until you see an External IP: + + ```bash + kubectl get svc grpc-hello + ``` + +1. Run the client: + + ```bash + python greeter_client.py --host=:80 --api_key= + ``` + +1. Cleanup: + + ```bash + gcloud container clusters delete my-cluster --zone=us-central1-a + ``` diff --git a/endpoints/getting-started-grpc/api_config.yaml b/endpoints/getting-started-grpc/api_config.yaml new file mode 100644 index 00000000000..eb521979979 --- /dev/null +++ b/endpoints/getting-started-grpc/api_config.yaml @@ -0,0 +1,36 @@ +# Copyright 2017 Google Inc. +# +# 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. + +# +# An example API configuration. +# +# Below, replace MY_PROJECT_ID with your Google Cloud Project ID. +# + +# The configuration schema is defined by service.proto file +# https://github.com/googleapis/googleapis/blob/master/google/api/service.proto +type: google.api.Service +config_version: 3 + +# +# Name of the service configuration. +# +name: hellogrpc.endpoints.MY_PROJECT_ID.cloud.goog + +# +# API title to appear in the user interface (Google Cloud Console). +# +title: Hello gRPC API +apis: +- name: helloworld.Greeter diff --git a/endpoints/getting-started-grpc/container-engine.yaml b/endpoints/getting-started-grpc/container-engine.yaml new file mode 100644 index 00000000000..20c0d7eb7f7 --- /dev/null +++ b/endpoints/getting-started-grpc/container-engine.yaml @@ -0,0 +1,54 @@ +# Copyright 2017 Google Inc. +# +# 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. + +apiVersion: v1 +kind: Service +metadata: + name: grpc-hello +spec: + ports: + - port: 80 + targetPort: 9000 + protocol: TCP + name: http + selector: + app: grpc-hello + type: LoadBalancer +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: grpc-hello +spec: + replicas: 1 + template: + metadata: + labels: + app: grpc-hello + spec: + containers: + - name: esp + image: gcr.io/endpoints-release/endpoints-runtime:1 + args: [ + "-P", "9000", + "-a", "grpc://127.0.0.1:50051", + "-s", "SERVICE_NAME", + "-v", "SERVICE_CONFIG_ID", + ] + ports: + - containerPort: 9000 + - name: python-grpc-hello + image: gcr.io/GCLOUD_PROJECT/python-grpc-hello:1.0 + ports: + - containerPort: 50051 diff --git a/endpoints/getting-started-grpc/greeter_client.py b/endpoints/getting-started-grpc/greeter_client.py new file mode 100644 index 00000000000..bdbc1fc5ab7 --- /dev/null +++ b/endpoints/getting-started-grpc/greeter_client.py @@ -0,0 +1,63 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""The Python implementation of the GRPC helloworld.Greeter client.""" + +import argparse + +import grpc + +import helloworld_pb2 +import helloworld_pb2_grpc + + +def run(host, api_key): + channel = grpc.insecure_channel(host) + stub = helloworld_pb2_grpc.GreeterStub(channel) + metadata = [] + if api_key: + metadata.append(('x-api-key', api_key)) + response = stub.SayHello( + helloworld_pb2.HelloRequest(name='you'), metadata=metadata) + print('Greeter client received: ' + response.message) + response = stub.SayHelloAgain( + helloworld_pb2.HelloRequest(name='you'), metadata=metadata) + print('Greeter client received: ' + response.message) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument( + '--host', default='localhost:50051', help='The server host.') + parser.add_argument( + '--api_key', default=None, help='The API key to use for the call.') + args = parser.parse_args() + run(args.host, args.api_key) diff --git a/endpoints/getting-started-grpc/greeter_server.py b/endpoints/getting-started-grpc/greeter_server.py new file mode 100644 index 00000000000..07e2f9d1345 --- /dev/null +++ b/endpoints/getting-started-grpc/greeter_server.py @@ -0,0 +1,69 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""The Python implementation of the GRPC helloworld.Greeter server.""" + +from concurrent import futures +import time + +import grpc + +import helloworld_pb2 +import helloworld_pb2_grpc + +_ONE_DAY_IN_SECONDS = 60 * 60 * 24 + + +class Greeter(helloworld_pb2_grpc.GreeterServicer): + + def SayHello(self, request, context): + return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name) + + def SayHelloAgain(self, request, context): + return helloworld_pb2.HelloReply( + message='Hello again, %s!' % request.name) + + +def serve(): + server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) + helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server) + server.add_insecure_port('[::]:50051') + server.start() + + # gRPC starts a new thread to service requests. Just make the main thread + # sleep. + try: + while True: + time.sleep(_ONE_DAY_IN_SECONDS) + except KeyboardInterrupt: + server.stop(grace=0) + + +if __name__ == '__main__': + serve() diff --git a/endpoints/getting-started-grpc/helloworld_pb2.py b/endpoints/getting-started-grpc/helloworld_pb2.py new file mode 100644 index 00000000000..9a133df46e8 --- /dev/null +++ b/endpoints/getting-started-grpc/helloworld_pb2.py @@ -0,0 +1,259 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: helloworld.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='helloworld.proto', + package='helloworld', + syntax='proto3', + serialized_pb=_b('\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2\x8e\x01\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x12\x43\n\rSayHelloAgain\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x62\x06proto3') +) +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + + + + +_HELLOREQUEST = _descriptor.Descriptor( + name='HelloRequest', + full_name='helloworld.HelloRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='helloworld.HelloRequest.name', 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=32, + serialized_end=60, +) + + +_HELLOREPLY = _descriptor.Descriptor( + name='HelloReply', + full_name='helloworld.HelloReply', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='message', full_name='helloworld.HelloReply.message', 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=62, + serialized_end=91, +) + +DESCRIPTOR.message_types_by_name['HelloRequest'] = _HELLOREQUEST +DESCRIPTOR.message_types_by_name['HelloReply'] = _HELLOREPLY + +HelloRequest = _reflection.GeneratedProtocolMessageType('HelloRequest', (_message.Message,), dict( + DESCRIPTOR = _HELLOREQUEST, + __module__ = 'helloworld_pb2' + # @@protoc_insertion_point(class_scope:helloworld.HelloRequest) + )) +_sym_db.RegisterMessage(HelloRequest) + +HelloReply = _reflection.GeneratedProtocolMessageType('HelloReply', (_message.Message,), dict( + DESCRIPTOR = _HELLOREPLY, + __module__ = 'helloworld_pb2' + # @@protoc_insertion_point(class_scope:helloworld.HelloReply) + )) +_sym_db.RegisterMessage(HelloReply) + + +try: + # THESE ELEMENTS WILL BE DEPRECATED. + # Please use the generated *_pb2_grpc.py files instead. + import grpc + from grpc.framework.common import cardinality + from grpc.framework.interfaces.face import utilities as face_utilities + from grpc.beta import implementations as beta_implementations + from grpc.beta import interfaces as beta_interfaces + + + class GreeterStub(object): + """The greeting service definition. + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.SayHello = channel.unary_unary( + '/helloworld.Greeter/SayHello', + request_serializer=HelloRequest.SerializeToString, + response_deserializer=HelloReply.FromString, + ) + self.SayHelloAgain = channel.unary_unary( + '/helloworld.Greeter/SayHelloAgain', + request_serializer=HelloRequest.SerializeToString, + response_deserializer=HelloReply.FromString, + ) + + + class GreeterServicer(object): + """The greeting service definition. + """ + + def SayHello(self, request, context): + """Sends a greeting + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def SayHelloAgain(self, request, context): + """Sends another greeting + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + + def add_GreeterServicer_to_server(servicer, server): + rpc_method_handlers = { + 'SayHello': grpc.unary_unary_rpc_method_handler( + servicer.SayHello, + request_deserializer=HelloRequest.FromString, + response_serializer=HelloReply.SerializeToString, + ), + 'SayHelloAgain': grpc.unary_unary_rpc_method_handler( + servicer.SayHelloAgain, + request_deserializer=HelloRequest.FromString, + response_serializer=HelloReply.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'helloworld.Greeter', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + class BetaGreeterServicer(object): + """The Beta API is deprecated for 0.15.0 and later. + + It is recommended to use the GA API (classes and functions in this + file not marked beta) for all further purposes. This class was generated + only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0.""" + """The greeting service definition. + """ + def SayHello(self, request, context): + """Sends a greeting + """ + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + def SayHelloAgain(self, request, context): + """Sends another greeting + """ + context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) + + + class BetaGreeterStub(object): + """The Beta API is deprecated for 0.15.0 and later. + + It is recommended to use the GA API (classes and functions in this + file not marked beta) for all further purposes. This class was generated + only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0.""" + """The greeting service definition. + """ + def SayHello(self, request, timeout, metadata=None, with_call=False, protocol_options=None): + """Sends a greeting + """ + raise NotImplementedError() + SayHello.future = None + def SayHelloAgain(self, request, timeout, metadata=None, with_call=False, protocol_options=None): + """Sends another greeting + """ + raise NotImplementedError() + SayHelloAgain.future = None + + + def beta_create_Greeter_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None): + """The Beta API is deprecated for 0.15.0 and later. + + It is recommended to use the GA API (classes and functions in this + file not marked beta) for all further purposes. This function was + generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0""" + request_deserializers = { + ('helloworld.Greeter', 'SayHello'): HelloRequest.FromString, + ('helloworld.Greeter', 'SayHelloAgain'): HelloRequest.FromString, + } + response_serializers = { + ('helloworld.Greeter', 'SayHello'): HelloReply.SerializeToString, + ('helloworld.Greeter', 'SayHelloAgain'): HelloReply.SerializeToString, + } + method_implementations = { + ('helloworld.Greeter', 'SayHello'): face_utilities.unary_unary_inline(servicer.SayHello), + ('helloworld.Greeter', 'SayHelloAgain'): face_utilities.unary_unary_inline(servicer.SayHelloAgain), + } + 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_Greeter_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None): + """The Beta API is deprecated for 0.15.0 and later. + + It is recommended to use the GA API (classes and functions in this + file not marked beta) for all further purposes. This function was + generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0""" + request_serializers = { + ('helloworld.Greeter', 'SayHello'): HelloRequest.SerializeToString, + ('helloworld.Greeter', 'SayHelloAgain'): HelloRequest.SerializeToString, + } + response_deserializers = { + ('helloworld.Greeter', 'SayHello'): HelloReply.FromString, + ('helloworld.Greeter', 'SayHelloAgain'): HelloReply.FromString, + } + cardinalities = { + 'SayHello': cardinality.Cardinality.UNARY_UNARY, + 'SayHelloAgain': 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, 'helloworld.Greeter', cardinalities, options=stub_options) +except ImportError: + pass +# @@protoc_insertion_point(module_scope) diff --git a/endpoints/getting-started-grpc/helloworld_pb2_grpc.py b/endpoints/getting-started-grpc/helloworld_pb2_grpc.py new file mode 100644 index 00000000000..58ab0c27dae --- /dev/null +++ b/endpoints/getting-started-grpc/helloworld_pb2_grpc.py @@ -0,0 +1,65 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +import grpc +from grpc.framework.common import cardinality +from grpc.framework.interfaces.face import utilities as face_utilities + +import helloworld_pb2 as helloworld__pb2 + + +class GreeterStub(object): + """The greeting service definition. + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.SayHello = channel.unary_unary( + '/helloworld.Greeter/SayHello', + request_serializer=helloworld__pb2.HelloRequest.SerializeToString, + response_deserializer=helloworld__pb2.HelloReply.FromString, + ) + self.SayHelloAgain = channel.unary_unary( + '/helloworld.Greeter/SayHelloAgain', + request_serializer=helloworld__pb2.HelloRequest.SerializeToString, + response_deserializer=helloworld__pb2.HelloReply.FromString, + ) + + +class GreeterServicer(object): + """The greeting service definition. + """ + + def SayHello(self, request, context): + """Sends a greeting + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def SayHelloAgain(self, request, context): + """Sends another greeting + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_GreeterServicer_to_server(servicer, server): + rpc_method_handlers = { + 'SayHello': grpc.unary_unary_rpc_method_handler( + servicer.SayHello, + request_deserializer=helloworld__pb2.HelloRequest.FromString, + response_serializer=helloworld__pb2.HelloReply.SerializeToString, + ), + 'SayHelloAgain': grpc.unary_unary_rpc_method_handler( + servicer.SayHelloAgain, + request_deserializer=helloworld__pb2.HelloRequest.FromString, + response_serializer=helloworld__pb2.HelloReply.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'helloworld.Greeter', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) diff --git a/endpoints/getting-started-grpc/protos/helloworld.proto b/endpoints/getting-started-grpc/protos/helloworld.proto new file mode 100644 index 00000000000..68d8888e6e0 --- /dev/null +++ b/endpoints/getting-started-grpc/protos/helloworld.proto @@ -0,0 +1,50 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} + // Sends another greeting + rpc SayHelloAgain (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/endpoints/getting-started-grpc/requirements.txt b/endpoints/getting-started-grpc/requirements.txt new file mode 100644 index 00000000000..5e131f557a2 --- /dev/null +++ b/endpoints/getting-started-grpc/requirements.txt @@ -0,0 +1,2 @@ +grpcio==1.1.3 +grpcio-tools==1.1.3 diff --git a/nox.py b/nox.py index 3268f00c2d0..fe8159405cc 100644 --- a/nox.py +++ b/nox.py @@ -140,7 +140,7 @@ def _setup_appengine_sdk(session): FLAKE8_COMMON_ARGS = [ '--show-source', '--builtin', 'gettext', '--max-complexity', '20', '--import-order-style', 'google', - '--exclude', '.nox,.cache,env,lib,generated_pb2', + '--exclude', '.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py', ] # Location of our common testing utilities. This isn't published to PyPI.