При работе с облаком Amazon, часто приходится выполнять много рутинных операций через Web консоль. Но хочется их автоматизировать.
AWS CLI, интерфейс командной строки, хорошо для этого подходит. Конечно, можно написать и приложение на Scala, но в повседневных задачах лучше обойться без «тяжелой артиллерии».
Команды AWS умеют возвращать данные в разных форматах, в том числе и в json. Можно воспользоваться bash и jq, но последнего нет в репозитарии cygwin, а руками устанавливать лень. Между тем в PowerShell есть прекрасная поддержка json! Правда оказалось, что воспользоваться этим не совсем просто.
Дело в том, что json выдается в виде нескольких строк, и трактуется как массив. Скормить его в PowerShell можно разными способами:
Получить нужную информацию теперь не сложно:
В простых случаях извлечение информации можно перепоручить aws:
или даже так
Таким образом, наблюдая странное поведение autoscaling group через консоли, я могу скопировать мышкой имя инстанса и зайти на него по ssh:
В более сложных случаях приходится уже писать нетривиальный код. Например, получить выходные параметры cloud formation стека можно следующим образом:
Теперь я могу получить параметры соединения с базой данных командой
Передача json в команды aws cli тоже преподносит неожиданности. Например, попытка добавить запись в таблицу dynamodb просто так не удается:
То есть где-то глубоко aws cli интерпретируют эту строку, прежде чем передать ее json-библиотеке. (Если бы это был bash, я бы понял, но зачем это может понадобится в программе на питоне выше моего понимания.)
Что бы обойти это странное поведение достаточно экранировать спецсимволы:
В принципе, для PowerShell есть и родной AWS-клиент, но мне он показался более сложным и хуже документированным.
AWS CLI, интерфейс командной строки, хорошо для этого подходит. Конечно, можно написать и приложение на Scala, но в повседневных задачах лучше обойться без «тяжелой артиллерии».
Команды AWS умеют возвращать данные в разных форматах, в том числе и в json. Можно воспользоваться bash и jq, но последнего нет в репозитарии cygwin, а руками устанавливать лень. Между тем в PowerShell есть прекрасная поддержка json! Правда оказалось, что воспользоваться этим не совсем просто.
C:\Users\mpotanin> $instance = aws ec2 describe-instances --instance-ids i-ecf1fe5c
C:\Users\...> ConvertFrom-Json $instance
ConvertFrom-Json : Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'InputObject'. Указанный метод не поддерживается.
At line:1 char:19
+ ConvertFrom-Json $instance
+ ~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [ConvertFrom-Json], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.ConvertFromJsonCommand
Дело в том, что json выдается в виде нескольких строк, и трактуется как массив. Скормить его в PowerShell можно разными способами:
$instance | ConvertFrom-Json
ConvertFrom-Json ($instance -join "")
ConvertFrom-Json "$instance"
Получить нужную информацию теперь не сложно:
(aws ec2 describe-instances --instance-ids i-ecf1fe5c | ConvertFrom-Json).Reservations[0].Instances[0].PublicIpAddress
В простых случаях извлечение информации можно перепоручить aws:
aws ec2 describe-instances --instance-ids i-ecf1fe5c --query 'Reservations[0].Instances[0].PublicIpAddress' | ConvertFrom-Json
или даже так
aws ec2 describe-instances --instance-ids i-ecf1fe5c --query 'Reservations[0].Instances[0].PublicIpAddress' --output=text
Таким образом, наблюдая странное поведение autoscaling group через консоли, я могу скопировать мышкой имя инстанса и зайти на него по ssh:
function get-address([String]$instanceId) {
aws ec2 describe-instances --instance-ids $instanceId --query 'Reservations[0].Instances[0].PublicIpAddress' | convertfrom-json
}
ssh -i devkey.pem -l ubuntu (get-address i-ecf1fe5c)
В более сложных случаях приходится уже писать нетривиальный код. Например, получить выходные параметры cloud formation стека можно следующим образом:
function reduce ($f,$a) {
if ($a.Length -eq 1) {
$a
} else {
$p = $a[0]
foreach ($x in 1..($a.Length-1)) {
$p = $f.Invoke($p,$a[$x])[0]
}
$p
}
}
function get-json($data) {
ConvertFrom-json "$data"
}
function get-cf-outputs($cfName) {
$o = (get-json(aws cloudformation describe-stacks --stack-name $cfName)).Stacks[0].Outputs
$r = foreach($i in $o) { @{$i.OutputKey = $i.OutputValue} }
reduce {param($a,$i); $a+$i } $r
}
Теперь я могу получить параметры соединения с базой данных командой
(get-cf-outputs microservice-rds-dev).DatabaseEndpoint
Передача json в команды aws cli тоже преподносит неожиданности. Например, попытка добавить запись в таблицу dynamodb просто так не удается:
C:\Users\...> aws dynamodb put-item --table-name tableName --item '{"groupId":{"S":"5"}, "ancestors":{"L":[{"S":"5"},{"S":"0"}]}}'
Error parsing parameter '--item': Invalid JSON: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
То есть где-то глубоко aws cli интерпретируют эту строку, прежде чем передать ее json-библиотеке. (Если бы это был bash, я бы понял, но зачем это может понадобится в программе на питоне выше моего понимания.)
Что бы обойти это странное поведение достаточно экранировать спецсимволы:
function put-item([string]$table, $data) {
aws dynamodb put-item --table-name $table --item (convertto-json -Depth 128 $data).Replace('\','\\').Replace('"','\"')
}
В принципе, для PowerShell есть и родной AWS-клиент, но мне он показался более сложным и хуже документированным.