blob: 3b9774104bc9d06ed62d2864f35d31bfdc06d3e0 [file] [log] [blame]
Scott Baker31acc652016-06-23 15:47:56 -07001import hashlib
2import os
3import socket
4import sys
5import base64
6import time
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +00007#import threading
8import subprocess
9import random
10import tempfile
11#from sshtunnel import SSHTunnelForwarder
Scott Baker31acc652016-06-23 15:47:56 -070012from django.db.models import F, Q
13from xos.config import Config
14from synchronizers.base.syncstep import SyncStep
15from synchronizers.base.ansible import run_template_ssh
16from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
17from core.models import Service, Slice
Srikanth Vavilapallid84b7b72016-06-28 00:19:07 +000018from services.monitoring.models import CeilometerService, MonitoringChannel
Scott Baker31acc652016-06-23 15:47:56 -070019from xos.logger import Logger, logging
20
21parentdir = os.path.join(os.path.dirname(__file__),"..")
22sys.path.insert(0,parentdir)
23
24logger = Logger(level=logging.INFO)
25
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +000026class SSHTunnel:
27
28 def __init__(self, localip, localport, key, remoteip, remote_port, jumpuser, jumphost):
29 self.key = key
30 self.remote_host = remoteip # Remote ip on remotehost
31 self.remote_port = remote_port
32 # Get a temporary file name
33 tmpfile = tempfile.NamedTemporaryFile()
34 tmpfile.close()
35 self.socket = tmpfile.name
36 self.local_port = localport
37 self.local_host = localip
38 self.jump_user = jumpuser # Remote user on remotehost
39 self.jump_host = jumphost # What host do we send traffic to
40 self.open = False
41
42 def start(self):
43 exit_status = subprocess.call(['ssh', '-MfN',
44 '-S', self.socket,
45 '-i', self.key,
46 '-L', '{}:{}:{}:{}'.format(self.local_host, self.local_port, self.remote_host, self.remote_port),
47 '-o', 'ExitOnForwardFailure=True',
48 self.jump_user + '@' + self.jump_host
49 ])
50 if exit_status != 0:
51 raise Exception('SSH tunnel failed with status: {}'.format(exit_status))
52 if self.send_control_command('check') != 0:
53 raise Exception('SSH tunnel failed to check')
54 self.open = True
55
56 def stop(self):
57 if self.open:
58 if self.send_control_command('exit') != 0:
59 raise Exception('SSH tunnel failed to exit')
60 self.open = False
61
62 def send_control_command(self, cmd):
63 return subprocess.check_call(['ssh', '-S', self.socket, '-O', cmd, '-l', self.jump_user, self.jump_host])
64
65 def __enter__(self):
66 self.start()
67 return self
68
69 def __exit__(self, type, value, traceback):
70 self.stop()
71
72
73#class SshTunnel(threading.Thread):
74# def __init__(self, localip, localport, remoteip, remoteport, proxy_ssh_key, jumpuser, jumphost):
75# threading.Thread.__init__(self)
76# self.localip = localip # Local ip to listen to
77# self.localport = localport # Local port to listen to
78# self.remoteip = remoteip # Remote ip on remotehost
79# self.remoteport = remoteport # Remote port on remotehost
80# self.proxy_ssh_key = proxy_ssh_key
81# self.jumpuser = jumpuser # Remote user on remotehost
82# self.jumphost = jumphost # What host do we send traffic to
83# self.daemon = True # So that thread will exit when
84# # main non-daemon thread finishes
85#
86# def run(self):
87# if subprocess.call([
88# 'ssh', '-N',
89# '-i', self.proxy_ssh_key,
90# '-L', self.localip + ':' + str(self.localport) + ':' + self.remoteip + ':' + str(self.remoteport),
91# jumpuser + '@' + jumphost ]):
92# raise Exception ('ssh tunnel setup failed')
93
Scott Baker31acc652016-06-23 15:47:56 -070094class SyncMonitoringChannel(SyncInstanceUsingAnsible):
95 provides=[MonitoringChannel]
96 observes=MonitoringChannel
97 requested_interval=0
98 template_name = "sync_monitoringchannel.yaml"
Srikanth Vavilapallid84b7b72016-06-28 00:19:07 +000099 service_key_name = "/opt/xos/synchronizers/monitoring/monitoring_channel_private_key"
Scott Baker31acc652016-06-23 15:47:56 -0700100
101 def __init__(self, *args, **kwargs):
102 super(SyncMonitoringChannel, self).__init__(*args, **kwargs)
103
104 def fetch_pending(self, deleted):
105 if (not deleted):
106 objs = MonitoringChannel.get_tenant_objects().filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
107 else:
108 objs = MonitoringChannel.get_deleted_tenant_objects()
109
110 return objs
111
112 def get_extra_attributes(self, o):
113 # This is a place to include extra attributes. In the case of Monitoring Channel, we need to know
114 # 1) Allowed tenant ids
115 # 2) Ceilometer API service endpoint URL if running externally
116 # 3) Credentials to access Ceilometer API service
117
118 ceilometer_services = CeilometerService.get_service_objects().filter(id=o.provider_service.id)
119 if not ceilometer_services:
120 raise "No associated Ceilometer service"
121 ceilometer_service = ceilometer_services[0]
122 ceilometer_pub_sub_url = ceilometer_service.ceilometer_pub_sub_url
123 if not ceilometer_pub_sub_url:
124 ceilometer_pub_sub_url = ''
125 instance = self.get_instance(o)
126
127 try:
128 full_setup = Config().observer_full_setup
129 except:
130 full_setup = True
131
132 fields = {"unique_id": o.id,
133 "allowed_tenant_ids": o.tenant_list,
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +0000134 "auth_url":ceilometer_service.ceilometer_auth_url,
135 "admin_user":ceilometer_service.ceilometer_admin_user,
136 "admin_password":ceilometer_service.ceilometer_admin_password,
137 "admin_tenant":ceilometer_service.ceilometer_admin_tenant,
Scott Baker31acc652016-06-23 15:47:56 -0700138 "ceilometer_pub_sub_url": ceilometer_pub_sub_url,
139 "full_setup": full_setup}
140
141 return fields
142
Srikanth Vavilapallifd8c9b32016-08-15 22:59:28 +0000143 def sync_fields(self, o, fields):
144 try:
145 super(SyncMonitoringChannel, self).sync_fields(o, fields)
146
147 #Check if ssh tunnel is needed
148 proxy_ssh = getattr(Config(), "observer_proxy_ssh", False)
149
150 if proxy_ssh:
151 proxy_ssh_key = getattr(Config(), "observer_proxy_ssh_key", None)
152 proxy_ssh_user = getattr(Config(), "observer_proxy_ssh_user", "root")
153 jump_hostname = fields["hostname"]
154
155 #Get the tunnel detsination
156 remote_host = o.private_ip
157 remote_port = o.ceilometer_port
158 #FIXME: For now, trying to setup the tunnel on the local port same as the remote port
159 local_port = remote_port
160 local_ip = socket.gethostbyname(socket.gethostname())
161
162# tunnel = SSHTunnelForwarder(jump_hostname,
163# ssh_username=proxy_ssh_user,
164# ssh_pkey=proxy_ssh_key,
165# ssh_private_key_password="",
166# remote_bind_address=(remote_host,remote_port),
167# local_bind_address=(local_ip,local_port),
168# set_keepalive=300)
169# tunnel.start()
170 tunnel = SSHTunnel(local_ip, local_port, proxy_ssh_key, remote_host, remote_port, proxy_ssh_user, jump_hostname)
171 tunnel.start()
172
173 #Update the model with ssh tunnel info
174 o.ssh_proxy_tunnel = True
175 o.ssh_tunnel_ip = local_ip
176 o.ssh_tunnel_port = local_port
177
178 except Exception,error:
179 raise Exception(error)
180
Scott Baker31acc652016-06-23 15:47:56 -0700181 def run_playbook(self, o, fields):
182 #ansible_hash = hashlib.md5(repr(sorted(fields.items()))).hexdigest()
183 #quick_update = (o.last_ansible_hash == ansible_hash)
184
185 #if quick_update:
186 # logger.info("quick_update triggered; skipping ansible recipe")
187 #else:
188 super(SyncMonitoringChannel, self).run_playbook(o, fields)
189
190 #o.last_ansible_hash = ansible_hash
191
192 def map_delete_inputs(self, o):
193 fields = {"unique_id": o.id,
194 "delete": True}
195 return fields