LINUX.ORG.RU

Python + pysftp


0

1

Доброго дня.

cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
sftp = pysftp.Connection(host, username='user', password='password ', cnopts=cnopts)
Как можно сделать чтобы этот кусок кода загружался по определённому условию например когда доступен 22 порт на сервер. Саму проверку порта я реализовал. НО проблема состоит в том что при загрузке скрипта когда доходит до загрузки этих строк в самом конф. файле сразу идет подключение, и если начинать экспериментировать с открытием/закрытием порта то падает в ошибку (если порт закрыт) или нет.

То есть что-то типа если функция проверки порта возвращает True идет загрузка кода. Если False то этот кусок кода не загружается с конфига. Если такое возможно...



Последнее исправление: vip71541 (всего исправлений: 3)

Познаёшь мир?

Что мешает тебе сначала проврить условие и только потом выполнять подключение? Но на самом деле, тебе никакие проверки не нужны, тебе нужно лишь обработать возникающее исключение с помощью try-except.

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

Да есть такое ;)

Но как сделать это так чтоб это строки загрузилась или нет после выполнения функции проверки порта. а не до нее. Так как сам скрипт состоит с что в есть 1 main_code и доп. файлы к нему.

vip71541
() автор топика
Ответ на: комментарий от vip71541

Я пока очень не понимаю, что именно ты хочешь. Покажи весь код и напиши в нём комментарии о том, что и в каком случае должно работать, а что нет.

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

WitcherGeralt

Функция проверки доступности порта. Она находится в отдельном файле. Я ее подключаю в main_code

from backup_v4.config import *


def check_host(port):
    #
    # Check destination port
    #
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # check open port
    port_result = sock.connect_ex((host, port))
    if port_result == 0:
        result = True
        #con_sftp = pysftp.Connection(host, username='user', password=password, cnopts=cnopts)
        #sftp = con_sftp
    else:
        result = False
    return result

Файл main_code

from backup_v4.check_network_connection import *
from backup_v4.path_for_logs_and_backups import path_is_exists
from backup_v4.parameters_for_7zip import parameters_for_7z
from backup_v4.rename_backup import renamed_backup
from backup_v4.calculating_copies_of_files import calc_copies_files
from backup_v4.delete_old_files import delete_old_files
from backup_v4.attach_email_file import attach_email
from backup_v4.send_email import send_email
from backup_v4.send_email_host_down import send_email_host_down
from backup_v4.config import *

while continue_working is True:
    # start timer for time sleep for recreating
    start_time = time.monotonic()

    # Check network connection
    def_check_network_connection = check_host(port)
    if def_check_network_connection is True:
        sftp = pysftp.Connection(host, username='user', password='c3^98fiXS&', cnopts=cnopts)
        # Count for damage archive
        if max_count_recreating == 0:
            continue_working = False
            continue
        current_time = time.strftime("%d.%m.%Y %H.%M.%S")
        #
        # Create paths for log and backups
        def_check_path_for_logs = path_is_exists(path_for_log)
        def_check_path_for_backups = path_is_exists(path_for_backup)
        file_log = sftp.open(fr'/{path_for_log}/logs_{current_time}.txt', mode='a+', bufsize=-1)
        file_log.write(f'Host {host} is up and port {port} is available\n')
        if def_check_path_for_logs and def_check_path_for_backups is True:
            file_log.write(f'Paths not exist!, creating path {path_for_log}\n'
                           f'Paths not exist!, creating path {path_for_backup}\n')
        else:
            file_log.write('Paths for logs and backups exists\n')

        # Parameters for 7zip
        def_parameters_for_7zip = parameters_for_7z()
        if def_parameters_for_7zip is 0 or 1:
            file_log.write('Creating archive\n')
        else:
            file_log.write('Error while creation\n!')

        # Rename backup
        renamed_backup(temp_dir_for_7z, current_time)
        file_log.write(f'Archive is created and renamed: {current_time}_backup.7z\n')
        list_dir = os.listdir(temp_dir_for_7z)
        temp = ''.join(list_dir)
        upload_to_sftp = sftp.chdir(path_for_backup)
        upload = sftp.put(temp_dir_for_7z + temp)
        os.remove(temp_dir_for_7z + temp)

        
        # Calculating copies logs and backups
        def_calculating_copies_of_logs = calc_copies_files(path_for_log)
        def_calculating_copies_of_backup = calc_copies_files(path_for_backup)
        file_log.write(f'Amount of copies in log folder: {def_calculating_copies_of_logs} qty\n')
        file_log.write(f'Amount of copies in backup folder: {def_calculating_copies_of_backup} qty\n')

        # Deleting old files, logs and backups
        def_delete_log = delete_old_files(path_for_log, def_calculating_copies_of_logs, log_extension)
        def_delete_backup = delete_old_files(path_for_backup, def_calculating_copies_of_backup, backup_extension)
        file_log.write(f'Finding and deleting old log file: {def_delete_log}\n')
        file_log.write(f'Finding and deleting old backup file: {def_delete_backup}\n')

        # Close log file
        file_log.close()

        # Send Email notification
        def_name_send_attache = attach_email(path_for_log)
        sftp.chdir('/')
        download_to_pc = sftp.chdir(path_for_log)
        download = sftp.get(def_name_send_attache, localpath=temp_dir_for_7z + def_name_send_attache)
        #
        #
        send_email(def_name_send_attache)
        sftp.close()
        #
        os.remove(temp_dir_for_7z + def_name_send_attache)


        continue_working = False
    else:
        continue_working = False
        send_email_host_down()

