Add initial gRPC server
diff --git a/.gitignore b/.gitignore
index 5fdec72..11d18ed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,6 +32,8 @@
# Protobuf output files
voltha/core/protos/*.desc
voltha/core/protos/*_pb2.py
+third_party/googleapis/**/*.desc
+third_party/googleapis/**/*_pb2.py
# Editors
*.bak
diff --git a/env.sh b/env.sh
index 8f3a07c..c24eb91 100644
--- a/env.sh
+++ b/env.sh
@@ -12,6 +12,9 @@
fi
. $VENVDIR/bin/activate
+# add top-level voltha dir to pythonpath
+export PYTHONPATH=$PYTHONPATH:$VOLTHA_BASE/voltha
+
# assign DOCKER_HOST_IP to be the main ip address of this host
export DOCKER_HOST_IP=$(python voltha/nethelpers.py)
diff --git a/requirements.txt b/requirements.txt
index 9580168..5f9796f 100755
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,6 +3,9 @@
decorator>=3.4.0
docker-py
fluent-logger>=0.4.3
+grpc>=0.3
+grpcio>=1.0.0
+grpcio-tools>=1.0.0
hash_ring>=1.3.1
hexdump>=3.3
klein>=15.3.1
diff --git a/third_party/googleapis/google/__init__.py b/third_party/googleapis/google/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/googleapis/google/__init__.py
diff --git a/third_party/googleapis/google/api/__init__.py b/third_party/googleapis/google/api/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/googleapis/google/api/__init__.py
diff --git a/voltha/core/__init__.py b/voltha/core/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/voltha/core/__init__.py
diff --git a/voltha/core/protos/Makefile b/voltha/core/protos/Makefile
index 5466e37..5452be7 100644
--- a/voltha/core/protos/Makefile
+++ b/voltha/core/protos/Makefile
@@ -22,7 +22,7 @@
default: build
-PROTO_FILES := $(wildcard *.proto)
+PROTO_FILES := $(wildcard *.proto) $(wildcard google/api/*proto)
PROTO_PB2_FILES := $(foreach f,$(PROTO_FILES),$(subst .proto,_pb2.py,$(f)))
PROTO_DESC_FILES := $(foreach f,$(PROTO_FILES),$(subst .proto,.desc,$(f)))
@@ -42,7 +42,7 @@
%_pb2.py: %.proto Makefile
@echo "Building protocol buffer artifacts from $<"
- env LD_LIBRARY_PATH=$(PROTOC_LIBDIR) $(PROTOC) -I. -I$(VOLTHA_BASE)/third_party/googleapis --python_out=. --descriptor_set_out=$(basename $<).desc --include_source_info $<
+ env LD_LIBRARY_PATH=$(PROTOC_LIBDIR) python -m grpc.tools.protoc -I. -I$(VOLTHA_BASE)/third_party/googleapis --python_out=. --grpc_python_out=. --descriptor_set_out=$(basename $<).desc --include_source_info $<
clean:
rm -f $(PROTO_PB2_FILES) $(PROTO_DESC_FILES)
diff --git a/voltha/core/protos/__init__.py b/voltha/core/protos/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/voltha/core/protos/__init__.py
diff --git a/voltha/core/protos/google2 b/voltha/core/protos/google2
new file mode 120000
index 0000000..689c27a
--- /dev/null
+++ b/voltha/core/protos/google2
@@ -0,0 +1 @@
+../../../third_party/googleapis/google
\ No newline at end of file
diff --git a/voltha/main.py b/voltha/main.py
index 20ef726..160eb76 100755
--- a/voltha/main.py
+++ b/voltha/main.py
@@ -20,15 +20,16 @@
import argparse
import os
import time
+
import yaml
from twisted.internet.defer import inlineCallbacks
-from structlog_setup import setup_logging
-from coordinator import Coordinator
-from northbound.rest.health_check import init_rest_service
-from nethelpers import get_my_primary_interface, get_my_primary_local_ipv4
-from dockerhelpers import get_my_containers_name
-
+from voltha.coordinator import Coordinator
+from voltha.dockerhelpers import get_my_containers_name
+from voltha.nethelpers import get_my_primary_interface, get_my_primary_local_ipv4
+from voltha.northbound.grpc.grpc_server import VolthaGrpcServer
+from voltha.northbound.rest.health_check import init_rest_service
+from voltha.structlog_setup import setup_logging
defs = dict(
consul=os.environ.get('CONSUL', 'localhost:8500'),
@@ -192,6 +193,7 @@
# components
self.coordinator = None
+ self.grpc_server = None
if not args.no_banner:
print_banner(self.log)
@@ -213,13 +215,19 @@
instance_id=self.args.instance_id,
consul=self.args.consul)
init_rest_service(self.args.rest_port)
+
+ self.grpc_server = VolthaGrpcServer().run()
+
self.log.info('started-internal-services')
@inlineCallbacks
def shutdown_components(self):
"""Execute before the reactor is shut down"""
self.log.info('exiting-on-keyboard-interrupt')
- yield self.coordinator.shutdown()
+ if self.coordinator is not None:
+ yield self.coordinator.shutdown()
+ if self.grpc_server is not None:
+ yield self.grpc_server.shutdown()
def start_reactor(self):
from twisted.internet import reactor
diff --git a/voltha/northbound/grpc/__init__.py b/voltha/northbound/grpc/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/voltha/northbound/grpc/__init__.py
diff --git a/voltha/northbound/grpc/grpc_client.py b/voltha/northbound/grpc/grpc_client.py
new file mode 100644
index 0000000..3700da5
--- /dev/null
+++ b/voltha/northbound/grpc/grpc_client.py
@@ -0,0 +1,32 @@
+#
+# Copyright 2016 the original author or 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.
+#
+
+"""Temp client code to test grpc server"""
+
+import grpc
+
+from voltha.northbound.grpc import pb2_loader
+from voltha.core.protos import voltha_pb2
+
+
+def run():
+ channel = grpc.insecure_channel('localhost:50055')
+ stub = voltha_pb2.HealthServiceStub(channel)
+ response = stub.GetHealthStatus(voltha_pb2.NullMessage())
+ print 'Health state:', response.state
+
+if __name__ == '__main__':
+ run()
diff --git a/voltha/northbound/grpc/grpc_server.py b/voltha/northbound/grpc/grpc_server.py
new file mode 100644
index 0000000..7e737ae
--- /dev/null
+++ b/voltha/northbound/grpc/grpc_server.py
@@ -0,0 +1,77 @@
+#
+# Copyright 2016 the original author or 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.
+#
+
+"""gRPC server endpoint"""
+import grpc
+from concurrent import futures
+from structlog import get_logger
+
+from voltha.northbound.grpc import pb2_loader
+from voltha.core.protos import voltha_pb2
+
+log = get_logger()
+
+
+class HealthService(voltha_pb2.HealthServiceServicer):
+
+ def __init__(self, thread_pool):
+ self.thread_pool = thread_pool
+
+ def GetHealthStatus(self, request, context):
+ """Return current health status of a Voltha instance
+ """
+ log.info('get-health-status', request=request)
+ hs = voltha_pb2.HealthStatus()
+ hs.state = voltha_pb2.HealthStatus.HEALTHY
+ return hs
+
+
+class VolthaGrpcServer(object):
+
+ def __init__(self, port=50055):
+ self.port = port
+ log.info('init-grpc-server', port=self.port)
+ self.thread_pool = futures.ThreadPoolExecutor(max_workers=10)
+ self.server = grpc.server(self.thread_pool)
+
+ voltha_pb2.add_HealthServiceServicer_to_server(
+ HealthService(self.thread_pool), self.server)
+
+ self.server.add_insecure_port('[::]:%s' % self.port)
+
+ def run(self):
+ log.info('starting-grpc-server')
+ self.server.start()
+ return self
+
+ def shutdown(self, grace=0):
+ self.server.stop(grace)
+
+
+# This is to allow runninf the GRPC server in stand-alone mode
+if __name__ == '__main__':
+
+ server = VolthaGrpcServer().run()
+
+ import time
+ _ONE_DAY_IN_SECONDS = 60 * 60 * 24
+ try:
+ while 1:
+ time.sleep(_ONE_DAY_IN_SECONDS)
+ except KeyboardInterrupt:
+ server.shutdown()
+
+
diff --git a/voltha/northbound/grpc/pb2_loader.py b/voltha/northbound/grpc/pb2_loader.py
new file mode 100644
index 0000000..920ebab
--- /dev/null
+++ b/voltha/northbound/grpc/pb2_loader.py
@@ -0,0 +1,40 @@
+#
+# Copyright 2016 the original author or 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.
+#
+
+"""Assist in loading *_pb2.py protobuf files"""
+
+import sys
+
+
+#~~~~~~~~~~~~~~~~~~~~ begin import hach ~~~~~~~~~~~~~~~~~~~~~~~~~
+# Import hack to allow loading the google.api local files
+# without shadowing the google.protoc dependency. We needed
+# to do this because the grpc-generated pb2 files use
+# "from google.api import ..." directive and we cannot alter
+# the path.
+class ModuleProxy(object):
+ def __getattr__(self, key):
+ if key == 'http_pb2':
+ return http_pb2
+ elif key == 'annotations_pb2':
+ return annotations_pb2
+ else:
+ return None
+sys.modules['google.api'] = ModuleProxy()
+from voltha.core.protos.google2.api import http_pb2
+from voltha.core.protos.google2.api import annotations_pb2
+#~~~~~~~~~~~~~~~~~~~~ end import hach ~~~~~~~~~~~~~~~~~~~~~~~~~
+