Есть отличная удаленная работа для php+codeception+jenkins+allure+docker спецов. 100% remote! Присоединиться к проекту

Выполнение команд Linux из командной строки Windows


(Игорь Кожин) #1

Следующие действия производятся вручную:

  1. Запуск cmd на Windows и переход в нужный каталог, где лежит необходимый exe-шник;
  2. Запуск данного экзешника, и выполнение определенного известного скрипта (в ходе выполнения скрипта наша тулза отправляет сообщение на сервер, на сервере в БД записываются определенные известные нам данные и отправляется ответ, по которому мы понимаем что все прошло успешно, т.е. статус ответа = 0).
  3. Запуск putty, коннект к северу через пару логин+пароль;
  4. В putty необходимо перейти в нужный каталог и выполнить скрипт селект к БД MySQL с логированием в файл;
  5. Открыть файл с результатами селекта и убедиться, что в БД все записалось корректно.

Данный процесс необходимо автоматизировать так, чтобы после запуска исполняющего файла пользователю выдавался результат. Чтобы это было возможно, я так понимаю, необходимо следующее:

  • действия 1-4 выполнить можно из командной строки (или каким либо другим единственным средством).
  • тем же средствами: файл с логом селекта копировать на компьютер пользователя и парсить данные в файле, затем на основании разбора выдавать результат.

Я пытался сделать через командную строку Windows, однако у меня случился ступор на подходе к пункту 4:
Если я пункт 3 выполняю следующей командой (нахожусь в каталоге с PUTTY.EXE):

PUTTY.EXE -ssh -l login -pw password 11.1.1.111

то у меня запускается Putty и происходит успешная авторизация. В терминале Putty я вижу следующее:

Using username "login".
Last login: Tue Jul 14 14:34:06 2015 from tratata
login@bumbum:~$

А если я пункт 3 выполняю следующей командой (нахожусь в каталоге с PUTTY.EXE):

PUTTY.EXE -ssh -l login -pw password 11.1.1.111 -m script.txt

то у меня запускается Putty и повисает на этой строчке

Using username "login".

Содержание файла “script.txt” на результат не влияет.

Более того, я пытался написать так, чтобы пункты 3,4+копирование файла на Windows производилось из командной строки, однако я не понимаю как это сделать, поскольку в случае успешного коннекта открывается терминал Putty.

Подскажите с помощью каких инструментов можно автоматизировать данный процесс?
Заранее спасибо.


(Dmitriy Zverev) #2

Здравствуйте.
Почему шаг 3 нельзя выполнить с Windows?
Почему исполняемый скрипт в виде txt-файла?
Зачем дополнительно парсить селект из базы, а не написать нужный селект?
По поводу выполнения скриптов на linux - Вам нужен plink


(Александр Таранков) #3

Зачем вообще для выполнения sql-запроса коннектиться по ssh на удаленный хост? Нельзя просто удаленно к базе обратиться?


(Игорь Кожин) #4

Шаг 3 я выполнял из командной строки. Спасибо, благодаря вашей ссылке и plink мне удалось объединить пункты 3 и 4 в один. Теперь у меня для коннекта и исполнения скрипта имеется строчка:

plink login@11.1.1.111 -pw password -m file.sh

В файле у меня две строчки: переход в нужный каталог и запуск селекта с логированием.
Затем я скачиваю файл, также из командной строки, с помощью pscp.

Нужный селект содержит результат по трем полям, в файл логов он записывается в следующем виде:


select field1, field2, field3 from license where field4 = ‘11111’ order by field1 desc limit 1

±-------±-------±-------+
| field1 | field2 | field3 |
±-------±-------±-------+
| 6413 | 5 | 3 |
±-------±-------±-------+
1 row in set (0.00 sec)

Bye

значение полей необходимо проверять.


(Игорь Кожин) #5

База лежит на linux-сервере, а я работаю из под Windows. Я думал об удаленном коннекте сразу к базе, но не нашел решения кроме описанного мной выше. Если вы знаете более простое решение, буду благодарен если поделитесь.


(Александр Таранков) #6

