CLI Bash/AWS: попытка выяснить, как проверить массив времени безотказной работы с двумя проверками при перезагрузке групп экземпляров EC2 через AWS SSM.

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

Первоначально я пытался настроить цикл while, который продолжал бы выдавать команду для проверки времени безотказной работы и отправки вывода в массив. Я пытаюсь понять, как вы можете перебирать массив, пока все элементы этого массива не будут больше 5 и меньше. Я даже не добился успеха в первой проверке больше 5. Возможно ли вообще постоянно записывать в массив и выполнять арифметические проверки для каждого значения в массиве, чтобы все значения должны быть больше X в цикле while? Количество серверов, которые будут помещать свое текущее время безотказной работы в массив, варьируется для каждой группы, поэтому количество значений в массиве не всегда будет одинаковым.

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

Вывод команды, которую я запускаю для подтягивания времени безотказной работы, выглядит примерно так:

1
2
1
4
3
2

Редактировать

Благодаря предоставленной помощи я смог получить функциональное доказательство концепции для этого, и я в восторге. Вот это на случай, если это может помочь любому, кто попытается сделать что-то подобное в будущем. Проблема заключалась в том, что мы используем AWS SSM для всех исправлений наших серверов Windows, и много раз, когда SSM приказывает серверам перезагрузиться после исправления, агенту SSM требуется много времени для регистрации. Это замедляет весь наш процесс, который сейчас выполняется вручную. десятки групп патчей. Много раз нам приходится идти и вручную проверять, действительно ли сервер перезагрузился после того, как мы сказали ему об этом из SSM, чтобы мы знали, что можем начать перезагрузку для следующей группы исправлений. Благодаря этому мы сможем создать единый сценарий, который выполняет перезагрузку для наших групп исправлений в правильном порядке и проверяет правильность перезагрузки серверов, прежде чем переходить к следующей группе.

#!/bin/bash

### The purpose of this script is to automate the execution of commands required to reboot groups of AWS Windows servers utilizing SSM while also verifying their uptime and only continuing on to the next group once the previous has reached X # of minutes. This solves the problems of AWS SSM Agents not properly checking in with SSM post-reboot.

patchGroups=(01 02 03)                      # array containing the values of the RebootGroup tag


for group in "${patchGroups[@]}"
do
    printf "Rebooting Patch Group %q\n" "$group"
    aws ec2 reboot-instances --instance-ids `aws ec2 describe-instances --filters "Name=tag:RebootGroup,Values=$group" --query 'Reservations[].Instances[].InstanceId' --output text`

    sleep 2m

    unset      passed failed serverList                      # wipe arrays
    declare -A passed failed serverList                      # declare associative arrays

    serverList=$(aws ec2 describe-instances --filter "Name=tag:RebootGroup,Values=$group" --query 'Reservations[*].Instances[*].[InstanceId]' --output text)

    for server in ${serverList}                  # loop through list of servers
    do
        failed["${server}"]=0                     # add to the failed[] array
    done

    while [[ "${#failed[@]}" -gt 0 ]]             # loop while number of servers in the failed[] array is greater than 0
    do
        for server in "${!failed[@]}"             # loop through servers in the failed[] array
        do
            ssmID=$(aws ssm send-command --document-name "AWS-RunPowerShellScript" --document-version "1" --targets "[{\"Key\":\"InstanceIds\",\"Values\":[\"$server\"]}]" --parameters '{"commands":["$wmi = Get-WmiObject -Class Win32_OperatingSystem ","$uptimeMinutes =    ($wmi.ConvertToDateTime($wmi.LocalDateTime)-$wmi.ConvertToDateTime($wmi.LastBootUpTime) | select-object -expandproperty \"TotalMinutes\")","[int]$uptimeMinutes"],"workingDirectory":[""],"executionTimeout":["3600"]}' --timeout-seconds 600 --max-concurrency    "50" --max-errors "0" --region us-west-2 --output text --query "Command.CommandId")

            sleep 5

            uptime=$(aws ssm list-command-invocations --command-id "$ssmID" --details --query 'CommandInvocations[].CommandPlugins[].Output' --output text | sed 's/\r$//')

            printf "Checking instance ID %q\n" "$server"
            printf "Value of uptime is = %q\n" "$uptime"

            # if uptime is within our 'success' window then move server to passed[] array

            if [[ "${uptime}" -ge 3 && "${uptime}" -lt 60 ]] 
            then
                passed["${server}"] = "${uptime}"   # add to passed[] array
                printf "Server with instance ID %q has successfully rebooted.\n" "$server"
                unset failed["${server}"]         # remove from failed[] array
            fi
        done

        # display current status (edit/remove as desired)

        printf "\n++++++++++++++ successful reboots\n"
        printf "%s\n" "${!passed[@]}" | sort -n

        printf "\n++++++++++++++ failed reboot\n"

        for server in ${!failed[@]}
        do
            printf "%s - %s (mins)\n" "${server}" "${failed[${server}]}"
        done | sort -n

        printf "\n"

        sleep 60                            # adjust as necessary
    done
