# -*- coding: utf-8 -*- # # vim:syntax=python:sw=4:ts=4:expandtab # synctools.py # # Copyright (C) Adelux - 2009 # """ OpenVPNConsole synctools module : Synchronisation tools used to copy openvpn configuration to non-local servers """ import os import subprocess import paramiko import traceback import sys import re class OVPNServerSync: """ Object used to manage distant server Sets some default values """ def __init__(self, hostname, login, password, port=22): """ construct object properties """ self.hostname = hostname self.login = login self.password = password self.dst_dir = '/tmp/test_copy' self.copy_method = 'ssh' self.source_dir = None self.port = port self.ssh_handle = None def sync(self): """ connects to server, and copy files """ # if source_dir is not set, returns if self.source_dir is None: raise SourceDirError("Source dir %s not defined" % self.source_dir) # if source_dir does not exist, return if not os.path.exists(self.source_dir): raise SourceDirError("Source dir %s does not exist" % self.source_dir) # create connection return self._copy_source(self.copy_method) # Private methods def _copy_source(self, method): """ copy files to server, depending on method """ output = '' if self.copy_method is 'ssh': # get host key hostkeytype = None hostkey = None try: host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts')) except IOError: try: host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts')) except IOError: #output += '*** Unable to open host keys file, continuing anyway\n' host_keys = {} # try to connect by ssh and use paramiko Transport to negotiate SSH2 across the connection try: t = paramiko.Transport((self.hostname, self.port)) t.connect(username=self.login, password=self.password, hostkey=hostkey) sftp = paramiko.SFTPClient.from_transport(t) # copy directory onto the server # go into source_dir and walk in each subdirectory pwd = os.getcwd() os.chdir(self.source_dir) # try to create dst_dir try: output += 'creating directory %s \n' % self.dst_dir sftp.mkdir(self.dst_dir) except IOError: output += '(assuming %s already exists) \n' % self.dst_dir for (root, dirs, files) in os.walk('.'): # if dirs not empty, create sub directory if dirs is not None: for dir in dirs: dst = os.path.normpath(os.path.join(self.dst_dir, root, dir)) try: output += 'creating directory %s \n' % dst sftp.mkdir(dst) except IOError: output += '(assuming %s already exists) \n' % dst # copy each file in distant directory if files is not None: for file in files: src = os.path.normpath(os.path.join(root, file)) dst = os.path.normpath(os.path.join(self.dst_dir, root, file)) try: output += 'copying file %s to %s \n' % (src, dst) sftp.put(src, dst) except IOError: output += '(error during copy) \n' t.close() # change the path again os.chdir(pwd) except Exception, e: output += '*** Caught exception: %s: %s' % (e.__class__, e) traceback.print_exc() try: t.close() except: pass sys.exit(1) else: raise ConnectionError("Method %s is not supported by module" % self.copy_method) output += 'Finished \n' return output def __del__(self): pass class OVPNServerAdmin: """ allows start, stop, restart, reload, status functions to manage local or distant openvpn server """ def __init__(self): self.server_type = 'local' self.init_script = '/etc/init.d/openvpn' self.hostname = 'localhost' self.login = 'user' self.password = 'password' self.cmd_prefix = None # public methods def start_server(self): """ function returns three values : return code, stdout, and sterr """ if self.cmd_prefix is not None: (retcmd, stdout, stderr) = self._shell_cmd(self.cmd_prefix + ' ' + self.init_script + ' ' + 'start', self.server_type) else: (retcmd, stdout, stderr) = self._shell_cmd(self.init_script + ' ' + 'start', self.server_type) output = [] output.append(str(retcmd)) output.append(''.join(stdout) + '\n') output.append(''.join(stderr) + '\n') return output def stop_server(self): """ function returns three values : return code, stdout, and sterr """ if self.cmd_prefix is not None: (retcmd, stdout, stderr) = self._shell_cmd(self.cmd_prefix + ' ' + self.init_script + ' ' + 'stop', self.server_type) else: (retcmd, stdout, stderr) = self._shell_cmd(self.init_script + ' ' + 'stop', self.server_type) output = [] output.append(str(retcmd)) output.append(''.join(stdout) + '\n') output.append(''.join(stderr) + '\n') return output def restart_server(self, server_name = ''): """ function returns three values : return code, stdout, and sterr """ if self.cmd_prefix is not None: (retcmd, stdout, stderr) = self._shell_cmd(self.cmd_prefix + ' ' + self.init_script + ' ' + 'restart ' + server_name, self.server_type) else: (retcmd, stdout, stderr) = self._shell_cmd(self.init_script + ' ' + 'restart ' + server_name, self.server_type) output = [] output.append(str(retcmd)) output.append(''.join(stdout) + '\n') output.append(''.join(stderr) + '\n') return output def reload_server(self): """ function returns three values : return code, stdout, and sterr """ if self.cmd_prefix is not None: (retcmd, stdout, stderr) = self._shell_cmd(self.cmd_prefix + ' ' + self.init_script + ' ' + 'reload', self.server_type) else: (retcmd, stdout, stderr) = self._shell_cmd(self.init_script + ' ' + 'reload', self.server_type) output = [] output.append(str(retcmd)) output.append(''.join(stdout) + '\n') output.append(''.join(stderr) + '\n') return output def get_connected_users(self,status_file): """ function returns three values : return code, stdout, and sterr """ if self.cmd_prefix is not None: (retcmd, stdout, stderr) = self._shell_cmd(self.cmd_prefix + 'cat ' + status_file, self.server_type) else: (retcmd, stdout, stderr) = self._shell_cmd('cat ' + status_file, self.server_type) user_list = [] if retcmd == 0 and stdout is not None : for line in stdout: p = re.search("^CLIENT_LIST,([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*)",line) if p is not None: user_list.append(p.group(1,2,3,4,5,6)) return retcmd, user_list, stderr def get_server_status(self,status_file): pass # private methods def _shell_cmd(self, cmd, connexion): """ send 'cmd' shell command to local or distant shell function returns three values : return code, stdout, and sterr if access_type is 'ssh', the method needs an additional parameter : ssh connexion object to interract with distant system """ if connexion is 'local': proc = subprocess.Popen(cmd, shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) stdout_value, stderr_value = proc.communicate() return (proc.returncode, stdout_value, stderr_value) elif connexion is 'ssh': # get host key hostkeytype = None hostkey = None # create paramiko object ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy( paramiko.AutoAddPolicy()) # connect to ssh server ssh.connect(self.hostname, username=self.login, password=self.password) # execute command stdin, stdout, stderr = ssh.exec_command(cmd) output = stdout.readlines() err = stderr.readlines() if err: retcode = -1 else: retcode = 0 # close connexion ssh.close() return (retcode, output, err) ## Additional functions class SourceDirError(Exception): pass class ConnectionError(Exception): pass