Async/streaming gRPC client/server proto
This experiment was to fine-tune how we can implement
async gRPC client and server code inside a Twisted
python app.
Change-Id: I945014e27f4b9d6ed624666e0284cc298548adb3
Major cleanup of openflow_13.proto
Change-Id: I4e54eaf87b682124ec518a0ade1a6050a6ec6da8
Relocated openflow_13.proto to voltha
Change-Id: I66ae45a9142d180c2c6651e75c7a1ee08aef7ef8
Removed forced utest from make build
Change-Id: If0da58e9d135ebde6ca68c3316688a03a7b10f2f
twisted openflow agent first pass
Change-Id: Ibe5b4727ccfe92e6fd464ccd3baf6275569ef5d3
store openflow derived files
Change-Id: Ib3e1384bb2ca2a9c0872767f7b793f96b0a154e2
Minor cleanup
Change-Id: I1280ed3acb606121b616a0efd573f5f59d010dca
Factored out common utils
Change-Id: Icd86fcd50f60d0900924674cbcd65e13e47782a1
Refactored twisted agent
Change-Id: I71f26ce5357a4f98477df60b8c5ddc068cf75d43
Relocated openflow agent to ofagent
... and preserved obsolete working (non-twisted) agent under
~/obsolete, so we can still run the olt-oftest and pass tests,
unit the new twisted based agent reaches that maturity point.
Change-Id: I727f8d7144b1291a40276dad2966b7643bd7bc4b
olt-oftest in fake mode works with new agent
Change-Id: I43b4f5812e8dfaa9f45e4a77fdcf6c30ac520f8d
Initial ofagent/voltha operation
Change-Id: Ia8104f1285a6b1c51635d36d7d78fc113f800e79
Additional callouts to Voltha
Change-Id: If8f483d5140d3c9d45f22b480b8d33249a29cd4e
More gRPC calls
Change-Id: I7d24fadf9425217fb26ffe18f25359d072ef38fa
Flow add/list now works
Change-Id: Ie3e3e73108645b47891cef798fc61372a022fd93
Missed some files
Change-Id: I29e81238ff1a26c095c0c73e521579edf7092e21
diff --git a/asleep.py b/asleep.py
deleted file mode 100644
index e1868ab..0000000
--- a/asleep.py
+++ /dev/null
@@ -1,27 +0,0 @@
-#
-# 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.
-#
-
-""" Async sleep (asleep) method and other twisted goodies """
-
-from twisted.internet import reactor
-from twisted.internet.defer import Deferred
-
-
-def asleep(dt):
- assert isinstance(dt, (int, float))
- d = Deferred()
- reactor.callLater(dt, lambda: d.callback(None))
- return d
diff --git a/dockerhelpers.py b/dockerhelpers.py
deleted file mode 100644
index 0927711..0000000
--- a/dockerhelpers.py
+++ /dev/null
@@ -1,50 +0,0 @@
-#
-# 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.
-#
-
-"""
-Some docker related convenience functions
-"""
-
-import os
-from structlog import get_logger
-
-from docker import Client
-
-
-log = get_logger()
-
-
-def get_my_containers_name():
- """
- Return the docker containers name in which this process is running.
- To look up the container name, we use the container ID extracted from the
- $HOSTNAME environment variable (which is set by docker conventions).
- :return: String with the docker container name (or None if any issue is
- encountered)
- """
- my_container_id = os.environ.get('HOSTNAME', None)
-
- try:
- docker_cli = Client(base_url='unix://tmp/docker.sock')
- info = docker_cli.inspect_container(my_container_id)
-
- except Exception, e:
- log.exception('failed', my_container_id=my_container_id, e=e)
- raise
-
- name = info['Name'].lstrip('/')
-
- return name
diff --git a/grpc_client/grpc_client.py b/grpc_client/grpc_client.py
index 790bab3..9129b2e 100644
--- a/grpc_client/grpc_client.py
+++ b/grpc_client/grpc_client.py
@@ -33,7 +33,7 @@
from twisted.internet.defer import inlineCallbacks
from werkzeug.exceptions import ServiceUnavailable
-from chameleon.asleep import asleep
+from common.utils.asleep import asleep
from chameleon.protos.schema_pb2 import NullMessage, SchemaServiceStub
log = get_logger()
diff --git a/main.py b/main.py
index 3892dac..14c854b 100755
--- a/main.py
+++ b/main.py
@@ -28,11 +28,11 @@
sys.path.append(base_dir)
sys.path.append(os.path.join(base_dir, '/chameleon/protos/third_party'))
-from chameleon.structlog_setup import setup_logging
-from chameleon.nethelpers import get_my_primary_local_ipv4
-from chameleon.dockerhelpers import get_my_containers_name
from chameleon.grpc_client.grpc_client import GrpcClient
from chameleon.web_server.web_server import WebServer
+from common.utils.dockerhelpers import get_my_containers_name
+from common.utils.nethelpers import get_my_primary_local_ipv4
+from common.utils.structlog_setup import setup_logging
defs = dict(
diff --git a/nethelpers.py b/nethelpers.py
deleted file mode 100644
index 52f7f4c..0000000
--- a/nethelpers.py
+++ /dev/null
@@ -1,46 +0,0 @@
-#
-# 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.
-#
-
-"""
-Some network related convenience functions
-"""
-
-from netifaces import AF_INET
-
-import netifaces as ni
-
-
-def get_my_primary_interface():
- gateways = ni.gateways()
- assert 'default' in gateways, \
- ("No default gateway on host/container, "
- "cannot determine primary interface")
- default_gw_index = gateways['default'].keys()[0]
- # gateways[default_gw_index] has the format (example):
- # [('10.15.32.1', 'en0', True)]
- interface_name = gateways[default_gw_index][0][1]
- return interface_name
-
-
-def get_my_primary_local_ipv4(ifname=None):
- ifname = get_my_primary_interface() if ifname is None else ifname
- addresses = ni.ifaddresses(ifname)
- ipv4 = addresses[AF_INET][0]['addr']
- return ipv4
-
-
-if __name__ == '__main__':
- print get_my_primary_local_ipv4()
diff --git a/protoc_plugins/gw_gen.py b/protoc_plugins/gw_gen.py
index 77f74fa..5398c32 100755
--- a/protoc_plugins/gw_gen.py
+++ b/protoc_plugins/gw_gen.py
@@ -40,6 +40,8 @@
def add_routes(app, grpc_client):
+ pass # so that if no endpoints are defined, Python is still happy
+
{% for method in methods %}
{% set method_name = method['service'] + '_' + method['method'] %}
{% set path = method['path'].replace('{', '<string:').replace('}', '>') %}
diff --git a/structlog_setup.py b/structlog_setup.py
deleted file mode 100644
index d4b2e8e..0000000
--- a/structlog_setup.py
+++ /dev/null
@@ -1,113 +0,0 @@
-#
-# 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.
-#
-
-"""Setting up proper logging for Voltha"""
-
-import logging
-import logging.config
-from collections import OrderedDict
-
-import structlog
-from structlog.stdlib import BoundLogger, INFO
-
-try:
- from thread import get_ident as _get_ident
-except ImportError:
- from dummy_thread import get_ident as _get_ident
-
-
-class FluentRenderer(object):
- def __call__(self, logger, name, event_dict):
- # in order to keep structured log data in event_dict to be forwarded as
- # is to the fluent logger, we need to pass it into the logger framework
- # as the first positional argument.
- args = (event_dict, )
- kwargs = {}
- return args, kwargs
-
-
-class PlainRenderedOrderedDict(OrderedDict):
- """Our special version of OrderedDict that renders into string as a dict,
- to make the log stream output cleaner.
- """
- def __repr__(self, _repr_running={}):
- 'od.__repr__() <==> repr(od)'
- call_key = id(self), _get_ident()
- if call_key in _repr_running:
- return '...'
- _repr_running[call_key] = 1
- try:
- if not self:
- return '{}'
- return '{%s}' % ", ".join("%s: %s" % (k, v)
- for k, v in self.items())
- finally:
- del _repr_running[call_key]
-
-
-def setup_logging(log_config, instance_id, verbosity_adjust=0, fluentd=None):
- """
- Set up logging such that:
- - The primary logging entry method is structlog
- (see http://structlog.readthedocs.io/en/stable/index.html)
- - By default, the logging backend is Python standard lib logger
- - Alternatively, fluentd can be configured with to be the backend,
- providing direct bridge to a fluent logging agent.
- """
-
- def add_exc_info_flag_for_exception(_, name, event_dict):
- if name == 'exception':
- event_dict['exc_info'] = True
- return event_dict
-
- def add_instance_id(_, __, event_dict):
- event_dict['instance_id'] = instance_id
- return event_dict
-
- # if fluentd is specified, we need to override the config data with
- # its host and port info
- if fluentd is not None:
- fluentd_host = fluentd.split(':')[0].strip()
- fluentd_port = int(fluentd.split(':')[1].strip())
-
- handlers = log_config.get('handlers', None)
- if isinstance(handlers, dict):
- for _, defs in handlers.iteritems():
- if isinstance(defs, dict):
- if defs.get('class', '').endswith('FluentHandler'):
- defs['host'] = fluentd_host
- defs['port'] = fluentd_port
-
- # Configure standard logging
- logging.config.dictConfig(log_config)
- logging.root.level -= 10 * verbosity_adjust
-
- processors = [
- add_exc_info_flag_for_exception,
- structlog.processors.StackInfoRenderer(),
- structlog.processors.format_exc_info,
- add_instance_id,
- FluentRenderer(),
- ]
- structlog.configure(logger_factory=structlog.stdlib.LoggerFactory(),
- context_class=PlainRenderedOrderedDict,
- wrapper_class=BoundLogger,
- processors=processors)
-
- # Mark first line of log
- log = structlog.get_logger()
- log.info("first-line")
- return log