Groovy script issue with escaping quotes - amazon-web-services

I'm running this shell command using groovy (which worked in bash):
aws --profile profileName --region us-east-1 dynamodb update-item --table-name tableName --key '{"group_name": {"S": "group_1"}}' --attribute-updates '{"attr1": {"Value": {"S": "STOP"},"Action": "PUT"}}'
This updates the value of an item to STOP in DynamoDB. In my groovy script, I'm running this command like so:
String command = "aws --profile profileName --region us-east-1 dynamodb update-item --table-name tableName --key '{\"group_name\": {\"S\": \"group_1\"}}' --attribute-updates '{\"attr1\": {\"Value\": {\"S\": \"STOP\"},\"Action\": \"PUT\"}}'"
println(command.execute().text)
When I run this with groovy afile.groovy, nothing is printed out and when I check the table in DynamoDB, it's not updated to STOP. There is something wrong with the way I'm escaping the quotes but I'm not sure what. Would appreciate any insights.
Sidenote: When I do a simple aws command like aws s3 ls it works and prints out the results so it's something with this particular command that is throwing it off.

You don't quote for groovy (and the underlying exec) -- you would have to quote for your shell. The execute() on a String does not work like a shell - the underlyting code just splits at whitespace - any quotes are just passed down as part of the argument.
Use ["aws", "--profile", profile, ..., "--key", '{"group_name": ...', ...].execute() and ignore any quoting.
And instead of banging strings together to generate JSON, use groovy.json.JsonOutput.toJson([group_name: [S: "group_1"]])

Related

select part of AWS CLI query output

