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.
253 lines
8.4 KiB
253 lines
8.4 KiB
|
13 years ago
|
# -*- 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
|
||
|
|
|