Я возможно что-то недопонял, но по идее пункты 3, 4. 5 делаются с помощью простого command-line mysql client (mysql.exe в случае Windows). Для этого у клиента есть параметр -h, в котором указывается хост, где установлен сервер с БД. В конфиге БД нужно для этого разрешить удаленное подключение к базам данных. И тогда все пункты можно будет легко выполнить из одного cmd-файла без необходимости таскать файлики по ssh


(Игорь Кожин) #7

Я правильно понимаю, что для реализации вашего варианта необходимо установить какой-нибудь sql-client, типа pl/sql developer или toad?


(Игорь Кожин) #8

А вообще какие инструменты посоветуете для решения данной задачи?


(Евгений Бухгаммер) #9

http://www.ryanchapin.com/fv-b-4-743/Executing-MySQL-Queries-and-Commands-from-the-Command-Line-to-a-Remote-Server.html

mysql -u uid -p -h remote.host database -e 'SQL query here;'

(Александр Таранков) #10

Вот тут про винду написано: http://www.windows-commandline.com/connect-mysql-command-line-client/


(Olexsandr Borisov) #11

а если приватный ключ?


(Olexsandr Borisov) #12

у меня случай когда есть только приватный ключ, написал некий костыль

class HiveClient(SSHClient):
bufsize = 65536

def __init__(self, server, username, port=22, password=None, rsa_private_key=None):
    super(HiveClient, self).__init__(server, username, port, password, rsa_private_key)
    self.transport = self.get_transport()
    self.transport.use_compression(True)
    session = self.transport.open_session()
    session.set_combine_stderr(True)
    session.get_pty()
    session.exec_command('hive')
    session.recv(self.bufsize)
    self.session = session
    self._run_poll('set hive.cli.print.header=true;\n')

def select(self, from_table, select_fields=None, where=None, **kwargs):
    if not where:
        where = {}
    if not select_fields:
        select_fields = ['*']
    command = 'select '
    if isinstance(select_fields, list):
        command += ','.join(select_fields) + ' '
    elif isinstance(select_fields, basestring):
        command += select_fields + ' '
    command += 'from %s ' % from_table
    if where:
        command += 'where %s ' % ' and '.join('%s=%s' % (key, where[key]) for key in where.keys())
    command += ';\n'
    result = self._run_poll(command)
    result = result.split('Time taken:')[0].split('OK')[-1]
    first_part = result.split('SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".')[0]
    last_part = result.split('org.apache.hadoop.mapreduce.task.T')[-1]
    last_part = last_part.split('AM INFO: parquet.hadoo')[-1]
    last_part = \
    last_part.split('SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.\r\n')[-1]
    return BaseManager().deserialize(last_part, first_part)

def _run_poll(self, input_data, timeout=10):
    """
    Poll until the command completes.

    @param input_data  The input data.
    @returns the output
    """
    session = self.session
    output = ''
    session.setblocking(0)
    start_time = datetime.datetime.now()

    if session.recv_ready():
        session.recv(self.bufsize)

    if session.send_ready():
        log.info('sending input data %d' % (len(input_data)))
        session.send(input_data)

    while (datetime.datetime.now() - start_time).total_seconds() <= timeout:
        if session.recv_ready():
            output += session.recv(self.bufsize)
        if session.exit_status_ready():
            break

    return output

и сам коннект

import logging
import paramiko


class SSHClient(paramiko.SSHClient):
def __init__(self, server, username, port=22, password=None, rsa_private_key=None):
    super(SSHClient, self).__init__()
    self.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    paramiko.util.log_to_file("support_scripts.log")
    rsa_key = paramiko.RSAKey.from_private_key_file(rsa_private_key)

    if password:
        self.connect(server, port, username=username, password=password)
    else:
        self.connect(server, port, username=username, pkey=rsa_key)

def exec_command(self, command, bufsize=-1, timeout=None, get_pty=False):
    """

    :rtype : tuple
    """
    logging.debug(str(command))
    if isinstance(command, list):
        result = []
        for com in command:
            result.append(self.exec_command(com, bufsize, timeout, get_pty))
        return result
    else:
        return super(SSHClient, self).exec_command(command, bufsize, timeout, get_pty)