Prep for docker-only tests

Chnages to support more production-like tests where all
components are running as Docker containers. Specific
changes:
- Expanded Vagrant memory to 6G to have room
- Chameleon to cope with premature service lookup before
  Voltha is self-registered (can happen when docker-compose
  starts the "world"
- Add missing termcolor package
- Allow CLI to use Consul for endpoints
- 2nd external ponmgmt bridge for Voltha

Change-Id: Ib2471784a5aafbfd9c611ebf293d7f81f61dd75b
diff --git a/grpc_client/grpc_client.py b/grpc_client/grpc_client.py
index 05a4dd7..48cfa75 100644
--- a/grpc_client/grpc_client.py
+++ b/grpc_client/grpc_client.py
@@ -95,7 +95,8 @@
 
         try:
             if self.endpoint.startswith('@'):
-                _endpoint = self._get_endpoint_from_consul(self.endpoint[1:])
+                _endpoint = yield self._get_endpoint_from_consul(
+                    self.endpoint[1:])
             else:
                 _endpoint = self.endpoint
 
@@ -138,6 +139,7 @@
             log.info('reconnected', after_retries=self.retries)
             self.retries = 0
 
+    @inlineCallbacks
     def _get_endpoint_from_consul(self, service_name):
         """
         Look up an appropriate grpc endpoint (host, port) from
@@ -146,11 +148,16 @@
         host = self.consul_endpoint.split(':')[0].strip()
         port = int(self.consul_endpoint.split(':')[1].strip())
 
-        consul = Consul(host=host, port=port)
-        _, services = consul.catalog.service(service_name)
-
-        if len(services) == 0:
-            raise Exception('Cannot find service %s in consul' % service_name)
+        while True:
+            log.debug('consul-lookup', host=host, port=port)
+            consul = Consul(host=host, port=port)
+            _, services = consul.catalog.service(service_name)
+            log.debug('consul-response', services=services)
+            if services:
+                break
+            log.warning('no-service', consul_host=host, consul_port=port,
+                        service_name=service_name)
+            yield asleep(1.0)
 
         # pick a random entry
         # TODO should we prefer local IP addresses? Probably.
@@ -158,7 +165,7 @@
         service = services[randint(0, len(services) - 1)]
         endpoint = '{}:{}'.format(service['ServiceAddress'],
                                   service['ServicePort'])
-        return endpoint
+        returnValue(endpoint)
 
     def _retrieve_schema(self):
         """
diff --git a/main.py b/main.py
index 805acba..4d3939d 100755
--- a/main.py
+++ b/main.py
@@ -219,15 +219,18 @@
 
     @inlineCallbacks
     def startup_components(self):
-        self.log.info('starting-internal-components')
-        args = self.args
-        self.grpc_client = yield \
-            GrpcClient(args.consul, args.work_dir, args.grpc_endpoint)
-        self.web_server = yield \
-            WebServer(args.rest_port, args.work_dir, self.grpc_client).start()
-        self.grpc_client.set_reconnect_callback(
-            self.web_server.reload_generated_routes).start()
-        self.log.info('started-internal-services')
+        try:
+            self.log.info('starting-internal-components')
+            args = self.args
+            self.grpc_client = yield \
+                GrpcClient(args.consul, args.work_dir, args.grpc_endpoint)
+            self.rest_server = yield \
+                WebServer(args.rest_port, args.work_dir, self.grpc_client).start()
+            self.grpc_client.set_reconnect_callback(
+                self.rest_server.reload_generated_routes).start()
+            self.log.info('started-internal-services')
+        except Exception, e:
+            self.log.exception('startup-failed', e=e)
 
     @inlineCallbacks
     def shutdown_components(self):