Файл confiп

import subprocess
import os
import fnmatch
import time
import smtplib
import socket
import pysftp
from email.mime.text import MIMEText
from email.mime.multipart import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email import encoders
from datetime import timedelta

#
dict_attach_name = {}
max_archive_name = ''
max_log_name = ''
#

#
host = '172.16.209.210'  # Host for backups
port = 22 # Default sftp port
path_folder = 'test'
name_folder_for_backup = 'backup'
name_folder_for_log = 'logs'
#
#
dir_for_archive = "C:\\Temp\\test_7zip"   # Files for backup
#
continue_working = True

# Check destination port
#
#sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # check open port
#port_result = sock.connect_ex((host, port))

#result = subprocess.Popen(["ping", '-n', '3', str(host)], stdout=subprocess.PIPE) # ping request
#ping_result = (result.stdout.read().decode('cp866'))

#cnopts = pysftp.CnOpts()
#cnopts.hostkeys = None
#sftp = pysftp.Connection(host, username='user', password='c3^98fiXS&', cnopts=cnopts)
#sftp = 0

#
path_for_log = name_folder_for_log
path_for_backup = name_folder_for_backup


dir_home_7z = "C:\\Program Files\\7-Zip\\7z.exe"  # Dir home of 7zip
temp_dir_for_7z = "C:\\Temp\\tmp\\"
temp1 = ''


max_count_recreating = 3  # Count for damage archive
flag_for_recreating = 3   # Count for recreating
time_sleep_for_recreating = 0  # Timeout in seconds for waiting between recreating archives

saved_archive_copies = 5  # saved archive copies
log_extension = "logs_*.txt"
backup_extension = "*_backup.7z"

Вот почти весь мой скрипт. Начало идет от функции проверки порта.

vip71541
() автор топика
Ответ на: комментарий от vip71541

пробовал создавать пустую переменную и ей присваивать новое значения после выполнение функции проверки порта но результата не дало. Пуская переменная лежит в конфиге, новую создаю в main_code но при запуске все остальные функции тянут эту переменную как пустую. НО па после перезаписи они не вытягивают новые значения.

vip71541
() автор топика
Ответ на: комментарий от vip71541

Так сейчас правильно же всё, код для подключения не должен быть в файле конфигурации. Тебе нужно вынести туда не подключение, а значения username и password.

Что действительно не так в коде:

# while continue_working is True:

while continue_working:
#def_check_network_connection = check_host(port)
#    if def_check_network_connection is True:

if check_host(port):

Но на самом деле проверка вообще не нужна:

try:
  sftp = pysftp.Connection(host, username='user', password='passwd', cnopts=cnopts)
except IOError: # ошибку лучше уточнить. Проверь, какая вылазит, её и подставь
  print('...')
  break
#if max_count_recreating == 0:
#            continue_working = False
#            continue

if not max_count_recreating:
  break
#if def_parameters_for_7zip is 0 or 1: # здесь у тебя всегда истина

if def_parameters_for_7zip in (0, 1):

И старайся не изменять то, что задано в конфиге, относить к конфигу как к константе и всегда создавай отдельные локальные переменные, а уже их изменяй (они на самом деле у тебя и так локальные, но так всё равно делать не стоит).

WitcherGeralt ★★
()
Ответ на: комментарий от vip71541

То есть тебе нужен общий объект подключения для нескольких модулей?

Собственно, вынеси инициализацию в отдельный модуль, примерно так:

_conn = None
def get_conn():
  global _conn
  if not _conn:
    cnopts = pysftp.CnOpts()
    cnopts.hostkeys = None
    _conn = pysftp.Connection(host, username='user', password='password ', cnopts=cnopts)
  return _conn

Но это, примитивно, конечно, и не совсем верно, лучше юзать ООП.

WitcherGeralt ★★
()
Последнее исправление: WitcherGeralt (всего исправлений: 1)
Ответ на: комментарий от WitcherGeralt

WitcherGeralt

