Вопрос или проблема
В теории
Моя цель — чтобы локальный скрипт на python (“s1.py”) запускал второй скрипт на python (“s2.py”) через ssh на удаленной машине. В процессе запуска s2.py, s1.py должна передать словарь python, который s2.py загрузит в память и затем будет использовать в своей работе. Словарь берется из локального файла, который я хочу оставить на локальном компьютере по соображениям безопасности, поэтому идея заключается в том, чтобы отправить его по сети и загрузить в память (например, я мог бы скопировать файл на удаленную машину в область tmpfs, прочитать его и немедленно удалить tmpfs; все это произойдет довольно быстро, но я все равно считаю это плохой практикой, если можно передать данные без отправки файла).
Подход, который я использую, основывается на предположении, что я могу передать этот словарь, через ssh, как объект python из s1.py в s2.py в виде командной строки, а также с некоторыми другими необходимыми флагами. Что-то вроде:
ssh user@remote python3 s2.py python-dict-obj flag1 flag2
S2.py затем сможет прочитать объект (предпочтительно как словарь) каким-либо образом, например:
useful_dict = sys.argv[1], var1_flag1=sys.argv[2], var2_flag2=sys.argv[2]
На практике
Как я уже упомянул, словарь берется из локального файла, который может быть сохранен в формате yaml или json (yaml предпочтительнее). Поэтому s1.py может создать словарь, используя стандартные модули python:
with open("local_file", "r", encoding="utf-8") as read_file:
dict_from_file = json.load(read_file)
with open("local_file", 'r') as stream:
dict_from_file = yaml.safe_load(stream)
S1.py затем пытается, через ssh, инициировать s2.py и отправить словарь, например, используя модуль subprocess:
subprocess.run(['ssh', 'user@remote', 'python3', '/user/scripts/s2.py', 'dict_from_file', 'flag1', 'flag2'])
Проблемы / Решения
Возникает ли проблема из-за того, что я пытаюсь отправить словарь через ssh? Может ли “dict_from_file” существовать как объект python, проходя через модуль subprocess и отправляясь в окружение/оболочку удаленной машины? То же самое, когда используется Paramiko или Fabric?
На данный момент все, что я пробовал, кажется, приводит к тому, что s2.py отклоняет данные. Это может означать, что, возможно, не удается передать словарь так, как я хочу. Честно говоря, я не пробовал ничего более сложного, чем принимать ввод в командной строке в s2.py с использованием модуля sys, поэтому, возможно, существует способ загрузить данные другим способом.
Даже если невозможно передать реальный объект словаря через ssh, конечно, необработанные данные можно отправить в формате json? Возможно, json-строка (json.dumps?), хотя у меня нет опыта с этим? Тогда, предположительно, s2.py сможет прочитать строку и восстановить словарь?
Или мой подход просто слишком naивен? Нужно ли мне исследовать сокеты/трубопроводы/многопроцессность, чтобы добиться того, что я пытаюсь сделать. На базовом уровне я просто пытаюсь выполнить простую (как я думаю) передачу данных, так что я надеюсь, что есть краткий, элегантный способ это сделать. Все предложения приветствуются.
Ответ или решение
Чтобы отправить словарь из локального скрипта Python (s1.py
) на удалённый скрипт Python (s2.py
) через SSH, лучшим подходом будет сериализация словаря в формат JSON (или YAML), а затем передача этой сериализованной строки как аргумента командной строки. Давайте подробно рассмотрим, как это сделать.
Шаг 1: Подготовка локального скрипта (s1.py
)
-
Импортируйте необходимые модули:
import json import subprocess
-
Загрузите словарь из файла:
with open("local_file.json", "r", encoding="utf-8") as read_file: dict_from_file = json.load(read_file)
-
Сериализуйте словарь в строку JSON:
json_dict = json.dumps(dict_from_file)
-
Отправьте строку JSON на удалённый скрипт (
s2.py
) с помощьюsubprocess.run
:subprocess.run(['ssh', 'user@remote', 'python3', '/path/to/s2.py', json_dict, 'flag1', 'flag2'])
Шаг 2: Создание удалённого скрипта (s2.py
)
-
Импортируйте необходимые модули:
import json import sys
-
Получите строку JSON и флаги из аргументов командной строки:
json_string = sys.argv[1] # Первая команда - это строка JSON var1_flag1 = sys.argv[2] # Второй аргумент - флаг 1 var2_flag2 = sys.argv[3] # Третий аргумент - флаг 2
-
Десериализуйте строку JSON обратно в словарь:
useful_dict = json.loads(json_string)
Пример кода
Локальный скрипт s1.py
:
import json
import subprocess
# Загрузка словаря из локального файла JSON
with open("local_file.json", "r", encoding="utf-8") as read_file:
dict_from_file = json.load(read_file)
# Сериализация словаря в строку JSON
json_dict = json.dumps(dict_from_file)
# Отправка на удалённый скрипт
subprocess.run(['ssh', 'user@remote', 'python3', '/path/to/s2.py', json_dict, 'flag1', 'flag2'])
Удалённый скрипт s2.py
:
import json
import sys
# Получение аргументов
json_string = sys.argv[1]
var1_flag1 = sys.argv[2]
var2_flag2 = sys.argv[3]
# Десериализация строки JSON в словарь
useful_dict = json.loads(json_string)
# Пример использования значений словаря и флагов
print("Полученный словарь:", useful_dict)
print("Флаг 1:", var1_flag1)
print("Флаг 2:", var2_flag2)
Заключение
Использование JSON позволяет передавать сложные структуры данных (такие как словари) между скриптами через SSH эффективно и безопасно. Основным шагом является сериализация данных в строку JSON в локальном скрипте и их десериализация в удалённом скрипте. Это решение должно решить вашу задачу без необходимости использования более сложных методов, таких как сокеты или потоки.