I want to return only the current AWS username using AWS CLI. I'm on Windows 11. I think there's a way to do it using a regex but I can't figure out how. I think I need to use a pipe along with a regex but there's no related examples on the JMESPath website. I want to have something like "only return the text after 'user/' ".
Here's what I have so far:
aws sts get-caller-identity --output text --query 'Arn'
which returns `"arn:aws:iam::999999009999:user/joe.smith"
I just want to return "joe.smith".
jmes does not support splitting a string nor matching a substring in a string, so you'll have to resort to a native command like:
> (aws sts get-caller-identity --output text --query 'Arn').Split("/")[-1]
or use something like jq :
$ aws sts get-caller-identity --output json | jq '.Arn | split("/")[-1]' -r

Filter results using Jmespath on one dimensional array

Using jmespath and given the below json, how would I filter so only JobNames starting with "analytics" are returned?
For more context, the json was returned by the aws cli command aws glue list-jobs
{
"JobNames": [
"analytics-job1",
"analytics-job2",
"team2-job"
]
}
Tried this
JobNames[?starts_with(JobNames, `analytics`)]
but it failed with
In function starts_with(), invalid type for value: None, expected one
of: ['string'], received: "null"
Above I extracted the jmespath bit, but here is the entire aws cli command I tried and failed is this
aws glue list-jobs --query '{"as_string": to_string(JobNames[?starts_with(JobNames, `analytics`)])}'
I couldn't test it on list-jobs but the query part works on list-crawlers. Just replaced the JobNames with CrawlerNames.
aws glue list-jobs --query 'JobNames[?starts_with(#, `analytics`) == `true`]'

AWS CLI list-objects by specific date

I'm trying to make a groovy script that list the objects on the AWS S3 that have been uploaded in the past three days. I installed the AWS CLI on the agent that the script runs on. The command I found that lists the objects by date is the following:
def cmd = "aws s3api list-objects --bucket (name of bucket) --query \"Contents[?LastModified>= '2018-10-16'].{Key: Key, LastModified: LastModified }\""
When I run this command on the agent directly from a putty session, it runs fine and lists the objects correctly. But when I try to execute the same command from the groovy script, I get the following error:
Bad value for --query "Contents[?LastModified: Bad jmespath expression: Unclosed " delimiter:
"Contents[?LastModified
^
I tried to replace the first and last quotation marks with single quotes but did not work. I tried to do the same thing with the quotation marks before contents and after LastModified but did not work as well. I tried passing Contents[?LastModified>= '2018-10-16'].{Key: Key, LastModified: LastModified } to a string variable and pass its value in the command after --query but that didn't work as well.
Please try:
Then try:
def date = new Date().format('yyyy-MM-dd')
def cmd = ['aws', 's3api', 'list-objects', '--bucket', 'Bucket-Name', '--query', "Contents[?LastModified>='${date}'].{Key: Key , LastModified: LastModified}"]
Remember to always pass the command as a list, not string.

aws cli returns an extra 'None' when fetching the first element using --query parameter and with --output text

I am getting an extra None in aws-cli (version 1.11.160) with --query parameter and --output text when fetching the first element of the query output.
See the examples below.
$ aws kms list-aliases --query "Aliases[?contains(AliasName,'alias/foo')].TargetKeyId|[0]" --output text
a3a1f9d8-a4de-4d0e-803e-137d633df24a
None
$ aws kms list-aliases --query "Aliases[?contains(AliasName,'alias/foo-bar')].TargetKeyId|[0]" --output text
None
None
As far as I know this was working till yesterday but from today onwards this extra None comes in and killing our ansible tasks.
Anyone experienced anything similar?
Thanks
I started having this issue in the past few days too. In my case I was querying exports from a cfn stack.
My solution was (since I'll only ever get one result from the query) to change | [0].Value to .Value, which works with --output text.
Some examples:
$ aws cloudformation list-exports --query 'Exports[?Name==`kms-key-arn`] | []'
[
{
"ExportingStackId": "arn:aws:cloudformation:ap-southeast-2:111122223333:stack/stack-name/83ea7f30-ba0b-11e8-8b7d-50fae957fc4a",
"Name": "kms-key-arn",
"Value": "arn:aws:kms:ap-southeast-2:111122223333:key/a13a4bad-672e-45a3-99c2-c646a9470ffa"
}
]
$ aws cloudformation list-exports --query 'Exports[?Name==`kms-key-arn`] | [].Value'
[
"arn:aws:kms:ap-southeast-2:111122223333:key/a13a4bad-672e-45a3-99c2-c646a9470ffa"
]
$ aws cloudformation list-exports --query 'Exports[?Name==`kms-key-arn`] | [].Value' --output text
arn:aws:kms:ap-southeast-2:111122223333:key/a13a4bad-672e-45a3-99c2-c646a9470ffa
aws cloudformation list-exports --query 'Exports[?Name==`kms-key-arn`] | [0].Value' --output text
arn:aws:kms:ap-southeast-2:111122223333:key/a13a4bad-672e-45a3-99c2-c646a9470ffa
None
I'm no closer to finding out why it's happening, but it disproves #LHWizard's theory, or at least indicates there are conditions where that explanation isn't sufficient.
The best explanation is that not every match for your query statement has a TargetKeyId. On my account, there are several Aliases that only have AliasArn and AliasName key/value pairs. The None comes from a null value for TargetKeyId, in other words.
I came across the same issue when listing step functions. I consider it to be a bug. I don't like solutions that ignore the first or last element, expecting it will always be None at that position - at some stage the issue will get fixed and your workaround has introduced a nasty bug.
So, in my case, I did this as a safe workaround (adapt to your needs):
#!/usr/bin/env bash
arn="<step function arn goes here>"
arns=()
for arn in $(aws stepfunctions list-executions --state-machine-arn "$arn" --max-items 50 --query 'executions[].executionArn' --output text); do
[[ $arn == 'None' ]] || arns+=("$arn")
done
# process execution arns
for arn in "${arns[#]}"; do
echo "$arn" # or whatever
done
Supposing you need only the first value:
Replace --output text with --output json and you could parsed with jq
Therefore, you'll have something like
Ps. the -r option with jq is to remove the quotes around the response
aws kms list-aliases --query "Aliases[?contains(AliasName,'alias/foo')].TargetKeyId|[0]" --output | jq -r '.'

AWSCli dynamodb update-item command syntax

am using AmazonAwsCli to write a shell script to update an attribute in an item in a dynamodb table. I want to update an attribute in a table for multiple items. I am reading the attribute value from a file and am trying to update the table by injecting the value of the shell script variable in the command. The documentation available at http://docs.aws.amazon.com/cli/latest/reference/dynamodb/update-item.html suggests using separate json files for expression-attribute-names and expression-attribute-values. However, I do not want to create separate json files. Rather, I want to write one command to update an item for a given attribute value.
My table name = MY_TABLE_NAME
hashkey = AccountId
shell script variable holding the value of AccountId = accountId
attribute name that needs to be updated = Version
shell script variable holding the value of Version = ver
I have got something like :
aws dynamodb update-item --table-name MY_TABLE_NAME --key '{"AccountId": {"S": '$accountId'}}' --update-expression "SET Version = '{"Version": {"S": '$ver'}}'" --condition-expression "attribute_exists(Version)" --return-values UPDATED_NEW
But, the above command does not work. Can someone point me to the correct syntax.
My AwsCli version did not support --update-expression option. I used the attribute-updates option instead.
Here is my command :
updatedVersion=aws dynamodb update-item --table-name MY_TABLE_NAME --key '{"AccountId": {"S": '$accountId'}}' --attribute-updates '{"Version": {"Value": {"S": '$desiredVersion'},"Action": "PUT"}}' --return-values UPDATED_NEW | jq '.Attributes.RuleSetVersion.S'
Below is the update command with --update-expression
aws --region "us-east-1" dynamodb update-item \
--table-name "MY_TABLE_NAME" --key \
'{"Primary_Column_name":{"S":"Primary_Column_value"}}' \
--update-expression 'SET #H = :h' \
--expression-attribute-names '{"#H":"Column_name_to_change"}' \
--expression-attribute-values '{":h":{"S":"Changed_Column_value"}}'
The other answers will work very good on MAC and Linux.
If you want to run it on Windows, you need to use " quotes instead of ' and double quotes "" instead of a single quote "`"
Example:
aws dynamodb update-item --table-name MY_TABLE_NAME --key "{""PRIMARY_KEY_NAME"":{""S"":""PRIMARY_KEY_VALUE""}}" --update-expression "SET #G = :g" --expression-attribute-names "{""#G"":""COLUMN_NAME_TO_UPDATE_VALUE""}" --expression-attribute-values "{"":g"":{""N"":""DESIRED_VALUE""}}"