antoniuslin
antoniuslin

Reputation: 249

Cleaner way to use jq selection

The background of my question is loaded; but I'd like to focus on just the jq portion in this current piece (although if you could help in its entirety, it'd be so very much welcomed and appreciated).

I have a Terraform spec that I've successfully applied to create an autoscaling group in AWS (re: Terraform provisioning I will ask on a separate question, if perhaps there's a better way than what I'm doing). I had wanted to run some provisioning in each of the produced instances, and in so doing, I decided to couple it with an ansible command.

Ansible, as you may know, runs on inventory/host file. Consequently, I'd have to update my host file each time AWS scales up or down in order to successfully run the following ansible ad-hoc command ansible -i ./myansible.hostfile myawsinstances -a "reprovisioning_command" (which itself has a different set of issues, tbd.)

On the part of creating the ansible host file, I got what I needed using the following command:

command sample 1

aws ec2 describe-instances | jq .Reservations[].Instances[].PublicIpAddress | sed 's/"//g' | awk '{print "inst"$1 " ansible_ssh_host="$1 " ansible_ssh_user=ubuntu"}' > myansible.hostfile

output sample 1 in myansible.hostfile

inst[ip_no1] ansible_ssh_host=[ip_no1] ansible_ssh_user=ubuntu
inst[ip_no2] ansible_ssh_host=[ip_no2] ansible_ssh_user=ubuntu

It seems to me rather long and somewhat convoluted.

If I were to just use jq alone along with its string operation facilities, such as:

command sample 2

aws ec2 describe-instances | jq '"inst" + .Reservations[].Instances[].PublicIpAddress + " ansible_ssh_hosts=" + .Reservations[].Instances[].PublicIpAddress + " ansible_ssh_user=ubuntu"' > myansible.hostfile

I would receive dupes of the output like so:

output sample 2 in myansible.hostfile

inst[ip_no1] ansible_ssh_host=[ip_no1] ansible_ssh_user=ubuntu
inst[ip_no2] ansible_ssh_host=[ip_no2] ansible_ssh_user=ubuntu
inst[ip_no1] ansible_ssh_host=[ip_no1] ansible_ssh_user=ubuntu
inst[ip_no2] ansible_ssh_host=[ip_no2] ansible_ssh_user=ubuntu

Presumably because I'm calling the object selectors twice in the same command. The question is:

a. Is there a cleaner command expression that I could use instead of (command sample 1) to achieve the same (output sample 1)?

b. What would be the correct way to strictly use jq command like in (command sample 2) in order to produce the desired (output sample 1) without dupes like in the (output sample 2)?

Thanks much in advance.

Upvotes: 1

Views: 370

Answers (2)

ydaetskcoR
ydaetskcoR

Reputation: 56877

I'm not sure why you're setting an Ansible inventory name that includes the IP address as this seems pretty pointless to me as it doesn't give it a human readable name or add anything useful compared to just using the IP address.

If you're happy with ditching that requirement then in reality you can just use the query option of the AWS CLI and ditch jq and your formatting:

cat <<EOF > hosts-file.ini
[all:vars]
ansible_ssh_user=ubuntu

[all]
EOF
aws ec2 describe-instances --query 'Reservations[*].Instances[*].PublicIpAddress' --output text >> hosts-file.ini

This will set some inline vars at the all level to set the SSH user to be ubuntu and then dump all of the EC2 instance's public IP addresses under the all block.

Upvotes: 1

peak
peak

Reputation: 116780

First, jq's -r option will remove the outermost quotation marks from JSON string outputs.

Second, the following jq filter, used in conjunction with the aforementioned -r option, should be sufficient to achieve your goals, though it's hard to verify since you haven't provided an MCVE:

.Reservations[].Instances[].PublicIpAddress
| "inst" + . + " ansible_ssh_hosts=" + . + " ansible_ssh_user=ubuntu"

Upvotes: 2

Related Questions