I have a database that I want to back up with my a python code.
I tried to base my code from the code in this discussion that uses the subprocess module and pg_dump. My problem now is that I have to manually type in the password to get the backup file. I read somewhere that doing a .pgpass but I do want to see if it is possible to do it within the subprocess module.
My code follows below:
from subprocess import Popen, PIPE
from pathlib import Path, PureWindowsPath
def backup():
version = 11
postgresDir = Path("C:/Program Files/PostgreSQL/{}/bin/".format(version))
directory = PureWindowsPath(postgresDir)
filename = 'myBackUp2' # output filename here
saveDir = Path("D:/Desktop/{}.tar".format(filename)) # output directory here
file = PureWindowsPath(saveDir)
host = 'localhost'
user = 'postgres'
port = '5434'
dbname = 'database_name' # database name here
proc = Popen(['pg_dump', '-h', host, '-U', user, '-W', '-p', port,
'-F', 't', '-f', str(file), '-d', dbname],
cwd=directory, shell=True, stdin=PIPE)
proc.wait()
backup()
The code above works and the backup is created is I type in the password. I tried to replace proc.wait() with the code below to remove the need of typing the password manually:
return proc.communicate('{}\n'.format(database_password))
But I would receive this error:
TypeError: a bytes-like object is required, not 'str'
Is this possible to do within subprocess? If so, how?
Use a password file.
On Microsoft Windows the file is named %APPDATA%\postgresql\pgpass.conf (where %APPDATA% refers to the Application Data subdirectory in the user's profile).
and the -w or --no-password command line option (instead of -W)
-w
--no-password
Never issue a password prompt. If the server requires password authentication and a password is not available by other means such as a .pgpass file, the connection attempt will fail. This option can be useful in batch jobs and scripts where no user is present to enter a password.
The easiest is to use the PGPASSWORD environment variable.
There is two classes:
First class needed for create dsn string. Then try to connect
with dsn parameters. If cannot connect go to Second class.
Second class needed for create for create DataBase and restore all tables
from file. You need to remake this strings:
for correctly open your DataBase dump_file
__folder_name = Path(__file__).parent.parent
__folder_name_data = os.path.join(__folder_name, 'data')
__file_to_open = os.path.join(__folder_name_data, 'bd.backup')
import os
import textwrap
from pathlib import Path
from subprocess import Popen, PIPE
class DataBaseAPI:
__slots__ = ('__dsn', 'cur')
def __init__(self):
self.__dsn = self.__dsn_string()
self.cur = self.__connection()
#staticmethod
def __dsn_string() -> dict:
print(f'INPUT name of DataBase')
name = input()
print(f'INPUT password of DataBase')
password = input()
print(f'INPUT user_name of DataBase or press ENTER if user_name="postgres"')
user_name = input()
if len(user_name) == 0:
user_name = 'postgres'
print(f'INPUT host_name of DataBase or press ENTER if host_name="localhost"')
host_name = input()
if len(host_name) == 0:
host_name = 'localhost'
return {'dbname': name, 'user': user_name, 'password': password, 'host': host_name}
def __connection(self):
try:
conn = psycopg2.connect(dbname=self.__dsn['dbname'], user=self.__dsn['user'],
host=self.__dsn['host'], password=self.__dsn['password'], port=5432)
except psycopg2.OperationalError:
print(textwrap.fill(f'There is no existing DataBase. Creating new DataBase', 80,
subsequent_indent=' '))
DataBaseCreator(self.__dsn)
conn = psycopg2.connect(dbname=self.__dsn['dbname'], user=self.__dsn['user'],
host=self.__dsn['host'], password=self.__dsn['password'], port=5432)
finally:
conn.autocommit = True
cur = conn.cursor()
print(f'DataBase connection complete')
return cur
class DataBaseCreator:
def __init__(self, dsn):
self.__dsn = dsn
self.__check_conf_file()
self.__create_data_base()
self.__restore_data_base()
def __check_conf_file(self):
__app_data = os.environ.copy()["APPDATA"]
__postgres_path = Path(f'{__app_data}\postgresql')
__pgpass_file = Path(f'{__postgres_path}\pgpass.conf')
parameters = f'{self.__dsn["host"]}:{5432}:{self.__dsn["dbname"]}:' \
f'{self.__dsn["user"]}:{int(self.__dsn["password"])}\n'
if not os.path.isdir(__postgres_path):
os.makedirs(__postgres_path)
if os.path.isfile(__pgpass_file):
log.debug(f'File "pgpass.conf" already exists')
with open(__pgpass_file, 'r+') as f:
content = f.readlines()
if parameters not in content:
# сервер: порт:база_данных: имя_пользователя:пароль
f.write(parameters)
else:
log.info(f' {parameters} already in "pgpass.conf" file')
else:
log.debug(f'File "pgpass.conf" not exists')
with open(__pgpass_file, 'x') as f:
# сервер: порт:база_данных: имя_пользователя:пароль
f.write(parameters)
def __create_data_base(self):
try:
__conn = psycopg2.connect(dbname='postgres', user=self.__dsn['user'],
host=self.__dsn['host'], password=self.__dsn['password'], port=5432)
except Exception as _:
log.exception(f'{_}')
else:
__conn.autocommit = True
__cur = __conn.cursor()
__query = f'CREATE DATABASE "{self.__dsn["dbname"]}"'
__cur.execute(__query)
log.info(f'{__query}')
def __restore_data_base(self):
__col = [x for x in self.__dsn.values()]
__folder_name = Path(__file__).parent.parent
__folder_name_data = os.path.join(__folder_name, 'data')
__file_to_open = os.path.join(__folder_name_data, 'bd.backup')
__cmd = f'pg_restore --host={__col[3]} --dbname={__col[0]} --username={__col[1]} ' \
f'--verbose=True --no-password ' \
f'{__file_to_open}'
try:
__proc = Popen(__cmd, stdout=PIPE, stderr=PIPE)
except FileNotFoundError:
log.info(f'FileNotFoundError: [WinError 2] Не удается найти указанный файл')
log.info(textwrap.fill(f'You need to SET Windows $PATH for use "pg_restore" in cmd', 80,
subsequent_indent=' '))
else:
__stderr = __proc.communicate()[1].decode('utf-8', errors="ignore").strip()
log.debug(textwrap.fill(f'{__stderr}', 80))
One more option is to use dbname parameter
'pg_dump --dbname=postgresql://{}:{}#{}:{}/{}'.format(user, password, host, port, database_name)
Related
I'm trying to customise the SFTOperator take download multiple file from a server. I know that the original SFTPOperator only allow one file at a time.
I copied the same code from source and I twerk by adding a new function called get_xml_from_source(). Please refer the code below:
def get_xml_from_source(sftp_client, remote_filepath, local_filepath, prev_execution_date, execution_date):
"""
Copy from Source to local path
"""
files_attr = sftp_client.listdir_attr(remote_filepath) # eg: /source/ HITTING ERROR HERE
files_name = sftp_client.listdir(remote_filepath) # eg: /source/
today_midnight = datetime.combine(datetime.today(), time.min)
yesterday_midnight = today_midnight - timedelta(days=1)
for file_attr, file_name in zip(files_attr, files_name):
modified_time = datetime.fromtimestamp(file_attr.st_mtime)
if yesterday_midnight <= modified_time < today_midnight:
# if prev_execution_date <= modified_time < execution_date:
try:
# Download to local path
sftp_client.get(remote_filepath, local_filepath)
print(file_name)
except: # pylint: disable=bare-except
print("File not found")
else:
print("Not the file!")
Where this function will only download files from yesterday up to today.
I added the function at this line:
with self.ssh_hook.get_conn() as ssh_client:
sftp_client = ssh_client.open_sftp()
if self.operation.lower() == SFTPOperation.GET:
local_folder = os.path.dirname(self.local_filepath)
if self.create_intermediate_dirs:
# Create Intermediate Directories if it doesn't exist
try:
os.makedirs(local_folder)
except OSError:
if not os.path.isdir(local_folder):
raise
file_msg = "from {0} to {1}".format(self.remote_filepath,
self.local_filepath)
self.log.info("Starting to transfer %s", file_msg)
# This is where it starts to copy, customization begins here
# sftp_client.get(self.remote_filepath, self.local_filepath) <--- Original code that I commented out and replace with mine below
get_xml_from_source(sftp_client, self.remote_filepath,
self.local_filepath, self.prev_execution_date, self.execution_date)
Note that, rest of the codes did not change. It is how it looks like in the source.
I keep hitting error at files_attr = sftp_client.listdir_attr(remote_filepath) with this error:
Error while transferring from /source/ to
/path/to/destination, error: [Errno 2] No such file.
Which obviously meant, it can't find the sftp directory. I tried running the whole function locally, it works fine.
Is there any part of the code that tied the paramiko connection to only get one file? I checked the paramiko connection for SFTPOperator, it should be just fine. In this case, how should I fix it?
This is how I established my connection when running locally :
def connect_to_source():
"""
Get source credentials
:param: None
:return: username & password
"""
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
username, password = get_eet_credentials()
# key = paramiko.RSAKey.from_private_key_file(openssh_key, password=password)
ssh.connect(hostname=SFTP_SERVER, port=SFTP_PORT_NUMBER,
username=username, password=password)
client = ssh.open_sftp()
print("Connection to source success!")
return client
Lastly, below is my airflow task:
def copy_from_source():
"""
Copy XML file from source to local path
"""
return SFTPOperator(
task_id="copy_from_source",
ssh_conn_id="source_conn",
local_filepath=f"{current_dir}/destination",
remote_filepath= "/source/",
prev_execution_date='{{ prev_execution_date }}',
execution_date='{{ execution_date }}', # strftime("%Y-%m-%d %H:%M:%S")
create_intermediate_dirs=True,
operation="get",
dag=dag
)
I'm trying to do something similar to you. I'm not sure what is causing the issues you are facing but this is the updated SFTP Operator I have written that gets multiple files from a server
sftp_get_multiple_files_operator.py
import os
from pathlib import Path
from typing import Any
from airflow.exceptions import AirflowException
from airflow.models import BaseOperator
from airflow.contrib.hooks import SSHHook
class SFTPGetMultipleFilesOperator(BaseOperator):
template_fields = ('local_directory', 'remote_filename_pattern', 'remote_host')
def __init__(
self,
*,
ssh_hook=None,
ssh_conn_id=None,
remote_host=None,
local_directory=None,
remote_filename_pattern=None,
filetype=None,
confirm=True,
create_intermediate_dirs=False,
**kwargs,
) -> None:
super().__init__(**kwargs)
self.ssh_hook = ssh_hook
self.ssh_conn_id = ssh_conn_id
self.remote_host = remote_host
self.local_directory = local_directory
self.filetype = filetype
self.remote_filename_pattern = remote_filename_pattern
self.confirm = confirm
self.create_intermediate_dirs = create_intermediate_dirs
def execute(self, context: Any) -> str:
file_msg = None
try:
if self.ssh_conn_id:
if self.ssh_hook and isinstance(self.ssh_hook, SSHHook):
self.log.info("ssh_conn_id is ignored when ssh_hook is provided.")
else:
self.log.info(
"ssh_hook is not provided or invalid. Trying ssh_conn_id to create SSHHook."
)
self.ssh_hook = SSHHook(ssh_conn_id=self.ssh_conn_id)
if not self.ssh_hook:
raise AirflowException("Cannot operate without ssh_hook or ssh_conn_id.")
if self.remote_host is not None:
self.log.info(
"remote_host is provided explicitly. "
"It will replace the remote_host which was defined "
"in ssh_hook or predefined in connection of ssh_conn_id."
)
self.ssh_hook.remote_host = self.remote_host
with self.ssh_hook.get_conn() as ssh_client:
sftp_client = ssh_client.open_sftp()
all_files = sftp_client.listdir()
self.log.info(f'Found {len(all_files)} files on server')
timestamp = context['ds_nodash']
filename_pattern = self.remote_filename_pattern + timestamp
# fetch all CSV files for the run date that match the filename pattern
matching_files = [f for f in all_files
if f.find(filename_pattern) != -1]
# if file type is specified filter matching files for the file type
if self.filetype is not None:
matching_files = [filename for filename in matching_files
if filename[-len(self.filetype):] == self.filetype]
self.log.info(f'Found {len(matching_files)} files with name including {filename_pattern}')
local_folder = os.path.dirname(self.local_directory)
if self.create_intermediate_dirs:
Path(local_folder).mkdir(parents=True, exist_ok=True)
for f in matching_files:
self.log.info(f"Starting to transfer from /{f} to {self.local_directory}/{f}")
sftp_client.get(f'/{f}', f'{self.local_directory}/{f}')
except Exception as e:
raise AirflowException(f"Error while transferring {file_msg}, error: {str(e)}")
return self.local_directory
def _make_intermediate_dirs(sftp_client, remote_directory) -> None:
"""
Create all the intermediate directories in a remote host
:param sftp_client: A Paramiko SFTP client.
:param remote_directory: Absolute Path of the directory containing the file
:return:
"""
if remote_directory == '/':
sftp_client.chdir('/')
return
if remote_directory == '':
return
try:
sftp_client.chdir(remote_directory)
except OSError:
dirname, basename = os.path.split(remote_directory.rstrip('/'))
_make_intermediate_dirs(sftp_client, dirname)
sftp_client.mkdir(basename)
sftp_client.chdir(basename)
return
dag.py
sftp_report = SFTPGetMultipleFilesOperator(
task_id=f"sftp_reports_to_gcs",
ssh_conn_id="sftp_connection",
local_directory=f'/opt/airflow/dags/reports',
remote_filename_pattern=f'reportname_', # ds_nodash is added in the operator by accessing Airflow context
create_intermediate_dirs=True,
filetype='.csv'
)
I'm trying to connect and to read data in a MongoDB database, to learn Python. I'm using Pymongo and I have this error :
Traceback (most recent call last):
File "secondtest.py", line 107, in <module>
user_info = dbco.find({})
TypeError: expected a character buffer object
This is my database.ini :
[postgresql]
host=monhostname
database=monpass
port=15000
user=monuser
password=monpass
[mongodb]
hostname=127.0.0.1
database=Mydatabase
username=Myname
password=Myn#me!
collection=measure
port=27017
And my code using it :
# -*- coding: utf-8 -*-
# secondtest.py
import psycopg2
import sys
import pymongo
from urllib import quote_plus
from pymongo import MongoClient
from configparser import ConfigParser
# Connection information in database.ini
params = ''
mongollection = ''
# Variables to connect to a database, to use a cursor object and to fetch all results from a query
mongoClient = ''
pgsqlClient = ''
pgsqlCursor = ''
pgsqlRecords = ''
mongoRecords = ''
dbco = ''
# Retrieve connection information from ini file
def dbConfig(section, filename='database.ini'):
# Create a parser
parser = ConfigParser()
# Read config file
parser.read(filename)
# Get section, depending on the database engine
db = {}
if parser.has_section(section):
params = parser.items(section)
for param in params:
db[param[0]] = param[1]
else:
raise Exception('Section {0} not found in the {1} file'.format(section, filename))
# Return data or directly as a string
if section == 'postgresql':
return db
elif section == 'mongodb':
host = ''
username = ''
passwd = ''
port = ''
dbmongo = ''
connectstring = ''
# Make a string to connect to MongoDB
for key, value in db.iteritems():
if key == 'hostname':
host = value.encode("utf-8")
elif key == 'username':
username = value
elif key == 'password':
passwd = value
elif key == 'database':
dbmongo = value
elif key == 'collection':
mongollection = value
elif key == 'port':
port = value
connectstring = "mongodb://" + username + ":" + quote_plus(passwd) + "#" + host + ":" + port
print("Internal test = " + connectstring)
return connectstring.encode('iso-8859-1')
# Connection to MongoDB
def connectToMongoDb():
# The f-string is only available in Python >= 3.6
params = dbConfig('mongodb')
print("Parameters : " + params)
mongoClient = MongoClient(params)
try:
# print("Connection to database")
dbco = mongoClient.mongollection
print("Here")
print("Test dbco : " + dbco)
print("Connected to MongoDB !")
return dbco
except:
return "Error : can't connect to MongoDB !"
# Close MongoDB connection
def closeMongoDbConnection():
# try:
mongoClient.close()
return 'Connection closed'
# except:
# return "Can't close the connection. See if you already had one or if you didn't mispell its name."
# Make a query in MongoDB
def mongoDbQuery():
#mongocursor = mongoClient.mongollection.find()
#for document in cursor:
#print(document)
mongoClient.database_names()
if __name__ == '__main__':
dataconnect = connectToMongoDb()
print("Connection\n")
#mongoDbQuery()
#collec = mongoClient.measure
user_info = dbco.find({})
print(user_info)
print(closeMongoDbConnection())
Could you help me with this problem ? I think quote_plus() or even dbco = mongoClient.mongollection is what makes this error occurs. But I'm not 100% sure and I don't see, even with the documentation, how could I resolve this.
Thank you.
I'm reading your code. I see in the beginning of the program, you create the dbco variable to point to an empty string:
dbco = ''
following after that, I see you define a couple functions, then you call find() on that string:
user_info = dbco.find({})
You're passing {} (empty dict) as parameter to the method... but as you can see in the documentation here, this method needs another string as first parameter. That causes the error you see.
Now I'm not entirely sure how to fix it because I don't know what you mean. Maybe you mean to use the dataconnect variable, since that is the one that gets the results of the connectToMongoDb function:
dataconnect = connectToMongoDb()
I made it again and changed some little things. Now, it works. Here is the code, for people who'd need it in the future.
import sys
import pymongo
from urllib import quote_plus
from pymongo import MongoClient
from configparser import ConfigParser
client = MongoClient()
connected = ''
# Retrieve connection information from ini file
def dbConfig(section, filename='database.ini'):
# Keep result in global variable when the function is finished
global client
# Create a parser
parser = ConfigParser()
# Read config file
parser.read(filename)
# Get section, depending on the database engine
db = {}
if parser.has_section(section):
params = parser.items(section)
for param in params:
db[param[0]] = param[1]
else:
raise Exception('Section {0} not found in the {1} file'.format(section, filename))
# Return data or directly as a string
if section == 'postgresql':
return db
elif section == 'mongodb':
# Variables for the connection
host = ''
username = ''
passwd = ''
port = ''
connectstring = ''
# Make a string to connect to MongoDB
for key, value in db.iteritems():
if key == 'hostname':
host = value.encode("utf-8")
elif key == 'username':
username = value
elif key == 'password':
passwd = value
elif key == 'database':
dbmongo = value
elif key == 'collection':
mongollection = value
elif key == 'port':
port = value
# Make the URI needed for the connection to Mongo DB
passwing = "mongodb://" + username + ":" + quote_plus(passwd) + "#" + host + ":" + port
client = MongoClient(passwing)
return client
# Close MongoDB connection
def closeMongoDbConnection():
# Try to close the connection to Mongo DB
try:
client.close()
return 'Connection closed'
except:
return "Can't close the connection. See if you already had one or if you didn't mispell its name."
# Connection to MongoDB
def connectToMongoDb(mydb):
db = client.get_database(mydb)
return db.measure
# Make a query in MongoDB
def mongoDbQuery():
docs = connected.find().count()
#for document in docs:
#print(document)
print(docs)
if __name__ == '__main__':
connected = connectToMongoDb('neocampus')
#docs = connected.find()
# print(test)
#for document in docs:
#print(document)
mongoDbQuery()
# Show if the connection to Mongo DB is a success or not
print(closeMongoDbConnection())
The problems were :
- about global variables in and out of functions
- the database variable empty (because of that)
- a first call of MongoClient()
I have a requirement to log into multiple devices,run multiple commands and store the output.I am currently achieving this using paramiko for remote SSH and then storing the results in an excel sheet using xlswriter. This is the code that I currently have :
import getpass
import paramiko
import xlsxwriter
username = raw_input('Enter username for device login:')
def enterPassword():
while True: # repeat forever
password = getpass.getpass('Enter corresponding password:')
password_again = getpass.getpass('Confirm password:')
if password != password_again:
print 'Password and confirmation do not match.Please try again!!'
else:
return password
password = enterPassword()
print "Running the tests..this might take some time.."
# Opens file in read mode
f1 = open('hostnames','r')
f2 = open('commandlist','r')
# Creates list based on f1
devices = f1.readlines()
commands = f2.readlines()
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
data = []
for device in devices:
column = device.split()
data.append([column[0]])
print column[0]
for command in commands:
try:
conn=ssh.connect(column[1], username=username, password=password, timeout=4)
if conn is None:
stdin, stdout, stderr = ssh.exec_command(command)
data[-1].append(stdout.read())
ssh.close()
except paramiko.AuthenticationException:
output = "Authentication Failed"
data[-1].append(output)
break
except paramiko.SSHException:
output = "Issues with SSH service"
data[-1].append(output)
break
except socket.error, e:
output = "Connection Error"
data[-1].append(output)
break
data[-1] = tuple(data[-1])
f1.close()
f2.close()
book = xlsxwriter.Workbook('finalresults.xlsx')
sheet = book.add_worksheet('sheet1')
for row, data_in_row in enumerate(data):
for col, text in enumerate(data_in_row):
sheet.write(row + 1, col, text)
book.close()
This works perfectly fine on remote machines running bash and I get just the output of the commands that I run.However,on certain machines that don't run bash,I get the command run and extra prompts in the output as follows:
How do I strip the first line and the last two lines from the stdout.read() for each command within the loop.I have heard of using grep with subprocess but was looking for inbuilt python string operators
EDIT:
So I did a bit more reading,trolled a few sites and this is what I have :
data = []
offending = [">"]
for device in devices:
column = device.split()
data.append([column[0]])
print column[0]
for command in commands:
try:
conn=ssh.connect(column[1], username=username, password=password, timeout=4)
if conn is None:
stdin, stdout, stderr = ssh.exec_command(command)
for line in stdout.readline():
if not True in [item in line for item in offending]:
output = line
data[-1].append(output)
ssh.close()
However,now I have blank cells.I tried this on the command line interpreter and it worked fine.What could be wrong ??
Ok..so after a bit more research and trial and error,this snippet of code works:
data = []
for device in devices:
column = device.split()
data.append([column[0]])
print column[0]
for command in commands:
try:
conn=ssh.connect(column[1], username=username, password=password, timeout=4)
if conn is None:
stdin, stdout, stderr = ssh.exec_command(command)
output = '\n'.join(item for item in stdout.read().splitlines() if '>' not in item)
data[-1].append(output)
ssh.close()
Hi Im trying to write a Python script to SSH into a remote server and execute a mysqldump. My method so far was to establish portforwarding then run a backup script I already had written. I suspect the issue is in the portforwarding as the backup script is pretty straightforward. Here is the portforwarding:
import getpass
import os
import socket
import select
import SocketServer
import sys
import paramiko
username = 'myusername'
remote_server = 'remote.servername'
remote_port = 3306
local_server = '127.0.0.1'
local_port = 3307
SSH_PORT = 22
password = None
keyfile = 'hosting.pem'
g_verbose = True
class ForwardServer (SocketServer.ThreadingTCPServer):
daemon_threads = True
allow_reuse_address = True
class Handler (SocketServer.BaseRequestHandler):
def handle(self):
try:
chan = self.ssh_transport.open_channel('direct-tcpip',
(self.chain_host, self.chain_port),
self.request.getpeername())
except Exception, e:
verbose('Incoming request to %s:%d failed: %s' % (self.chain_host,
self.chain_port,
repr(e)))
return
if chan is None:
verbose('Incoming request to %s:%d was rejected by the SSH server.' %
(self.chain_host, self.chain_port))
return
verbose('Connected! Tunnel open %r -> %r -> %r' % (self.request.getpeername(),
chan.getpeername(), (self.chain_host, self.chain_port)))
while True:
r, w, x = select.select([self.request, chan], [], [])
if self.request in r:
data = self.request.recv(1024)
if len(data) == 0:
break
chan.send(data)
if chan in r:
data = chan.recv(1024)
if len(data) == 0:
break
self.request.send(data)
chan.close()
self.request.close()
verbose('Tunnel closed from %r' % (self.request.getpeername(),))
def forward_tunnel(local_port, remote_host, remote_port, transport):
# this is a little convoluted, but lets me configure things for the Handler
# object. (SocketServer doesn't give Handlers any way to access the outer
# server normally.)
class SubHander (Handler):
chain_host = remote_host
chain_port = remote_port
ssh_transport = transport
ForwardServer(('', local_port), SubHander).serve_forever()
def verbose(s):
if g_verbose:
print s
def pforward():
paramiko.util.log_to_file('demo.log')
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.WarningPolicy())
try:
client.connect(remote_server, SSH_PORT, username, key_filename=keyfile,
look_for_keys=True)
except Exception, e:
print '*** Failed to connect to %s:%d: %r' % (remote_server, SSH_PORT, e)
sys.exit(1)
verbose('Now forwarding port %d to %s:%d ...' % (local_port, remote_server, remote_port))
try:
forward_tunnel(local_port, remote_server, remote_port, client.get_transport())
except KeyboardInterrupt:
print 'C-c: Port forwarding stopped.'
sys.exit(0)
pforward()
Then once thats run this is my mysql backup script:
import MySQLdb
import os
conn = MySQLdb.connect (
host = "127.0.0.1",
user = "root",
passwd = "password"
port = 3307)
cursor = conn.cursor()
cursor.execute("SHOW DATABASES")
results = cursor.fetchall()
cursor.close()
conn.close()
print results
for result in results:
backupfile=result[0]+".sql.gz"
cmd="echo 'Back up "+result[0]+" database to yourLocation/"+backupfile+"'"
os.system(cmd)
cmd="mysqldump -u "+user+" -h "+host+" -p"+passwd+" --opt --routines --flush-privileges --single-transaction --database "+result[0]+" | gzip -9 --rsyncable > yourlocation/"+backupfile
this is the error that I get:
_mysql_exceptions.OperationalError: (2013, "Lost connection to MySQL server at 'waiting for initial communication packet', system error:
0")
Ok- so I guess I was over-thinking it, no need to set up port forwarding and all that mess. Here is the solution>
# -*- coding: utf-8 -*- # <nbformat>3.0</nbformat>
import paramiko
import os
savefile = 'dump.sql'
mykey = paramiko.RSAKey.from_private_key_file("/users/me/my-host.pem")
client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect('hungry.turtles.com', username = "turtles", pkey = mykey)
def ssh(cmd):
out = []
msg = [stdin, stdout, stderr] = client.exec_command(cmd)
for item in msg:
try:
for line in item:
out.append(line.strip('\n'))
except: pass
return(list(out))
dump = ssh('mysqldump -u root -ppassword turtleturds')
file = open(savefile, 'w')
file.write(str(dump))
file.close()
print 'The dump had '+ str(len(dump))+ ' lines and was saved to '+ str(os.path.realpath('dump.sql'))
I would like to retrieve multiple log files from an Ubuntu server (using Python 2.7 on win 7 machine) without having to write verbose, repetitive code. I'm sure I can use a loop to accomplish this, but I can't come up with any valid solutions (neophyte programmer). I need the direction of someone more seasoned than I. In advanced, I appreciate the help. Below is the code I'm using in my script to log into a server and retrieve one file. Below is a sample path of files I would like to retrieve at the same time:
/var/log/apache/a.log
/var/log/apache/e.log
/var/opt/smart/log/me.log
/var/opt/smart/log/se.log
I have several more paths, but I imagine you get the idea. Below is the code used to log into the server:
def do_siteserver(self, line):
import paramiko
paramiko.util.log_to_file('c:\Python27\paramiko-wininst.log')
host = '10.5.48.65'
port = 22
transport = paramiko.Transport((host,port))
while True:
try:
print '\n'
passW = raw_input("Enter the SiteServer weekly password: ")
password = passW
username = 'gilbert'
print '\n'
print 'Establishing SFTP connection to: ', host + ':' + str(port), '...'
transport.connect(username = username, password = password)
sftp = paramiko.SFTPClient.from_transport(transport)
print 'Authorization Successful!!!'
filepath = '/var/log/apache2/error.log'
localpath = 'C:\\remote\\NewFile.log'
sftp.get(filepath, localpath)
sftp.close()
transport.close()
break
except:
print '\n'
print "Authorization Failed!!!"
break
Instead of
filepath = '/var/log/apache2/error.log'
localpath = 'C:\\remote\\NewFile.log'
sftp.get(filepath, localpath)
I propose this :
log_names = {
"/var/log/apache2/error.log" : 'C:\\remote\\NewFile.log',
"/var/log/apache/a.log" : 'C:\\remote\\NewFile_a.log',
} # add here all the log files you want to retrieve
for log_file, local_name in log_names.iteritems():
sftp.get(log_file, local_name)
That ?? :
def do_siteserver(self, line):
import paramiko
host = '10.5.48.65'
port = 22
username = 'gilbert'
password = raw_input("\nEnter the SiteServer weekly password: ")
localpath = 'C:\\remote\\NewFile.log'
paramiko.util.log_to_file('c:\Python27\paramiko-wininst.log')
with open(localpath,'w') as lf:
for filepath in ('/var/log/apache/a.log',
'/var/log/apache/e.log',
'/var/opt/smart/log/me.log'
'/var/opt/smart/log/se.log'):
try:
print '\nEstablishing SFTP connection to: {}: {}...'.format(host,port)
transport = paramiko.Transport((host,port))
transport.connect(username = username, password = password)
sftp = paramiko.SFTPClient.from_transport(transport)
print 'Authorization Successful!!!'
lf.write("Content of server's file : "+filepath+'\n\n')
sftp.get(filepath, localpath)
# or sftp.get(filepath, lf) ?
sftp.close()
transport.close()
lf.write("\n\n\n")
except:
print "\nAuthorization Failed!!!"
break
I understood that you want to record the got contents in only one file of path 'C:\remote\NewFile.log'
I don't know if mixing instruction sftp.get(filepath, localpath) and instruction lf.write() is authorized.
.
EDIT
Now I have understood the aim I can propose a more correct code:
def do_siteserver(self, line):
import paramiko
host = '10.5.48.65'
port = 22
username = 'gilbert'
password = raw_input("\nEnter the SiteServer weekly password: ")
localpath = 'C:\\remote\\NewFile'
paramiko.util.log_to_file('c:\Python27\paramiko-wininst.log')
for filepath in ('/var/log/apache/a.log',
'/var/log/apache/e.log',
'/var/opt/smart/log/me.log'
'/var/opt/smart/log/se.log'):
try:
print '\nEstablishing SFTP connection to: {}: {}...'.format(host,port)
transport = paramiko.Transport((host,port))
transport.connect(username = username, password = password)
sftp = paramiko.SFTPClient.from_transport(transport)
print 'Authorization Successful!!!'
sftp.get(filepath, localpath + filepath.replace('/','_'))
sftp.close()
transport.close()
except:
print "\nAuthorization Failed!!!"
break
BY the way, there is no need of break in the try portion