ожидать скрипт для получения вывода с нескольких серверов

Вопрос или проблема

Я пытаюсь получить вывод IQN с нескольких серверов. Я получаю следующую ошибку.

Вывод ошибки

spawn /usr/bin/ssh VM2 | /usr/bin/cat /etc/iscsi/initiatorname.iscsi
root@VM2's password:
bash: -c: line 0: syntax error near unexpected token `|'
bash: -c: line 0: `| /usr/bin/cat /etc/iscsi/initiatorname.iscsi'

скрипт

#!/bin/bash

HOSTS="VM2 VM3 VM4 VM1"

read -p "Password: " PASSWORD

for HOST in $HOSTS
do
expect -c "
spawn cat /etc/iscsi/initiatorname.iscsi
    expect {
    "*password:*" { send $PASSWORD\r;interact }
    }
    exit
    "
done

Я делаю что-то неправильно?

Прежде всего, я не совсем понимаю, что именно вы пытаетесь достичь.

Понял, что вы хотите cat /etc/iscsi/initiatorname.iscsi на каждом сервере, верно?

Но тогда зачем вам нужно interact с каждым сервером?

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

Поэтому сначала я решил записать большую часть скрипта на expect и не передавать его через bash. Думаю, таким образом у вас будет больше ошибок.

Вот bash-скрипт, который используется как запускающий, он запрашивает пароль, чтобы пароль не был напечатан или виден (это сложно сделать непосредственно в expect)

#!/bin/bash 

expect_script="./connect_to_many_hosts_and_cat_files.exp"

[ ! -f $expect_script ] && echo expect_script does not exist && exit 1

echo "Please enter a password:"

read -s password

$expect_script $password

Теперь сам скрипт expect

#!/usr/bin/expect

if {$argc != 1} {
   puts "please run expect script using bash script"
   puts "that prompts for password"
   exit
}

set password [lindex $argv 0]

# замените имена хостов своими !!!
set hosts "host1 host2"

foreach host [ split $hosts " " ] {

    set number_of_password_prompts($host) 0

    puts "# "
    puts "# ssh $host"
    puts "# "

    spawn ssh $host
        expect {
            # здесь я добавил проверку пароля, на случай, если пароль неверен
            # выглядит немного некрасиво, но лучше, чем ничего
            "Password:" {
                if { $number_of_password_prompts($host) == 0 } {
                    incr number_of_password_prompts($host)
                    puts "# "
                    puts "# Authenticating try $number_of_password_prompts($host)"
                    puts "# "
                    send "$password\r"
                    exp_continue
                } else {
                    puts "# "
                    puts "# Password is wrong"
                    puts "# "
                    exit
                }
            }
            # на случай, если на хосте /bin/sh или /bin/bash
            "$ " {
                puts "# "
                puts "# cat /etc/iscsi/initiatorname.iscsi"
                puts "# "
                send "cat /etc/iscsi/initiatorname.iscsi \r"
                expect "$ "
            }
            # на случай, если на хосте /bin/csh
            "% " {
                puts "# "
                puts "# cat /etc/iscsi/initiatorname.iscsi"
                puts "# "
                send "cat /etc/iscsi/initiatorname.iscsi \r"
                expect "% "
            }
            send "exit\r"
            expect eof
            close
        }
}

И наконец, убедитесь, что вы использовали chmod +x для обоих файлов. Вы также можете запускать expect и по-другому. И также убедитесь, что у вас правильное местоположение expect. У меня это /usr/bin/expect. У вас может быть что-то другое.

Также важно. Для expect важно, какие приглашения на серверах. Если это /bin/bash, вы видите, что я добавил условие с $, если это /bin/csh, тогда нужно добавить условие с %.

Очень важно проверять, как будет выглядеть ваш $PS1 или другое приглашение после ssh. Скрипт выше не будет работать, если ваше приглашение

    user@host:~>

