VOL-539: Provide option to enable/disable TLS security between ofagent and ONOS

Change-Id: I0655a22d39d9b95d7558aea08f4cab719bd6eec0
diff --git a/compose/docker-compose-ofagent-swarm.yml b/compose/docker-compose-ofagent-swarm.yml
index 29a5363..d11ffcf 100644
--- a/compose/docker-compose-ofagent-swarm.yml
+++ b/compose/docker-compose-ofagent-swarm.yml
@@ -25,6 +25,9 @@
             - --controller=onos:6653
             - --grpc-endpoint=vcore:50556
             - --instance-id-is-container-name
+            - --enable-tls
+            - --key-file=/ofagent/pki/voltha.key
+            - --cert-file=/ofagent/pki/voltha.crt
         volumes:
             - /var/run/docker.sock:/tmp/docker.sock
         networks:
diff --git a/compose/docker-compose-ofagent-test.yml b/compose/docker-compose-ofagent-test.yml
index d2de4c2..20d20ca 100644
--- a/compose/docker-compose-ofagent-test.yml
+++ b/compose/docker-compose-ofagent-test.yml
@@ -178,7 +178,7 @@
   #
   ofagent:
     image: cord/ofagent
-    command: /ofagent/ofagent/main.py -v --consul=${DOCKER_HOST_IP}:8500 --fluentd=fluentd:24224 --controller ${DOCKER_HOST_IP}:6633 ${DOCKER_HOST_IP}:6644 ${DOCKER_HOST_IP}:6655 --grpc-endpoint=@voltha-grpc --instance-id-is-container-name
+    command: /ofagent/ofagent/main.py -v --consul=${DOCKER_HOST_IP}:8500 --fluentd=fluentd:24224 --controller ${DOCKER_HOST_IP}:6633 ${DOCKER_HOST_IP}:6644 ${DOCKER_HOST_IP}:6655 --grpc-endpoint=@voltha-grpc --instance-id-is-container-name --enable-tls --key-file=/ofagent/pki/voltha.key --cert-file=/ofagent/pki/voltha.crt
     depends_on:
     - consul
     - voltha
diff --git a/compose/docker-compose-system-test.yml b/compose/docker-compose-system-test.yml
index e22ea0a..0ce7920 100644
--- a/compose/docker-compose-system-test.yml
+++ b/compose/docker-compose-system-test.yml
@@ -206,6 +206,9 @@
       "--controller=${DOCKER_HOST_IP}:6653",
       "--grpc-endpoint=@voltha-grpc",
       "--instance-id-is-container-name",
+      "--enable-tls",
+      "--key-file=/ofagent/pki/voltha.key",
+      "--cert-file=/ofagent/pki/voltha.crt",
       "-v"
     ]
     depends_on:
diff --git a/ofagent/agent.py b/ofagent/agent.py
index d2ecd0c..cb59d24 100644
--- a/ofagent/agent.py
+++ b/ofagent/agent.py
@@ -17,6 +17,7 @@
 import sys
 
 import structlog
+import os.path
 from twisted.internet import protocol
 from twisted.internet import reactor
 from twisted.internet import reactor, ssl
@@ -42,12 +43,18 @@
                  datapath_id,
                  device_id,
                  rpc_stub,
+                 enable_tls=False,
+                 key_file=None,
+                 cert_file=None,
                  conn_retry_interval=1):
 
         self.controller_endpoint = controller_endpoint
         self.datapath_id = datapath_id
         self.device_id = device_id
         self.rpc_stub = rpc_stub
+        self.enable_tls = enable_tls
+        self.key_file = key_file
+        self.cert_file = cert_file
         self.retry_interval = conn_retry_interval
 
         self.running = False
@@ -89,18 +96,31 @@
         while not self.exiting:
             host, port = self.resolve_endpoint(self.controller_endpoint)
             log.info('connecting', host=host, port=port)
-            try:
-               with open("/ofagent/pki/voltha.key") as keyFile:
-                    with open("/ofagent/pki/voltha.crt") as certFile:
-                         clientCert = ssl.PrivateCertificate.loadPEM(
-                              keyFile.read() + certFile.read())
+            if self.enable_tls:
+                try:
+                    # Check that key_file and cert_file is provided and
+                    # the files exist
+                    if self.key_file is None or             \
+                       self.cert_file is None or            \
+                       not os.path.isfile(self.key_file) or \
+                       not os.path.isfile(self.cert_file):
+                        raise Exception('key_file "{}" or cert_file "{}"'
+                                        ' is not found'.
+                                         format(self.key_file, self.cert_file))
+                    with open(self.key_file) as keyFile:
+                        with open(self.cert_file) as certFile:
+                            clientCert = ssl.PrivateCertificate.loadPEM(
+                                keyFile.read() + certFile.read())
 
