SSH -f в скрипте - получение сигнала при выполнении команды - PullRequest
0 голосов
/ 04 февраля 2019

Итак, вот я: я пишу скрипт на Python, который выполняет следующее:

  • Запускает команду для запуска процесса регистрации (скрипт bash) на сервере через SSH
  • Использует ab для сравнения сервера с клиента
  • Восстанавливает файл журнала, созданный на сервере с помощью scp
  • Создает график с помощью matplotlib с данными на клиенте

Я приложу оба сценария в конце, но я сомневаюсь, что они пригодятся для этого вопроса.

Чтобы не ждать окончания сценария регистрации, запущенного через SSH, для продолжения работы pythonсценарий, я использовал -f с SSH, чтобы отправить его в фоновом режиме.Сценарий python действительно продолжается, но я обнаружил, что у меня возникла проблема, связанная со временем процесса регистрации и бенчмаркинга, которая может сильно различаться в зависимости от доступа к сети и вычислительной мощности клиента.

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

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

Как отслеживать состояние команды SSH в python, чтобы запускать эту часть скрипта только после завершения команды SSH (которая находится в фоновом режиме)?

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

Файл журнала, на стороне сервера

#!/usr/bin/env bash
#perf_measurement.sh

# logs the load average every n seconds for a y period of time in a csv file

# interval, in seconds, for the load measure
INTERVAL=1
# amount of measures
MEASURES=$1
# path of the logging file
LOGFILE_EXT=".csv"
LOGFILE="$2""$LOGFILE_EXT"
# separator for the csv file
SEPARATOR=","
# load average file
LOADFILE="/proc/loadavg"
# timestamp at start of measure/script
INIT_TIMESTAMP=`date +%s`

# clearing logfile
if [ -e $LOGFILE ]; then
  rm $LOGFILE
fi

# function to get one of the load average values from LOADFILE
loadpm () {
  cat $LOADFILE | cut -d' ' -f$1
}
# function generation a timestamp starting from the start of the script, in seconds
timestamp () {
  echo $(expr $(date +%s) - $INIT_TIMESTAMP)
}

for (( i=0; i<$MEASURES; i++ )) ; do
  echo $(timestamp)$SEPARATOR$(loadpm 1) >> $LOGFILE
  sleep $INTERVAL
done


exit 0

Скрипт Python, клиентside #! / usr / bin / python # benchmark.py

import csv
import matplotlib.pyplot as plt
import os
import time

SERVER = "edited"
SERVER_USER = "ubuntu"
SERVER_PERF_MEASUREMENT_SCRIPT_PATH = "/var/www/html"
SERVER_PERF_MEASUREMENT_SCRIPT = "perf_measurement.sh"
REQUESTS = 1000000 # high because time limitation is used instead of number of requests to facilitate logging

CONCURRENCY = input("Input concurrency for test : ")
MEASURE_TIME = input("Input time of the test (in seconds) : ")
FILE = input("Input name of file/repo for test (without the extension) : ")
TEST_NAME = input("Input a name for the test (no space) : ")
FILENAME= f"{TEST_NAME}_conc_{CONCURRENCY}"
GRAPH_FILE = f"{FILENAME}.png"
LOG_FILE = f"{FILENAME}.csv"

FILE_PATH = f"/{FILE}"
TEST_TIME = int(int(MEASURE_TIME) - int(MEASURE_TIME) / 4)
SLEEP_TIME = int(int(MEASURE_TIME) / 8)


SSH_COMMAND = f"ssh -f {SERVER_USER}@{SERVER} 'cd {SERVER_PERF_MEASUREMENT_SCRIPT_PATH}&&./"\
                f"{SERVER_PERF_MEASUREMENT_SCRIPT} {MEASURE_TIME} {FILENAME}'"