Чтобы это работало, нужно добавить еще одно условие в expect

            "> " {
                puts "# "
                puts "# cat /etc/iscsi/initiatorname.iscsi"
                puts "# "
                send "cat /etc/iscsi/initiatorname.iscsi \r"
                expect "> "
            }

Обратите на это внимание, я потратил много дней, пытаясь понять, почему вещи не работают.

Используйте ansible для этого случая.

yum install ansible -y
vim /etc/ansible/hosts
[servers]
192.168.0.2
192.168.0.3

ssh-keygen

Скопируйте открытый ключ на целевой сервер.
После этого попробуйте подключиться к серверу

ansible servers -m ping

В ansible документации вы можете найти информацию о том, как управлять серверами.

Ответ или решение

Когда вы пытаетесь получить вывод IQN (iSCSI Qualified Name) с нескольких серверов, необходимо использовать подходящий инструмент для удаленного доступа и выполнения команд на серверах. Пользователь, который представил свой скрипт, сталкивается с ошибкой, связанной с использованием команды SSH в некорректном синтаксисе. Давайте разберем сложившуюся ситуацию и предложим решения.

Теория

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

  1. Expect: Скриптовый инструмент, который позволяет управлять взаимодействием с приложениями, запрашивающими ввод пользователя. Особенно эффективен для автоматизации SSH-сессий. Важно правильно задавать и обрабатывать промпты (строки запроса), которые приходят с удаленных серверов.

  2. Ansible: Более современное средство, основанное на SSH, но не требующее постоянного взаимодействия посредством терминала. Ansible имеет мощный синтаксис и возможность выполнения задач на большом количестве серверов одновременно, обеспечивая простую и безопасную автоматизацию.

Пример решения

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

Решение с использованием expect

Приведенные вами скрипты должны быть немного скорректированы для успешного выполнения команд на удаленных серверах.

  1. Bash-скрипт для запуска expect:
#!/bin/bash 

expect_script="./connect_to_many_hosts_and_cat_files.exp"

# Проверяем наличие скрипта
[ ! -f $expect_script ] && echo "Expect script does not exist" && exit 1

# Ввод пароля без его отображения на экране
echo "Please enter a password:"
read -s password

# Запуск expect скрипта
$expect_script $password
  1. Expect-скрипт для выполнения команд:
#!/usr/bin/expect

# Проверяем количество аргументов
if {$argc != 1} {
   puts "Run expect script using bash script"
   puts "that prompts for password"
   exit
}

# Получаем пароль из аргументов
set password [lindex $argv 0]

# Задаем список хостов
set hosts "host1 host2 host3"

# Перебор каждого хоста
foreach host [split $hosts " "] {
    set timeout 10

    spawn ssh $host
    expect {
        # Проверка на запрос пароля
        "*password:*" {
            send "$password\r"
            exp_continue
        }
        # Определение shell-промпта
        "$ " {
            send "cat /etc/iscsi/initiatorname.iscsi\r"
            expect "$ "
        }
    }
}

Преимущество использования Ansible

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

  1. Установка Ansible:
yum install ansible -y
  1. Описываем хосты в Ansible:

Редактируем файл /etc/ansible/hosts:

[servers]
192.168.0.2
192.168.0.3
...
  1. Настройка SSH-ключей для доступа без пароля:

Создаем SSH-ключи:

ssh-keygen

Копируем открытый ключ на удаленные серверы:

ssh-copy-id user@192.168.0.2
ssh-copy-id user@192.168.0.3
  1. Проверка подключения:
ansible servers -m ping
  1. Получение IQN с использованием Ansible:

Создайте playbook, например iqn_fetch.yml:

---
- hosts: servers
  tasks:
    - name: Fetch IQN from servers
      command: cat /etc/iscsi/initiatorname.iscsi
      register: iqn_output

    - name: Display IQN
      debug:
        var: iqn_output.stdout

Запустите playbook:

ansible-playbook iqn_fetch.yml

Применение

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

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

Оцените материал
Добавить комментарий

Капча загружается...