Creating SSH tunnels to monitoring channels to enable dashboard communicate with the channel
Change-Id: I2249a3f5326fd06dd5799b59c9cf486a13594305
diff --git a/xos/synchronizer/steps/sync_monitoringchannel.py b/xos/synchronizer/steps/sync_monitoringchannel.py
index bf3390b..3b97741 100644
--- a/xos/synchronizer/steps/sync_monitoringchannel.py
+++ b/xos/synchronizer/steps/sync_monitoringchannel.py
@@ -4,6 +4,11 @@
import sys
import base64
import time
+#import threading
+import subprocess
+import random
+import tempfile
+#from sshtunnel import SSHTunnelForwarder
from django.db.models import F, Q
from xos.config import Config
from synchronizers.base.syncstep import SyncStep
@@ -18,6 +23,74 @@
logger = Logger(level=logging.INFO)
+class SSHTunnel:
+
+ def __init__(self, localip, localport, key, remoteip, remote_port, jumpuser, jumphost):
+ self.key = key
+ self.remote_host = remoteip # Remote ip on remotehost
+ self.remote_port = remote_port
+ # Get a temporary file name
+ tmpfile = tempfile.NamedTemporaryFile()
+ tmpfile.close()
+ self.socket = tmpfile.name
+ self.local_port = localport
+ self.local_host = localip
+ self.jump_user = jumpuser # Remote user on remotehost
+ self.jump_host = jumphost # What host do we send traffic to
+ self.open = False
+
+ def start(self):
+ exit_status = subprocess.call(['ssh', '-MfN',
+ '-S', self.socket,
+ '-i', self.key,
+ '-L', '{}:{}:{}:{}'.format(self.local_host, self.local_port, self.remote_host, self.remote_port),
+ '-o', 'ExitOnForwardFailure=True',
+ self.jump_user + '@' + self.jump_host
+ ])
+ if exit_status != 0:
+ raise Exception('SSH tunnel failed with status: {}'.format(exit_status))
+ if self.send_control_command('check') != 0:
+ raise Exception('SSH tunnel failed to check')
+ self.open = True
+
+ def stop(self):
+ if self.open:
+ if self.send_control_command('exit') != 0:
+ raise Exception('SSH tunnel failed to exit')
+ self.open = False
+
+ def send_control_command(self, cmd):
+ return subprocess.check_call(['ssh', '-S', self.socket, '-O', cmd, '-l', self.jump_user, self.jump_host])
+
+ def __enter__(self):
+ self.start()
+ return self
+
+ def __exit__(self, type, value, traceback):
+ self.stop()
+
+
+#class SshTunnel(threading.Thread):
+# def __init__(self, localip, localport, remoteip, remoteport, proxy_ssh_key, jumpuser, jumphost):
+# threading.Thread.__init__(self)
+# self.localip = localip # Local ip to listen to
+# self.localport = localport # Local port to listen to
+# self.remoteip = remoteip # Remote ip on remotehost
+# self.remoteport = remoteport # Remote port on remotehost
+# self.proxy_ssh_key = proxy_ssh_key
+# self.jumpuser = jumpuser # Remote user on remotehost
+# self.jumphost = jumphost # What host do we send traffic to
+# self.daemon = True # So that thread will exit when
+# # main non-daemon thread finishes
+#
+# def run(self):
+# if subprocess.call([
+# 'ssh', '-N',
+# '-i', self.proxy_ssh_key,
+# '-L', self.localip + ':' + str(self.localport) + ':' + self.remoteip + ':' + str(self.remoteport),
+# jumpuser + '@' + jumphost ]):
+# raise Exception ('ssh tunnel setup failed')
+
class SyncMonitoringChannel(SyncInstanceUsingAnsible):
provides=[MonitoringChannel]
observes=MonitoringChannel
@@ -58,15 +131,53 @@
fields = {"unique_id": o.id,
"allowed_tenant_ids": o.tenant_list,
- "auth_url":instance.controller.auth_url,
- "admin_user":instance.controller.admin_user,
- "admin_password":instance.controller.admin_password,
- "admin_tenant":instance.controller.admin_tenant,
+ "auth_url":ceilometer_service.ceilometer_auth_url,
+ "admin_user":ceilometer_service.ceilometer_admin_user,
+ "admin_password":ceilometer_service.ceilometer_admin_password,
+ "admin_tenant":ceilometer_service.ceilometer_admin_tenant,
"ceilometer_pub_sub_url": ceilometer_pub_sub_url,
"full_setup": full_setup}
return fields
+ def sync_fields(self, o, fields):
+ try:
+ super(SyncMonitoringChannel, self).sync_fields(o, fields)
+
+ #Check if ssh tunnel is needed
+ proxy_ssh = getattr(Config(), "observer_proxy_ssh", False)
+
+ if proxy_ssh:
+ proxy_ssh_key = getattr(Config(), "observer_proxy_ssh_key", None)
+ proxy_ssh_user = getattr(Config(), "observer_proxy_ssh_user", "root")
+ jump_hostname = fields["hostname"]
+
+ #Get the tunnel detsination
+ remote_host = o.private_ip
+ remote_port = o.ceilometer_port
+ #FIXME: For now, trying to setup the tunnel on the local port same as the remote port
+ local_port = remote_port
+ local_ip = socket.gethostbyname(socket.gethostname())
+
+# tunnel = SSHTunnelForwarder(jump_hostname,
+# ssh_username=proxy_ssh_user,
+# ssh_pkey=proxy_ssh_key,
+# ssh_private_key_password="",
+# remote_bind_address=(remote_host,remote_port),
+# local_bind_address=(local_ip,local_port),
+# set_keepalive=300)
+# tunnel.start()
+ tunnel = SSHTunnel(local_ip, local_port, proxy_ssh_key, remote_host, remote_port, proxy_ssh_user, jump_hostname)
+ tunnel.start()
+
+ #Update the model with ssh tunnel info
+ o.ssh_proxy_tunnel = True
+ o.ssh_tunnel_ip = local_ip
+ o.ssh_tunnel_port = local_port
+
+ except Exception,error:
+ raise Exception(error)
+
def run_playbook(self, o, fields):
#ansible_hash = hashlib.md5(repr(sorted(fields.items()))).hexdigest()
#quick_update = (o.last_ansible_hash == ansible_hash)