def poll_sources(self): while self.running[0] and self.ctrl_be.running: #sleep here for cmd in self.sources: cmd.poll() time.sleep(self.interval) log_debug('Exiting monitor thread...\n')
def poll(self): output = StringIO.StringIO() if self.ctrl_be.server_helper.execute_command( "/usr/bin/uptime", output_handler=output.write) == 0: data = output.getvalue().strip(" \r\t\n,:.").split("\n")[-1] self._cpu_stat_return = None load_value = data.split()[-3] # in some systems, the format is x.xx x.xx x.xx and in others, it's x.xx, x.xx, x.xx load_value = load_value.rstrip(",") try: result = float(load_value.replace(',', '.')) except (ValueError, TypeError): log_error( "Shell source %s returned wrong value. Expected int or float but got '%s'\n" % (self.name, load_value)) result = 0 if self.widget is not None: self.widget.set_value( self.calc_cb(result) if self.calc_cb else result) if self.label_cb is not None: self.ctrl_be.uitask(self.label.set_text, self.label_cb(result)) else: value = output.getvalue() if value != self._cpu_stat_return: self._cpu_stat_return = value log_debug("CPU stat command returned error: %s\n" % value)
def cmd_executor(cmd): p1 = None if platform.system() != "Windows": try: p1 = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr=subprocess.PIPE, shell = True) except OSError as exc: log_error("Error executing command %s\n%s\n" % (cmd, exc)); import traceback traceback.print_exc() else: try: info = subprocess.STARTUPINFO() info.dwFlags |= subprocess.STARTF_USESHOWWINDOW info.wShowWindow = subprocess.SW_HIDE # Command line can contain object names in case of export and filename in case of import # Object names must be in utf-8 but filename must be encoded in the filesystem encoding, # which probably isn't utf-8 in windows. if isinstance(cmd, list): for idx,item in enumerate(cmd): cmd[idx] = item.encode("utf8") if isinstance(item,str) else item log_debug("Executing command: %s\n" % "".join(cmd)) else: cmd = cmd.encode("utf8") if isinstance(cmd,str) else cmd log_debug("Executing command: %s\n" % cmd) p1 = subprocess.Popen(str(cmd), stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=info, shell = True) except OSError as exc: log_error("Error executing command %s\n%s\n" % (cmd, exc)) import traceback traceback.print_exc() p1 = None return p1
def force_check_server_state(self, verbose=False): # Check the current state of the server and cause the SQL Editor to reconnect/update if the state # changed. Returns None if no state change was detected or the new state if it did change. old_state = self.last_known_server_running_status[0] new_state = self.is_server_running(verbose=verbose, force_hard_check=True) log_debug("Force check server state returned %s\n" % new_state) if new_state != old_state: info = { "state": -1, "connection": self.server_profile.db_connection_params } if new_state == "running": info['state'] = 1 elif new_state == "offline": info['state'] = -1 else: info['state'] = 0 # this will notify the rest of the App that the server state has changed, giving them a chance # to reconnect or formally disconnect nc.send("GRNServerStateChanged", self.editor, info) if new_state == "stopped" or new_state == "offline": self.server_variables = {} self.status_variables_time = None self.status_variables = {} return new_state return None
def wait_connection(self, port): tunnel = self.tunnel_by_port.get(port) if not tunnel: return 'Could not find a tunnel for port %d' % port error = None close_tunnel = False tunnel.port_is_set.wait() if tunnel.isAlive(): while True: # Process any message in queue. Every retrieved message is printed. # If an error is detected in the queue, exit returning its message: try: msg_type, msg = tunnel.q.get_nowait() except queue.Empty: continue else: if msg_type == 'KEY_ERROR': if mforms.Utilities.show_message("SSH Server Fingerprint Missing", msg['msg'], "Continue", "Cancel", "") == mforms.ResultOk: msg['obj'].client._host_keys.add(msg['obj'].hostname, msg['obj'].key.get_name(), msg['obj'].key) if msg['obj'].client._host_keys_filename is not None: try: if os.path.isdir(os.path.dirname(msg['obj'].client._host_keys_filename)) == False: log_warning("Host_keys directory is missing, recreating it\n") os.makedirs(os.path.dirname(msg['obj'].client._host_keys_filename)) if os.path.exists(msg['obj'].client._host_keys_filename) == False: log_warning("Host_keys file is missing, recreating it\n") open(msg['obj'].client._host_keys_filename, 'a').close() msg['obj'].client.save_host_keys(msg['obj'].client._host_keys_filename) log_warning("Successfully saved host_keys file.\n") except IOError as e: error = str(e) break; error = "Server key has been stored" else: error = "User cancelled" close_tunnel = True break # Exit returning the error message elif msg_type == 'IO_ERROR': error = msg break # Exit returning the error message else: time.sleep(0.3) _msg = msg if type(msg) is tuple: msg = '\n' + ''.join(traceback.format_exception(*msg)) _msg = str(_msg[1]) log_debug("%s: %s\n" % (msg_type, msg)) if msg_type == 'ERROR': error = _msg break # Exit returning the error message if (not tunnel.is_connecting() or not tunnel.isAlive()) and tunnel.q.empty(): break time.sleep(0.3) log_debug("returning from wait_connection(%s): %s\n" % (port, error)) # we need to close tunnel so it get opened again, without it we may have problems later if close_tunnel: tunnel.close() del self.tunnel_by_port[port] return error
def launch_process(self, command, working_directory): is_windows = platform.system() == 'Windows' real_command = "" info = None if is_windows: info = subprocess.STARTUPINFO() info.dwFlags |= _subprocess.STARTF_USESHOWWINDOW info.wShowWindow = _subprocess.SW_HIDE # Command line can contain object names in case of export and filename in case of import # Object names must be in utf-8 but filename must be encoded in the filesystem encoding, # which probably isn't utf-8 in windows. fse = sys.getfilesystemencoding() real_command = command.encode(fse) if isinstance( command, unicode) else command else: real_command = command try: log_debug("Executing command: %s\n" % real_command) proc = subprocess.Popen(real_command, cwd=working_directory, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=info) except OSError, exc: log_error("Error executing command %s\n%s\n" % (real_command, exc)) import traceback traceback.print_exc() raise RuntimeError("Error executing %s:\n%s" % (real_command, str(exc)))
def reader(self, ssh_session): what = None out = "" timeouts = 12 while self.running[0]: # running is passed in list via "refernce" try: ch = ssh_session.recv(1) timeouts = 12 if ch == "C": what = self.parse_cpu elif ch == "\r" or ch == "\n": if what is not None: what(out) what = None out = "" elif ch in "0123456789. ": out += ch elif ch == ",": out += "." else: what = None out = "" except socket.timeout: timeouts -= 1 if timeouts <= 0: ssh_session.close() raise Exception("Can't read from remote Windows script") log_debug('Leaving monitor thread which polls remote windows\n')
def open_ssh(self, server, username, password, keyfile, target): server = self._address_port_tuple(server, default_port=SSH_PORT) target = self._address_port_tuple(target, default_port=REMOTE_PORT) password = password or '' keyfile = keyfile or None if keyfile is not None: keyfile = keyfile.decode('utf-8') found = None for tunnel in self.tunnel_by_port.itervalues(): if tunnel.match(server, username, target) and tunnel.isAlive(): found = tunnel break if found: with tunnel.lock: log_debug('Reusing tunnel at port %d' % tunnel.local_port) return tunnel.local_port else: tunnel = Tunnel(Queue.Queue(), server, username, target, password, keyfile) tunnel.start() tunnel.port_is_set.wait() with tunnel.lock: port = tunnel.local_port self.tunnel_by_port[port] = tunnel return port
def migrationUpdate(self): if hasattr(self.migrationSource.migration, 'migrateUpdateForChanges'): self.migrationTarget.catalog = self.migrationSource.migration.migrateUpdateForChanges( self.state, self.migrationTarget.catalog) else: log_debug( 'migrateUpdateForChanges method call was skipped for module %s\n' % self.migrationSource.migration.__name__)
def shutdown(self): log_debug("shutting down admin\n") dprint_ex(2, " closing") self.closing = True for tab in self.tabs: if hasattr(tab, "shutdown"): res = tab.shutdown() if res is False: # It has to explicitely return False to cancel shutdown self.closing = False
def query_server_info(self): self.server_variables = {} result = self.exec_query("SHOW VARIABLES") if not result: # Didn't get the server variables. Assuming the server is stopped self.last_known_server_running_status = ("stopped", time.time()) return while result and result.nextRow(): self.server_variables[result.stringByName( "Variable_name")] = result.stringByName("Value") self.status_variables_time = time.time() self.status_variables = {} result = self.exec_query("SHOW GLOBAL STATUS") while result and result.nextRow(): self.status_variables[result.stringByName( "Variable_name")] = result.stringByName("Value") # check version if self.server_variables: self.raw_version = self.server_variables["version"] self.target_version = Version.fromstr(self.raw_version) if self.server_profile.server_version != self.raw_version: # Update profile version with live data from server log_debug( '%s.connect_sql(): The server version stored in the server instance profile was "%s". ' 'Changed it to the version reported by the server: "%s"\n' % (self.__class__.__name__, self.server_profile.server_version, self.raw_version)) self.server_profile.server_version = self.raw_version if self.target_version and self.target_version.is_supported_mysql_version_at_least( 5, 1, 5): # The command to retrieve plugins was 'SHOW PLUGIN' for v. [5.1.5, 5.1.9) # and was changed to 'SHOW PLUGINS' from MySQL Server v. 5.1.9 onwards: plugin_var = 'PLUGINS' if self.target_version.is_supported_mysql_version_at_least( 5, 1, 9) else 'PLUGIN' result = self.exec_query('SHOW %s' % plugin_var) # check whether Windows authentication plugin is available while result and result.nextRow(): name = result.stringByName("Name") status = result.stringByName("Status") plugin_type = result.stringByName("Type") if status == "ACTIVE": self.server_active_plugins.add((name, plugin_type)) if "offline_mode" in self.server_variables and self.server_variables[ "offline_mode"] == "ON": #We're in offline mode, need to change server status self.last_known_server_running_status = ("offline", time.time()) else: self.last_known_server_running_status = ("running", time.time())
def kill(self): self.abort_requested = True if self.process_handle: if platform.system() == 'Windows': cmd = "taskkill /F /T /PID %i" % self.process_handle.pid log_debug("Killing task: %s\n" % cmd) subprocess.Popen(cmd , shell=True) else: import signal try: log_debug("Sending SIGTERM to task %s\n" % self.process_handle.pid) os.kill(self.process_handle.pid, signal.SIGTERM) except OSError, exc: log_error("Exception sending SIGTERM to task: %s\n" % exc) self.print_log_message("kill task: %s" % str(exc))
def wait_connection(self, port): tunnel = self.tunnel_by_port.get(port) if not tunnel: return 'Could not find a tunnel for port %d' % port error = None tunnel.port_is_set.wait() if tunnel.isAlive(): while True: # Process any message in queue. Every retrieved message is printed. # If an error is detected in the queue, exit returning its message: try: msg_type, msg = tunnel.q.get_nowait() except Queue.Empty: continue else: if msg_type == 'KEY_ERROR': if mforms.Utilities.show_message("SSH Server Fingerprint Missing", msg['msg'], "Continue", "Cancel", "") == mforms.ResultOk: msg['obj'].client._host_keys.add(msg['obj'].hostname, msg['obj'].key.get_name(), msg['obj'].key) if msg['obj'].client._host_keys_filename is not None: try: if os.path.isdir(os.path.dirname(msg['obj'].client._host_keys_filename)) == False: log_warning("Host_keys directory is missing, recreating it\n") os.makedirs(os.path.dirname(msg['obj'].client._host_keys_filename)) if os.path.exists(msg['obj'].client._host_keys_filename) == False: log_warning("Host_keys file is missing, recreating it\n") open(msg['obj'].client._host_keys_filename, 'a').close() msg['obj'].client.save_host_keys(msg['obj'].client._host_keys_filename) log_warning("Successfully saved host_keys file.\n") except IOError, e: error = str(e) break; error = "Server key has been stored" else: error = "User cancelled" break # Exit returning the error message elif msg_type == 'IO_ERROR': error = msg break # Exit returning the error message else: time.sleep(0.3) _msg = msg if type(msg) is tuple: msg = '\n' + ''.join(traceback.format_exception(*msg)) _msg = str(_msg[1]) log_debug("%s: %s\n" % (msg_type, msg)) if msg_type == 'ERROR': error = _msg break # Exit returning the error message
def kill(self): self.abort_requested = True if self.process_handle: if platform.system() == 'Windows': cmd = "taskkill /F /T /PID %i" % self.process_handle.pid log_debug("Killing task: %s\n" % cmd) subprocess.Popen(cmd, shell=True) else: import signal try: log_debug("Sending SIGTERM to task %s\n" % self.process_handle.pid) os.kill(self.process_handle.pid, signal.SIGTERM) except OSError, exc: log_error("Exception sending SIGTERM to task: %s\n" % exc) self.print_log_message("kill task: %s" % str(exc))
def handle_on_close(self): log_debug("Closing admin\n") if self._timeout_tm: Utilities.cancel_timeout(self._timeout_tm) self._timeout_tm = None nc.remove_observer(self.handle_server_state_changed) App.get().set_status_text("Closing Administator.") self.shutdown() if not self.closing: log_debug("Admin close cancelled\n") return False self.ctrl_be.shutdown() self.release() self.owner.handle_close() return True
def __init__(self, ctrl_be, server_profile, main_view, editor): mforms.AppView.__init__(self, False, "Administrator", "Administrator", False) self.editor = editor self.owner = main_view self.tabs = [] self.name2page = {} self.config_ui = None self.closing = False self.tabview = newTabView(True) self.ctrl_be = ctrl_be self.old_active_tab = None self.server_profile = server_profile if self.server_profile.host_os == wbaOS.darwin: self.set_back_color( Color.getSystemColor(ControlBackgroundColor).to_html()) # Setup self self.set_managed() self.set_release_on_add() self.on_close(wb_admin_utils.weakcb(self, "handle_on_close")) nc.add_observer(self.handle_server_state_changed, "GRNServerStateChanged", editor) nc.add_observer(self.updateColors, "GNColorsChanged") self.ctrl_be.add_me_for_event("server_started", self) self.ctrl_be.add_me_for_event("server_stopped", self) self.add(self.tabview, True, True) self._timeout_tm = Utilities.add_timeout(0.5, weakcb(self, "timeout")) self.tabview.add_tab_changed_callback(self.tab_changed) self.timeout() # check initial state if editor.isConnected == 1: self.ctrl_be.event_from_main("server_started") elif editor.isConnected == -1: self.ctrl_be.event_from_main("server_offline") self.ctrl_be.continue_events( ) # Process events which are queue during init log_debug("WBA init complete\n")
def get_config_options(): if self.server_profile.config_file_path and self.server_helper: try: cfg_file = io.StringIO( self.server_helper.get_file_content( self.server_profile.config_file_path)) except PermissionDeniedError: log_debug( 'Could not open the file "%s" as the current user. Trying as admin\n' % self.server_profile.config_file_path) while True: try: password = self.password_handler.get_password_for( 'file') cfg_file = io.StringIO( self.server_helper.get_file_content( self.server_profile.config_file_path, as_user=Users.ADMIN, user_password=password)) break except InvalidPasswordError: self.password_handler.reset_password_for('file') except Exception as err: log_error('Could not open the file "%s": %s\n' % (self.server_profile.config_file_path, str(err))) return {} except Exception as err: log_error('Could not open the file "%s": %s\n' % (self.server_profile.config_file_path, str(err))) return {} opts = {} section = 'root' for line in cfg_file: line = line.strip() if line == '' or line.startswith('#'): continue elif line.startswith('[') and line.endswith(']'): section = line[1:-1].strip() else: k, d, v = line.partition('=') val = v.strip() or 'ON' opts.setdefault(section, {})[k.strip()] = val return opts return {}
def __init__(self, ctrl_be, server_profile, main_view, editor): mforms.AppView.__init__(self, False, "administrator", False) self.editor = editor self.owner = main_view self.tabs = [] self.name2page = {} self.config_ui = None self.closing = False self.tabview = newTabView(True) self.ctrl_be = ctrl_be self.old_active_tab = None self.server_profile = server_profile # if we're in the Mac, we need to set the background color of the main view of the tab to white, # so that MTabSwitcher will take the cue and set the tab color to white too if self.server_profile.host_os == wbaOS.darwin: self.set_back_color("#ffffff") # Setup self self.set_managed() self.set_release_on_add() self.on_close(wb_admin_utils.weakcb(self, "handle_on_close")) nc.add_observer(self.handle_server_state_changed, "GRNServerStateChanged", editor) self.ctrl_be.add_me_for_event("server_started", self) self.ctrl_be.add_me_for_event("server_stopped", self) self.add(self.tabview, True, True) self._timeout_tm = Utilities.add_timeout(0.5, weakcb(self, "timeout")) self.tabview.add_tab_changed_callback(self.tab_changed) self.timeout() # check initial state if editor.isConnected == 1: self.ctrl_be.event_from_main("server_started") elif editor.isConnected == -1: self.ctrl_be.event_from_main("server_offline") self.ctrl_be.continue_events( ) # Process events which are queue during init log_debug("WBA init complete\n")
def __init__(self, ctrl_be, server_profile, main_view, editor): mforms.AppView.__init__(self, False, "administrator", False) self.editor = editor self.owner = main_view self.tabs = [] self.name2page = {} self.config_ui = None self.closing = False self.tabview = newTabView(True) self.ctrl_be = ctrl_be self.old_active_tab = None self.server_profile = server_profile # if we're in the Mac, we need to set the background color of the main view of the tab to white, # so that MTabSwitcher will take the cue and set the tab color to white too if self.server_profile.host_os == wbaOS.darwin: self.set_back_color("#ffffff") # Setup self self.set_managed() self.set_release_on_add() self.on_close(wb_admin_utils.weakcb(self, "handle_on_close")) nc.add_observer(self.handle_server_state_changed, "GRNServerStateChanged", editor) self.ctrl_be.add_me_for_event("server_started", self) self.ctrl_be.add_me_for_event("server_stopped", self) self.add(self.tabview, True, True) self._timeout_tm = Utilities.add_timeout(0.5, weakcb(self, "timeout")) self.tabview.add_tab_changed_callback(self.tab_changed) self.timeout() # check initial state if editor.isConnected == 1: self.ctrl_be.event_from_main("server_started") elif editor.isConnected == -1: self.ctrl_be.event_from_main("server_offline") self.ctrl_be.continue_events() # Process events which are queue during init log_debug("WBA init complete\n")
def exec_query_multi_result(self, q, auto_reconnect=True): ret = None if self.sql is not None: try: ret = self.sql.exec_query_multi_result(q) except QueryError as e: log_warning("Error executing query multi result %s: %s\n" % (q, strip_password(str(e)))) if auto_reconnect and e.is_connection_error(): log_warning( "exec_query_multi_result: Loss of connection to mysql server was detected.\n" ) self.handle_sql_disconnection(e) else: # if exception is not handled, give a chance to the caller do it raise e else: log_debug("sql connection is down\n") return ret
def exec_sql(self, q, auto_reconnect=True): if self.sql is not None: try: ret = self.sql.execute(q) cnt = self.sql.updateCount() return ret, cnt except QueryError as e: log_warning("Error executing SQL %s: %s\n" % (strip_password(q), strip_password(str(e)))) if auto_reconnect and e.is_connection_error(): log_warning( "exec_sql: Loss of connection to mysql server was detected.\n" ) self.handle_sql_disconnection(e) else: raise e else: log_debug("sql connection is down\n") return None, -1
def testInstanceSettingByName(what, connection, server_instance): global test_ssh_connection log_debug("Test %s in %s\n" % (what, connection.name)) profile = ServerProfile(connection, server_instance) if what == "connect_to_host": if test_ssh_connection: test_ssh_connection = None log_info("Instance test: Connecting to %s\n" % profile.ssh_hostname) try: test_ssh_connection = wb_admin_control.WbAdminControl(profile, None, connect_sql=False, test_only = True) test_ssh_connection.init() grt.send_info("connected.") except Exception, exc: log_error("Exception: %s" % exc.message) import traceback log_debug2("Backtrace was: " % traceback.format_stack()) return "ERROR "+str(exc) except:
def testInstanceSettingByName(what, connection, server_instance): global test_ssh_connection log_debug("Test %s in %s\n" % (what, connection.name)) profile = ServerProfile(connection, server_instance) if what == "connect_to_host": if test_ssh_connection: test_ssh_connection = None log_info("Instance test: Connecting to %s\n" % profile.ssh_hostname) try: test_ssh_connection = wb_admin_control.WbAdminControl(profile, None, connect_sql=False, test_only=True) test_ssh_connection.init() grt.send_info("connected.") except Exception, exc: log_error("Exception: %s\n" % exc.message) import traceback log_debug2("Backtrace was: ", traceback.format_stack()) return "ERROR "+str(exc) except:
def server_polling_thread(self): try: password = self.get_mysql_password() self.poll_connection = MySQLConnection( self.server_profile.db_connection_params, password=password) self.poll_connection.connect() except MySQLError as err: log_error("Error creating SQL connection for monitoring: %r\n" % err) self.poll_connection = None mforms.Utilities.driver_shutdown() return None log_debug("Monitoring thread running...\n") time.sleep(self.status_variable_poll_interval) try: # runs in a separate thread to fetch status variables while self.running: log_debug3("Poll server status\n") variables = {} result = self.poll_connection.executeQuery( "SHOW GLOBAL STATUS") while result and result.nextRow(): variables[result.stringByName( "Variable_name")] = result.stringByName("Value") self.status_variables, self.status_variables_time = variables, time.time( ) time.sleep(self.status_variable_poll_interval) except QueryError: log_error("Error in monitoring thread: %s\n" % traceback.format_exc()) log_debug("Monitoring thread done.\n") self.poll_connection.disconnect() self.poll_connection = None mforms.Utilities.driver_shutdown()
def connect_sql(self): # from GUI thread only, throws MySQLError if not self.is_sql_connected(): password = self.get_mysql_password() connection = MySQLConnection( self.server_profile.db_connection_params, self.sql_status_callback, password=password) try: connection.connect() except grt.UserInterrupt: log_debug("Cancelled connection\n") return self.sql = SQLQueryExecutor(connection) if self.is_sql_connected(): # perform some server capabilities checking self.query_server_info() else: log_error("Failed to connect to MySQL server\n") else: log_debug("Already connected to MySQL server\n")
def poll(self): output = StringIO.StringIO() if self.ctrl_be.server_helper.execute_command("/usr/bin/uptime", output_handler=output.write) == 0: data = output.getvalue().strip(" \r\t\n,:.").split("\n")[-1] self._cpu_stat_return = None load_value = data.split()[-3] # in some systems, the format is x.xx x.xx x.xx and in others, it's x.xx, x.xx, x.xx load_value = load_value.rstrip(",") try: result = float(load_value.replace(',','.')) except (ValueError, TypeError): log_error("Shell source %s returned wrong value. Expected int or float but got '%s'\n" % (self.name, load_value)) result = 0 if self.widget is not None: self.widget.set_value(self.calc_cb(result) if self.calc_cb else result) if self.label_cb is not None: self.ctrl_be.uitask(self.label.set_text, self.label_cb(result)) else: value = output.getvalue() if value != self._cpu_stat_return: self._cpu_stat_return = value log_debug("CPU stat command returned error: %s\n" % value)
def testInstanceSettingByName(what, connection, server_instance): global test_ssh_connection log_debug("Test %s in %s\n" % (what, connection.name)) profile = ServerProfile(connection, server_instance) if what == "connect_to_host": if test_ssh_connection: test_ssh_connection = None log_info("Instance test: Connecting to %s\n" % profile.ssh_hostname) try: test_ssh_connection = wb_admin_control.WbAdminControl( profile, None, connect_sql=False) test_ssh_connection.init() grt.send_info("connected.") except Exception, exc: import traceback traceback.print_exc() return "ERROR " + str(exc) except:
def launch_process(self, command, working_directory): is_windows = platform.system() == 'Windows' real_command = "" info = None if is_windows: info = subprocess.STARTUPINFO() info.dwFlags |= _subprocess.STARTF_USESHOWWINDOW info.wShowWindow = _subprocess.SW_HIDE # Command line can contain object names in case of export and filename in case of import # Object names must be in utf-8 but filename must be encoded in the filesystem encoding, # which probably isn't utf-8 in windows. fse = sys.getfilesystemencoding() real_command = command.encode(fse) if isinstance(command, unicode) else command else: real_command = command try: log_debug("Executing command: %s\n" % real_command) proc = subprocess.Popen(real_command, cwd=working_directory, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT,startupinfo=info) except OSError, exc: log_error("Error executing command %s\n%s\n" % (real_command, exc)) import traceback traceback.print_exc() raise RuntimeError("Error executing %s:\n%s" % (real_command, str(exc)))
def import_script(self, path, default_schema=None, default_charset="utf8"): if not self._tool_path: raise RuntimeError( "mysql command line client not found. Please fix its path in Preferences -> Administration" ) is_windows = platform.system() == 'Windows' if is_windows: params = ['"%s"' % self._tool_path] pwdfile = tempfile.NamedTemporaryFile(delete=False, suffix=".cnf") pwdfilename = pwdfile.name tmpdir = None else: params = [self._tool_path] # use a pipe to feed the password to the client tmpdir = tempfile.mkdtemp() pwdfilename = os.path.join(tmpdir, 'extraparams.cnf') os.mkfifo(pwdfilename) params.append('--defaults-extra-file=' + pwdfilename) if default_charset: params.append("--default-character-set=%s" % default_charset) params += self._connection_params params += self._extra_params if default_schema: params.append(default_schema) cmdstr = " ".join(params) workdir = os.path.dirname(path) log_info("Feeding data from %s to %s (cwd=%s)\n" % (path, cmdstr, workdir)) p1 = None try: self.report_progress("Preparing...", None, None) if not is_windows: try: p1 = subprocess.Popen(params, cwd=workdir, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) except OSError, exc: log_error("Error executing command %s\n%s\n" % (" ".join(params), exc)) raise RuntimeError("Error executing %s:\n%s" % (" ".join(params), str(exc))) # in !Windows feed password to client after it's started (otherwise the fifo would block on open for writing) pwdfile = open(pwdfilename, 'w') pwdfile.write('[client]\npassword='******'' pwdfile.write(self._password.replace("\\", "\\\\")) pwdfile.write('\n') pwdfile.close() if is_windows: try: info = subprocess.STARTUPINFO() info.dwFlags |= _subprocess.STARTF_USESHOWWINDOW info.wShowWindow = _subprocess.SW_HIDE # Command line can contain object names in case of export and filename in case of import # Object names must be in utf-8 but filename must be encoded in the filesystem encoding, # which probably isn't utf-8 in windows. fse = sys.getfilesystemencoding() cmd = cmdstr.encode(fse) if isinstance(cmdstr, unicode) else cmdstr log_debug("Executing command: %s\n" % cmdstr) p1 = subprocess.Popen(cmd, cwd=workdir, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=info, shell=cmdstr[0] != '"') except OSError, exc: log_error("Error executing command %s\n%s\n" % (cmdstr, exc)) import traceback traceback.print_exc() raise RuntimeError("Error executing %s:\n%s" % (cmdstr, str(exc)))
import traceback traceback.print_exc() else: try: info = subprocess.STARTUPINFO() info.dwFlags |= _subprocess.STARTF_USESHOWWINDOW info.wShowWindow = _subprocess.SW_HIDE # Command line can contain object names in case of export and filename in case of import # Object names must be in utf-8 but filename must be encoded in the filesystem encoding, # which probably isn't utf-8 in windows. if isinstance(cmd, list): for idx, item in enumerate(cmd): cmd[idx] = item.encode("utf8") if isinstance( item, unicode) else item log_debug("Executing command: %s\n" % "".join(cmd)) else: cmd = cmd.encode("utf8") if isinstance(cmd, unicode) else cmd log_debug("Executing command: %s\n" % cmd) p1 = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=info, shell=True) except OSError, exc: log_error("Error executing command %s\n%s\n" % (cmd, exc)) import traceback traceback.print_exc() p1 = None return p1
p1 = subprocess.Popen("exec " + cmd, stdout = subprocess.PIPE, stderr=subprocess.PIPE, shell = True) except OSError, exc: log_error("Error executing command %s\n%s\n" % (cmd, exc)); import traceback traceback.print_ext() else: try: info = subprocess.STARTUPINFO() info.dwFlags |= _subprocess.STARTF_USESHOWWINDOW info.wShowWindow = _subprocess.SW_HIDE # Command line can contain object names in case of export and filename in case of import # Object names must be in utf-8 but filename must be encoded in the filesystem encoding, # which probably isn't utf-8 in windows. cmd = cmd.encode("utf8") if isinstance(cmd,unicode) else cmd log_debug("Executing command: %s\n" % cmd) p1 = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE,startupinfo=info,shell=True) except OSError, exc: log_error("Error executing command %s\n%s\n" % (cmd, exc)) import traceback traceback.print_exc() p1 = None return p1 class SpatialImporter: def __init__(self): self.import_table = None self.selected_fields = None self.process_handle = None self.import_overwrite = False self.import_append = False
log_error("Error executing command %s\n%s\n" % (cmd, exc)); import traceback traceback.print_exc() else: try: info = subprocess.STARTUPINFO() info.dwFlags |= _subprocess.STARTF_USESHOWWINDOW info.wShowWindow = _subprocess.SW_HIDE # Command line can contain object names in case of export and filename in case of import # Object names must be in utf-8 but filename must be encoded in the filesystem encoding, # which probably isn't utf-8 in windows. if isinstance(cmd, list): for idx,item in enumerate(cmd): cmd[idx] = item.encode("utf8") if isinstance(item,unicode) else item log_debug("Executing command: %s\n" % "".join(cmd)) else: cmd = cmd.encode("utf8") if isinstance(cmd,unicode) else cmd log_debug("Executing command: %s\n" % cmd) p1 = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=info, shell = True) except OSError, exc: log_error("Error executing command %s\n%s\n" % (cmd, exc)) import traceback traceback.print_exc() p1 = None return p1 class SpatialImporter: def __init__(self): self.import_table = None self.selected_fields = None
def import_script(self, path, default_schema=None, default_charset="utf8"): if not self._tool_path: raise RuntimeError("mysql command line client not found. Please fix its path in Preferences -> Administration") is_windows = platform.system() == 'Windows' if is_windows: params = ['"%s"' % self._tool_path] pwdfile = tempfile.NamedTemporaryFile(delete=False, suffix=".cnf") pwdfilename = pwdfile.name tmpdir = None else: params = [self._tool_path] # use a pipe to feed the password to the client tmpdir = tempfile.mkdtemp() pwdfilename = os.path.join(tmpdir, 'extraparams.cnf') os.mkfifo(pwdfilename) params.append('--defaults-extra-file=' + pwdfilename) if default_charset: params.append("--default-character-set=%s" % default_charset) params += self._connection_params params += self._extra_params if default_schema: params.append(default_schema) cmdstr = " ".join(params) workdir = os.path.dirname(path) log_info("Feeding data from %s to %s (cwd=%s)\n" % (path, cmdstr, workdir)) p1 = None try: self.report_progress("Preparing...", None, None) if not is_windows: try: p1 = subprocess.Popen(params, cwd=workdir, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) except OSError, exc: log_error("Error executing command %s\n%s\n" % (" ".join(params), exc)) raise RuntimeError("Error executing %s:\n%s" % (" ".join(params), str(exc))) # in !Windows feed password to client after it's started (otherwise the fifo would block on open for writing) pwdfile = open(pwdfilename, 'w') pwdfile.write('[client]\npassword='******'' pwdfile.write(self._password.replace("\\", "\\\\")) pwdfile.write('\n') pwdfile.close() if is_windows: try: info = subprocess.STARTUPINFO() info.dwFlags |= _subprocess.STARTF_USESHOWWINDOW info.wShowWindow = _subprocess.SW_HIDE # Command line can contain object names in case of export and filename in case of import # Object names must be in utf-8 but filename must be encoded in the filesystem encoding, # which probably isn't utf-8 in windows. fse = sys.getfilesystemencoding() cmd = cmdstr.encode(fse) if isinstance(cmdstr, unicode) else cmdstr log_debug("Executing command: %s\n" % cmdstr) p1 = subprocess.Popen(cmd, cwd=workdir, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT,startupinfo=info, shell=cmdstr[0] != '"') except OSError, exc: log_error("Error executing command %s\n%s\n" % (cmdstr, exc)) import traceback traceback.print_exc() raise RuntimeError("Error executing %s:\n%s" % (cmdstr, str(exc)))
def get_log_destination(self): dest = {} if self.ctrl_be.is_sql_connected(): # If server is up, query the destination from there if not self.ctrl_be.target_version.is_supported_mysql_version_at_least(5,1,6): # Logging to TABLE was introduced in v5.1.6 try: result = self.ctrl_be.exec_query("SHOW VARIABLES LIKE 'log'") if not result.nextRow(): return dest except: return dest self.instance_info.log_output = 'FILE' if result.stringByName("Value")=='ON' else 'NONE' log_debug('%s: log_output = %s\n' % (self.__class__.__name__, self.instance_info.log_output) ) else: try: result = self.ctrl_be.exec_query("SHOW VARIABLES LIKE 'log_output'") if not result.nextRow(): return dest except: return dest self.instance_info.log_output = result.stringByName("Value") if 'FILE' in self.instance_info.log_output and 'TABLE' in self.instance_info.log_output: def open_remote_file(path): import wb_server_control try: ssh = self.ctrl_be.ssh.WbAdminSSH() ssh.wrapped_connect(self.server_profile, wb_server_control.PasswordHandler(self.server_profile)) if ssh.isConnected() == 1: ssh.open(path) ssh.close() return True except Exception: log_error("Error opening remote file: %s\n", path) return False # Can't read logs from files if admin is disabled: if not self.instance_info.admin_enabled: dest['general_log'] = 'TABLE' dest['slow_log'] = 'TABLE' log_debug('%s: log_output = %s\n' % (self.__class__.__name__, dest) ) return dest # Try to prioritize the files if they are readable if not getattr(self, 'stored_general_log_source_choice', None): if self.instance_info.general_log_file_path: try: open(self.instance_info.general_log_file_path) if self.instance_info.is_local else open_remote_file(self.instance_info.general_log_file_path) dest['general_log'] = 'FILE' except: dest['general_log'] = 'TABLE' else: dest['general_log'] = 'TABLE' self.stored_general_log_source_choice = dest['general_log'] else: dest['general_log'] = self.stored_general_log_source_choice if not getattr(self, 'stored_slow_log_source_choice', None): if self.instance_info.slow_log_file_path: try: open(self.instance_info.slow_log_file_path) if self.instance_info.is_local else open_remote_file(self.instance_info.slow_log_file_path) dest['slow_log'] = 'FILE' except: dest['slow_log'] = 'TABLE' else: dest['slow_log'] = 'TABLE' self.stored_slow_log_source_choice = dest['slow_log'] else: dest['slow_log'] = self.stored_slow_log_source_choice log_debug('%s: log_output = %s\n' % (self.__class__.__name__, dest) ) return dest
def __init__(self, ctrl_be, server_profile, running, cpu_widget): self.ctrl_be = ctrl_be self.ssh = None self.cpu = 0 self.mtx = threading.Lock() self.running = running self.cpu_widget = cpu_widget self.settings = server_profile self.remote_admin_enabled = self.settings.uses_ssh if not self.remote_admin_enabled: return self.ctrl_be.add_me_for_event("shutdown", self) #upload script. Get local name, open ftp session and upload to the directory # where mysql.ini is. self.script = None self.ssh = ctrl_be.open_ssh_session_for_monitoring() (dirpath, code) = self.ssh.exec_cmd("cmd /C echo %USERPROFILE%") # %APPDATA% is n/a for LocalService # which is a user sshd can be run dirpath = dirpath.strip(" \r\t\n") if code == 0 and dirpath is not None and dirpath != "%USERPROFILE%": script_path = App.get().get_resource_path("mysql_system_status_rmt.vbs") filename = "\"" + dirpath + "\\mysql_system_status_rmt.vbs\"" log_debug('Script local path is "%s". Will be uploaded to "%s"\n' % (script_path, filename) ) if script_path is not None and script_path != "": #print "Uploading file to ", filename try: f = open(script_path) self.ssh.exec_cmd("cmd /C echo. > " + filename) maxsize = 1800 cmd = "" for line in f: line = line.strip("\r\n") tline = line.strip(" \t") if len(tline) > 0: if tline[0] != "'": if len(cmd) > maxsize: self.ssh.exec_cmd("cmd /C " + cmd.strip(" &")) self.ssh.exec_cmd("cmd /C echo " + line + " >> " + filename) cmd = "" else: cmd += "echo " + line + " >> " + filename cmd += " && " if len(cmd) > 0: self.ssh.exec_cmd("cmd /C " + cmd.strip(" &")) cmd = "" self.script = "cscript //NoLogo " + filename + " /DoStdIn" #run ssh in a thread log_debug2('About to run "%s"\n' % self.script) self.chan = None self.out = "" self.read_thread = threading.Thread(target=self.ssh.exec_cmd, args=(self.script, Users.CURRENT, None, self.reader, 1, self.save_channel)) self.read_thread.setDaemon(True) self.read_thread.start() except IOError, e: self.ssh.close() self.ssh = None raise e
def migrationUpdate(self): if hasattr(self.migrationSource.migration, 'migrateUpdateForChanges'): self.migrationTarget.catalog = self.migrationSource.migration.migrateUpdateForChanges(self.state, self.migrationTarget.catalog) else: log_debug('migrateUpdateForChanges method call was skipped for module %s\n' % self.migrationSource.migration.__name__)
def testInstanceSettingByName(what, connection, server_instance): global test_ssh_connection log_debug("Test %s in %s\n" % (what, connection.name)) profile = ServerProfile(connection, server_instance) if what == "connect_to_host": if test_ssh_connection: test_ssh_connection = None log_info("Instance test: Connecting to %s\n" % profile.ssh_hostname) try: test_ssh_connection = wb_admin_control.WbAdminControl( profile, None, connect_sql=False, test_only=True) test_ssh_connection.init() grt.send_info("connected.") except Exception as exc: log_error("Exception: %s\n" % str(exc)) import traceback log_debug2("Backtrace was: ", traceback.format_stack()) return "ERROR " + str(exc) except: return "ERROR" try: test_ssh_connection.acquire_admin_access() except Exception as exc: log_error("Exception: %s\n" % str(exc)) import traceback log_debug2("Backtrace was: " % traceback.format_stack()) return "ERROR " + str(exc) os_info = test_ssh_connection.detect_operating_system_version() if os_info: os_type, os_name, os_variant, os_version = os_info log_info("Instance test: detected remote OS: %s (%s), %s, %s\n" % (os_info)) # check if the admin access error was because of wrong OS set if os_type != profile.target_os: return "ERROR Wrong Remote OS configured for connection. Set to %s, but was detected as %s" % ( profile.target_os, os_type) else: log_warning( "Instance test: could not determine OS version information\n") return "ERROR Could not determine remote OS details" return "OK" elif what == "disconnect": if test_ssh_connection: test_ssh_connection = None return "OK" elif what == "check_privileges": return "ERROR" elif what in ("find_config_file", "check_config_path", "check_config_section"): config_file = profile.config_file_path print("Check if %s exists in remote host" % config_file) try: if not test_ssh_connection.ssh.fileExists(config_file): return "ERROR File %s doesn't exist" % config_file else: print("File was found in expected location") except IOError: return 'ERROR Could not verify the existence of the file %s' % config_file if what == "check_config_path": return "OK" section = profile.config_file_section cfg_file_content = "" print("Check if %s section exists in %s" % (section, config_file)) try: #local_file = test_ssh_connection.fetch_file(config_file) cfg_file_content = test_ssh_connection.server_helper.get_file_content( path=config_file) except Exception as exc: import traceback traceback.print_exc() return "ERROR " + str(exc) if ("[" + section + "]") in cfg_file_content: return "OK" return "ERROR Couldn't find section %s in the remote config file %s" % ( section, config_file) elif what in ("find_config_file/local", "check_config_path/local", "check_config_section/local"): config_file = profile.config_file_path config_file = wb_admin_control.WbAdminControl( profile, None, connect_sql=False).expand_path_variables(config_file) print("Check if %s can be accessed" % config_file) if os.path.exists(config_file): print("File was found at the expected location") else: return "ERROR File %s doesn't exist" % config_file if what == "check_config_path/local": return "OK" section = profile.config_file_section print("Check if section for instance %s exists in %s" % (section, config_file)) if check_if_config_file_has_section(open(config_file, "r"), section): print("[%s] section found in configuration file" % section) return "OK" return "ERROR Couldn't find section [%s] in the config file %s" % ( section, config_file) elif what == "find_error_files": return "ERROR" elif what == "check_admin_commands": path = profile.start_server_cmd cmd_start = None if path.startswith("/"): cmd_start = path.split()[0] if not test_ssh_connection.ssh.fileExists(cmd_start): return "ERROR %s is invalid" % path path = profile.stop_server_cmd if path.startswith("/"): cmd = path.split()[0] if cmd != cmd_start and not test_ssh_connection.ssh.fileExists( cmd): return "ERROR %s is invalid" % path return "OK" elif what == "check_admin_commands/local": path = profile.start_server_cmd cmd_start = None if path.startswith("/"): cmd_start = path.split()[0] if not os.path.exists(cmd_start): return "ERROR %s is invalid" % path path = profile.stop_server_cmd if path.startswith("/"): cmd = path.split()[0] if cmd != cmd_start and not os.path.exists(cmd): return "ERROR %s is invalid" % path return "OK" return "ERROR bad command"
def __init__(self, ctrl_be, server_profile, running, cpu_widget): self.ctrl_be = ctrl_be self.ssh = None self.cpu = 0 self.mtx = threading.Lock() self.running = running self.cpu_widget = cpu_widget self.settings = server_profile self.remote_admin_enabled = self.settings.uses_ssh if not self.remote_admin_enabled: return self.ctrl_be.add_me_for_event("shutdown", self) #upload script. Get local name, open ftp session and upload to the directory # where mysql.ini is. self.script = None self.ssh = ctrl_be.open_ssh_session_for_monitoring() (dirpath, code) = self.ssh.exec_cmd( "cmd /C echo %USERPROFILE%") # %APPDATA% is n/a for LocalService # which is a user sshd can be run dirpath = dirpath.strip(" \r\t\n") if code == 0 and dirpath is not None and dirpath != "%USERPROFILE%": script_path = App.get().get_resource_path( "mysql_system_status_rmt.vbs") filename = "\"" + dirpath + "\\mysql_system_status_rmt.vbs\"" log_debug('Script local path is "%s". Will be uploaded to "%s"\n' % (script_path, filename)) if script_path is not None and script_path != "": #print "Uploading file to ", filename try: f = open(script_path) self.ssh.exec_cmd("cmd /C echo. > " + filename) maxsize = 1800 cmd = "" for line in f: line = line.strip("\r\n") tline = line.strip(" \t") if len(tline) > 0: if tline[0] != "'": if len(cmd) > maxsize: self.ssh.exec_cmd("cmd /C " + cmd.strip(" &")) self.ssh.exec_cmd("cmd /C echo " + line + " >> " + filename) cmd = "" else: cmd += "echo " + line + " >> " + filename cmd += " && " if len(cmd) > 0: self.ssh.exec_cmd("cmd /C " + cmd.strip(" &")) cmd = "" self.script = "cscript //NoLogo " + filename + " /DoStdIn" #run ssh in a thread log_debug2('About to run "%s"\n' % self.script) self.chan = None self.out = "" self.read_thread = threading.Thread( target=self.ssh.exec_cmd, args=(self.script, Users.CURRENT, None, self.reader, 1, self.save_channel)) self.read_thread.setDaemon(True) self.read_thread.start() except IOError, e: self.ssh.close() self.ssh = None raise e
shell=True) except OSError, exc: log_error("Error executing command %s\n%s\n" % (cmd, exc)) import traceback traceback.print_ext() else: try: info = subprocess.STARTUPINFO() info.dwFlags |= _subprocess.STARTF_USESHOWWINDOW info.wShowWindow = _subprocess.SW_HIDE # Command line can contain object names in case of export and filename in case of import # Object names must be in utf-8 but filename must be encoded in the filesystem encoding, # which probably isn't utf-8 in windows. cmd = cmd.encode("utf8") if isinstance(cmd, unicode) else cmd log_debug("Executing command: %s\n" % cmd) p1 = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, startupinfo=info, shell=True) except OSError, exc: log_error("Error executing command %s\n%s\n" % (cmd, exc)) import traceback traceback.print_exc() p1 = None return p1 class SpatialImporter:
def __init__(self, ctrl_be, server_profile, running, cpu_widget): self.ctrl_be = ctrl_be self.ssh = None self.cpu = 0 self.mtx = threading.Lock() self.running = running self.cpu_widget = cpu_widget self.settings = server_profile self.remote_admin_enabled = self.settings.uses_ssh if not self.remote_admin_enabled: return self.ctrl_be.add_me_for_event("shutdown", self) #upload script. Get local name, open ftp session and upload to the directory # where mysql.ini is. self.script = None if self.ctrl_be.server_profile.uses_ssh: if self.ctrl_be.editor.sshConnection.isConnected() == 0: if self.ctrl_be.editor.sshConnection.connect() != 0: raise OperationCancelledError("Could not connect to SSH server") self.ssh = sshConnection if self.ssh is not None: # %APPDATA% is n/a for LocalService # which is a user sshd can be run dirpath = handle_ssh_command_output(self.ssh.executeCommand("cmd /C echo %USERPROFILE%")) dirpath = dirpath.strip(" \r\t\n") if dirpath is not None and dirpath != "%USERPROFILE%": script_path = App.get().get_resource_path("mysql_system_status_rmt.vbs") filename = "\"" + dirpath + "\\mysql_system_status_rmt.vbs\"" log_debug('Script local path is "%s". Will be uploaded to "%s"\n' % (script_path, filename) ) if script_path is not None and script_path != "": #print "Uploading file to ", filename try: f = open(script_path) handle_ssh_command_output(self.ssh.executeCommand("cmd /C echo. > " + filename)) maxsize = 1800 cmd = "" for line in f: line = line.strip("\r\n") tline = line.strip(" \t") if len(tline) > 0: if tline[0] != "'": if len(cmd) > maxsize: handle_ssh_command_output(self.ssh.executeCommand("cmd /C " + cmd.strip(" &"))) handle_ssh_command_output(self.ssh.executeCommand("cmd /C echo " + line + " >> " + filename)) cmd = "" else: cmd += "echo " + line + " >> " + filename cmd += " && " if len(cmd) > 0: handle_ssh_command_output(self.ssh.executeCommand("cmd /C " + cmd.strip(" &"))) cmd = "" self.script = "cscript //NoLogo " + filename + " /DoStdIn" #run ssh in a thread log_debug2('About to run "%s"\n' % self.script) self.chan = None self.out = "" self.read_thread = threading.Thread(target=self.ssh.executeCommand, args=(self.script, Users.CURRENT, None, self.reader, 1, self.save_channel)) self.read_thread.setDaemon(True) self.read_thread.start() except IOError as e: self.ssh.disconnect() self.ssh = None raise e else: print("Can't find a place to upload script dirpath='%s'"%dirpath)
(self._server[0], self._server[1])) break # Time to shutdown: for sock, chan in self._connections: try: sock.close() except: pass try: chan.close() except: pass self._listen_sock.close() self._client.close() log_debug("Leaving tunnel thread %s\n" % self.local_port) def notify(self, msg_type, msg_object): log_debug2("tunnel_%i: %s %s\n" % (self.local_port, msg_type, msg_object)) self.q.put((msg_type, msg_object)) def notify_exception_error(self, msg_type, msg_txt, msg_obj=None): self.notify(msg_type, msg_txt) log_error("%s\n" % traceback.format_exc()) def match(self, server, username, target): with self.lock: return self._server == server and self._username == username and self._target == target def _get_ssh_config_path(self):
self.notify('INFO', 'Closing tunnel to %s:%s for inactivity...' % (self._server[0], self._server[1]) ) break # Time to shutdown: for sock, chan in self._connections: try: sock.close() except: pass try: chan.close() except: pass self._listen_sock.close() self._client.close() log_debug("Leaving tunnel thread %s\n" % self.local_port) def notify(self, msg_type, msg_object): log_debug2("tunnel_%i: %s %s\n" % (self.local_port, msg_type, msg_object)) self.q.put((msg_type, msg_object)) def notify_exception_error(self, msg_type, msg_txt, msg_obj = None): self.notify(msg_type, msg_txt) log_error("%s\n" % traceback.format_exc()) def match(self, server, username, target): with self.lock: return self._server == server and self._username == username and self._target == target def _get_ssh_config_path(self):