done

Не могли бы вы предоставить входные данные для вашего скрипта?

Hammond95 18.12.2020 20:41

Насколько большой huge mess? нам нужно что-то для начала ... как вы получаете время безотказной работы и как вы сохраняете это в массиве? выберите небольшое количество серверов (например, 5-10), заполните свой массив, а затем запустите typeset -p array_name, чтобы мы могли увидеть, что находится в массиве; вам нужно повторно тестировать все серверы при каждом проходе или только те, которые (пока что) находятся за пределами допустимого диапазона времени? ${#array_name[@]} должен указать количество элементов массива ... сравните это со счетчиком серверов, которые «прошли» ваш тест?

markp-fuso 18.12.2020 20:44

@ Hammond95 Только что обновлено, чтобы включить пример вывода времени безотказной работы. Извиняюсь, что не включил это изначально.

Chris Smith 18.12.2020 20:49

@markp-fuso Я не думаю, что мне нужно будет повторно тестировать все серверы при каждом проходе. Мне нравится ваша идея потенциального создания счетчика серверов, которые не прошли проверку, и проверки их только на предмет того, превышает ли их время безотказной работы 5 и меньше 60. Затем выход из цикла возможен только после того, как все прошли обе проверки.

Chris Smith 18.12.2020 20:50

Единица измерения для этого списка чисел (1 2 1 4 3 2), секунды? минут? как вы управляете списком серверов... хранящимся в массиве? хранится в файле?; опять же, насколько велика huge mess и можете ли вы опубликовать минимальную версию своего кода, которая представляет вашу деятельность? подумав об этом еще немного ... ассоциативный массив, где индекс - это имя сервера, а значение - последнее «время безотказной работы» (uptime[server1]=3 (мин)); предполагая основной тип цикла while true, внутренний цикл будет перебирать индексы/значения массива... и выходить из основного цикла while, когда counter=0

markp-fuso 18.12.2020 21:00

Альтернатива... все серверы изначально загружены в массив out-of-range; по мере прохождения теста удалять из массива out-of-range и в массив in-range; когда в массиве out-of-range больше нет записей ... перейти к следующему набору серверов ...

markp-fuso 18.12.2020 21:03

@markp-fuso еще раз спасибо. Я обновил исходный пост, чтобы показать сценарий проверки концепции, за создание которого я должен вам 98% кредита. Без вашей помощи вряд ли бы туда попал. Я ценю тщательность ваших ответов и то, как быстро вы смогли что-то состряпать с нуля.

Chris Smith 21.12.2020 07:11

@ChrisSmith рад, что смог помочь, и спасибо за подробную информацию о том, чего вы пытаетесь достичь; не уверен, как переформулировать его, но... возможно, вы захотите посмотреть, сможете ли вы изменить тему вопроса на что-то более подходящее для того, что вы пытаетесь сделать (например, что-то более описательное, чем "как определить, если число находится между двумя другими числами?) :-)

markp-fuso 21.12.2020 13:14

@markp-fuso Сделано и сделано

Chris Smith 21.12.2020 16:27
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
9
496
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Похоже, вам нужно постоянно переоценивать выходные данные времени безотказной работы, чтобы получить нужные вам данные, поэтому массив или другая переменная могут просто застрять. Подумайте об этом функционально (как в функциях). Вам нужна функция, которая проверяет, находится ли время безотказной работы в пределах, которые вы хотите, только один раз. Затем вам нужно периодически запускать эту функцию. В случае успеха вы запускаете перезагрузку. Если это не удается, вы позволяете ему повторить попытку позже.

Рассмотрим этот код:

uptime_in_bounds() {
    local min = "$1"
    local max = "$2"
    local uptime_secs

    # The first value in /proc/uptime is the number of seconds the
    # system has been up. We have to truncate it to an integer…
    read -r uptime_float _ < /proc/uptime
    uptime_secs = "${uptime_float%.*}"

    # A shell function reflects the exit status of its last command.
    # This function "succeeds" if the uptime_secs is between min and max.
    (( min < uptime_secs && max > uptime_secs ))
}
if uptime_in_bounds 300 3600; then
    sudo reboot  # or whatever
fi

Как я могу использовать это именно? Например, моя первая группа серверов, которую я перезагружаю после исправления, сообщит что-то вроде «1 2 1 4 3 2» Я хотел бы продолжить перезагрузку моей следующей группы серверов только после того, как время работы каждого из этих серверов сообщит обратно. число больше 5.

Chris Smith 18.12.2020 21:00
Ответ принят как подходящий

Общая идея ... вероятно, потребуется некоторая настройка в зависимости от того, как OP отслеживает серверы, получает время безотказной работы и т. д...

# for a given set of servers, and assuming stored in variable ${server_list} ...

unset      passed failed                      # wipe arrays
declare -A passed failed                      # declare associative arrays

for server in ${server_list}                  # loop through list of servers
do
    failed["${server}"]=0                     # add to the failed[] array
done

while [[ "${#failed[@]}" -gt 0 ]]             # loop while number of servers in the failed[] array is greater than 0
do
    for server in "${!failed[@]}"             # loop through servers in the failed[] array
    do
        uptime=$( some_command_to_get_uptime_for_server "${server}" )

        # if uptime is within our 'success' window then move server to passed[] array

        if [[ "${uptime}" -gt 5 && "${uptime}" -lt 60 ]] 
        then
            passed["${server}"] = "${uptime}"   # add to passed[] array
            unset failed["${server}"]         # remove from failed[] array
        else
            failed["${server}"] = "${uptime}"
        fi
    done

    # display current status (edit/remove as desired)

    printf "\n++++++++++++++ successful reboots\n"
    printf "%s\n" "${!passed[@]}" | sort -n

    printf "\n++++++++++++++ failed reboot\n"

    for server in ${!failed[@]}
    do
        printf "%s - %s (mins)\n" "${server}" "${failed[${server}]}"
    done | sort -n

    printf "\n"

    sleep 30                            # adjust as necessary
done

ПРИМЕЧАНИЯ:

  • этот код, вероятно, будет частью более крупной циклической конструкции, основанной на наборах серверов (т. е. новых ${server_list}
  • если список серверов находится в другом формате (например, файл, другой массив и т. д.), потребуется изменить цикл for, чтобы правильно заполнить массив failed[]
  • OP нужно будет отредактировать, чтобы добавить код для определения времени безотказной работы для данного ${server}
  • OP (очевидно) может свободно переименовывать переменные/массивы по желанию
  • ОП, вероятно, нужно будет решить, что делать, если цикл while будет продолжаться «слишком долго»
  • если новый ${uptime} не находится в диапазоне 5-60 минут, OP может добавить блок else для выполнения некоторых других операций для проблемного ${server}

Маркп-фусо, спасибо. Это фантастика. Очень хорошо изложено, и я думаю, что это действительно поможет мне найти окончательное решение. Это чрезвычайно полезно, особенно когда я просто предлагал общую проблему и не имел никакого существующего кода для работы. Я отчитаюсь о своих результатах.

Chris Smith 18.12.2020 22:16

Другие вопросы по теме