You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
8.4 KiB
252 lines
8.4 KiB
# -*- 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 |
|
|
|
|