Если я правильно понял послед. сообщение.

то у нас есть переманенная _conn = None

потом мы создаем функцию get_conn объявляем глобальною переменную _conn и если ее нет соедениия то мы перезаписываем ее значения в конфиге правильно я понял ?

И эту функцию я могу вызвать сразу после проверки порта ??

vip71541
() автор топика
Ответ на: комментарий от vip71541

как вариант я думаю. Если вынести _conn = None в конфиг. я смогу его поменять через эту функцию ? ООп пока не особо понимаю.

vip71541
() автор топика
Ответ на: комментарий от vip71541

Отдельный модуль просто сделай, в конфиге этого быть не должно.

WitcherGeralt ★★
()
Ответ на: комментарий от vip71541

объявляем глобальною переменную _conn и если ее нет соедениия то мы перезаписываем ее значения в конфиге правильно я понял ?

Да, только объявлена переменная вне функции, а в функции только указан скоуп. Если не указать скоуп, переменная будет объвлена внутри функции. Мало того, до проверки глобальной перед заданием локальной дело даже не дойдет, всё свалится с UnboundLocalError.

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

WitcherGeralt

Что или я не то или лыже не те:) Итого сделал я отдельный файл:

from backup_v4.config import *
sftp = None
def create_connection():
    global sftp
    if not sftp:
        cnopts = pysftp.CnOpts()
        cnopts.hostkeys = None
        sftp = pysftp.Connection(host, username='user', password='password', cnopts=cnopts)
    return sftp
подгрузил его в main_code
from backup_v4.check_network_connection import *
from backup_v4.path_for_logs_and_backups import path_is_exists
from backup_v4.parameters_for_7zip import parameters_for_7z
from backup_v4.rename_backup import renamed_backup
from backup_v4.check_archive import check_archive
from backup_v4.calculating_copies_of_files import calc_copies_files
from backup_v4.delete_old_files import delete_old_files
from backup_v4.attach_email_file import attach_email
from backup_v4.send_email import send_email
from backup_v4.send_email_host_down import send_email_host_down
from backup_v4.sftp_connection import *
from backup_v4.config import *
Итого после проверки порта и перехода на следующий функцию это проверка наличие каталога на сервере(ее код)
from backup_v4.sftp_connection import *
def path_is_exists(path_for_files):
    #
    # Checking path for logs and backups.If paths are not exist, create them.
    #
    if not sftp.exists(path_for_files):
        create_dirs = sftp.makedirs(path_for_files)
        flag_for_create_dirs = True
        return flag_for_create_dirs
    else:
        flag_for_create_dirs = False
        return flag_for_create_dirs

То я получаю след. ошибку

File "C:\Users\user\PycharmProjects\untitled\backup_v4\path_for_logs_and_backups.py", line 8, in path_is_exists
    if not sftp.exists(path_for_files):
AttributeError: 'NoneType' object has no attribute 'exists'
я тогда понять не могу чего не меняется значение переменной sftp с None на строку подключения.

vip71541
() автор топика
Ответ на: комментарий от vip71541

Ты импориируешь начальное значение.

from backup_v4 import sftp_connection

if not sftp_connection.sftp.exists(path_for_files):

— вот так работать будет, если ты уже подключился.

Но я не зря назвал переменную _conn в примере с подчёркивания, это конвенция именования приватных полей. Лучше просто каждый раз вызывай функцию там, где тебе нужно получить соединение.

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

Что то я вообще запутался. Можешь пожалуйста объяснить на примере функции проверки путей на сервере. Где мне нужно вызывать функцию подключения.

from backup_v4.sftp_connection import *
def path_is_exists(path_for_files):
    #
    # Checking path for logs and backups.If paths are not exists, create them.
    #
    create_connection()
    if not sftp.exists(path_for_files):
        create_dirs = sftp.makedirs(path_for_files)
        flag_for_create_dirs = True
        return flag_for_create_dirs
    else:
        flag_for_create_dirs = False
        return flag_for_create_dirs
я и так пробовал. Но всеравно получаю ту же ошибку,что тип NoneType не имеет параметры 'exists'. И сама перемена не менят значение.

vip71541
() автор топика
Ответ на: комментарий от WitcherGeralt

Да спасибо заработало. А как в идеале бы такое подключение сделать ? Если не отталкиваться от моего уровня знаний/умений по питону, интересно... ? Или тут полностью этот скрипт переписать нужно будет.

vip71541
() автор топика
Ответ на: комментарий от vip71541

Если это просто скрипт, который отрабатывает и умирает, то и так сойдёт.

Безотносительно данного конкретного случая, работа с соединениями это слишком большая тема, нет смысла пытаться её здесь раскрыть. Тут нужна хорошо обдуманная лекция на часок.

WitcherGeralt ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.