AB_COMMAND = f"ab -c {CONCURRENCY} -t {TEST_TIME} -n {REQUESTS} {SERVER}{FILE_PATH}"
SCP_COMMAND = f"scp {SERVER_USER}@{SERVER}:{SERVER_PERF_MEASUREMENT_SCRIPT_PATH}/{LOG_FILE} ."

print(SSH_COMMAND)

print("\nStarting the logging server side...\n")
os.system(SSH_COMMAND)

print(f"\nSleeping {SLEEP_TIME} seconds to visualize load gain...\n")
time.sleep(SLEEP_TIME)

print("\nStarting benchmark...\n")
os.system(AB_COMMAND)

print("\nRecovering log file from server...\n")
os.system(SCP_COMMAND)


print("\nGenerating graph...\n")
# declaring list for coordinates of the graph
x_coord = []
y_coord = []

# opening log file
with open(LOG_FILE, "r") as csvfile:

    # reading csv logfile
    logfile = csv.reader(csvfile)

    # iterating through logfile
    for row in logfile:
        # storing coordinates in list
        x_coord.append(int(row[0]))
        y_coord.append(float(row[1]))


# generation graph
plt.plot(x_coord, y_coord)
plt.ylabel('Load average (from /proc/loadavg)')
plt.xlabel('Time')

# exporting graph to png
plt.savefig(GRAPH_FILE)

1 Ответ

0 голосов
/ 04 февраля 2019

Учитывая довольно уникальную природу этого скрипта, он выглядит как хороший вариант использования для subprocess.Popen(...).

Вместо того, чтобы отправлять команду SSH в фоновый режим, вы можете использоватьПопен, чтобы запустить его с ручкой процесса.Затем вы можете приступить к проведению любых тестов, которые вам необходимо выполнить, и вернуться к этому дескриптору процесса, прежде чем вы scp получите результаты.Это должно работать, потому что команда ssh, когда в конце вызова метода предоставляется набор команд, отправляет команды вместо открытия интерактивной оболочки входа в систему, а затем возвращает выходные данные клиентскому компьютеру.По завершении удаленной команды ssh закрывает соединение и выходит из своего собственного процесса.Поэтому должно работать следующее:

import subprocess
import shlex

# ... your other imports and code...

_PROC_TIMEOUT_SEC = 5
SSH_COMMAND = (
                f"ssh {SERVER_USER}@{SERVER} 'cd {SERVER_PERF_MEASUREMENT_SCRIPT_PATH}&&./"
                f"{SERVER_PERF_MEASUREMENT_SCRIPT} {MEASURE_TIME} {FILENAME}'"
              )
AB_COMMAND = f"ab -c {CONCURRENCY} -t {TEST_TIME} -n {REQUESTS} {SERVER}{FILE_PATH}"
SCP_COMMAND = f"scp {SERVER_USER}@{SERVER}:{SERVER_PERF_MEASUREMENT_SCRIPT_PATH}/{LOG_FILE} ."

print("\nStarting the logging server side...\n")
portioned_ssh_command = shlex.split(SSH_COMMAND)
ssh_proc = subprocess.Popen(portioned_ssh_command)

# Still perform your testing as you had planned...
# Not sure if you need to sleep here, but I'll leave that up to you.
print(f"\nSleeping {SLEEP_TIME} seconds to visualize load gain...\n")
time.sleep(SLEEP_TIME)
print("\nStarting benchmark...\n")
os.system(AB_COMMAND)

# Wait for SSH process to finish before attempting to scp log file.
ssh_return_code = None
while(ssh_return_code is None):
    try:
        ssh_return_code = ssh_proc.wait(_PROC_TIMEOUT_SEC)
    except subprocess.TimeoutExpired:
        pass

print(f"Info: SSH completed with exitcode {ssh_proc.returncode}")

# Now that SSH 
print("\nRecovering log file from server...\n")
os.system(SCP_COMMAND)

# ... The rest of your code...

Примечание : я не проверял приведенный выше код, но я уверен, что сделаю то, что вы хотите сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...