-               ctx = clientCert.options()
-               self.connector = reactor.connectSSL(host, port, self, ctx)
+                    ctx = clientCert.options()
+                    self.connector = reactor.connectSSL(host, port, self, ctx)
+                    log.info('tls-enabled')
 
-            except Exception as e:
-                log.exception('failed-to-connect', reason=e)
-
+                except Exception as e:
+                    log.exception('failed-to-connect', reason=e)
+            else:
+                self.connector = reactor.connectTCP(host, port, self)
+                log.info('tls-disabled')
 
             self.d_disconnected = Deferred()
             yield self.d_disconnected
diff --git a/ofagent/connection_mgr.py b/ofagent/connection_mgr.py
index 0d75be0..a61f2ab 100644
--- a/ofagent/connection_mgr.py
+++ b/ofagent/connection_mgr.py
@@ -41,6 +41,7 @@
 
 class ConnectionManager(object):
     def __init__(self, consul_endpoint, vcore_endpoint, controller_endpoints,
+                 enable_tls=False, key_file=None, cert_file=None,
                  vcore_retry_interval=0.5, devices_refresh_interval=5,
                  subscription_refresh_interval=5):
 
@@ -49,6 +50,9 @@
         self.controller_endpoints = controller_endpoints
         self.consul_endpoint = consul_endpoint
         self.vcore_endpoint = vcore_endpoint
+        self.enable_tls = enable_tls
+        self.key_file = key_file
+        self.cert_file = cert_file
 
         self.channel = None
         self.grpc_client = None  # single, shared gRPC client to vcore
@@ -256,7 +260,8 @@
         device_id = device.id
         for controller_endpoint in self.controller_endpoints:
             agent = Agent(controller_endpoint, datapath_id,
-                          device_id, self.grpc_client)
+                          device_id, self.grpc_client, self.enable_tls,
+                          self.key_file, self.cert_file)
             agent.start()
             self.agent_map[(datapath_id,controller_endpoint)] = agent
             self.device_id_to_datapath_id_map[device_id] = datapath_id
diff --git a/ofagent/main.py b/ofagent/main.py
index 4811380..6812514 100755
--- a/ofagent/main.py
+++ b/ofagent/main.py
@@ -37,7 +37,9 @@
     instance_id=os.environ.get('INSTANCE_ID', os.environ.get('HOSTNAME', '1')),
     internal_host_address=os.environ.get('INTERNAL_HOST_ADDRESS',
                                          get_my_primary_local_ipv4()),
-    work_dir=os.environ.get('WORK_DIR', '/tmp/ofagent')
+    work_dir=os.environ.get('WORK_DIR', '/tmp/ofagent'),
+    key_file=os.environ.get('KEY_FILE', '/ofagent/pki/voltha.key'),
+    cert_file=os.environ.get('CERT_FILE', '/ofagent/pki/voltha.crt')
 )
 
 
@@ -147,6 +149,29 @@
                         default=False,
                         help=_help)
 
+    _help = ('Specify this option to enable TLS security between ofagent \
+              and onos.')
+    parser.add_argument('-t', '--enable-tls',
+                        dest='enable_tls',
+                        action='store_true',
+                        help=_help)
+
+    _help = ('key file to be used for tls security (default=%s)'
+             % defs['key_file'])
+    parser.add_argument('-k', '--key-file',
+                        dest='key_file',
+                        action='store',
+                        default=defs['key_file'],
+                        help=_help)
+
+    _help = ('certificate file to be used for tls security (default=%s)'
+             % defs['cert_file'])
+    parser.add_argument('-r', '--cert-file',
+                        dest='cert_file',
+                        action='store',
+                        default=defs['cert_file'],
+                        help=_help)
+
     args = parser.parse_args()
 
     # post-processing
@@ -213,7 +238,8 @@
         self.log.info('starting-internal-components')
         args = self.args
         self.connection_manager = yield ConnectionManager(
-            args.consul, args.grpc_endpoint, args.controller).start()
+            args.consul, args.grpc_endpoint, args.controller,\
+            args.enable_tls, args.key_file, args.cert_file).start()
         self.log.info('started-internal-services')
 
     @inlineCallbacks