I want to list volume's snapshots but in the output I would like to also see the Name of that volume (I mean tag).
So far I was using:
aws ec2 describe-snapshots
And in the reply I got something like:
Snapshots: [
{
"Description": "some description",
"Encrypted": false,
"OwnerId": "someownerid",
"Progress": "100%",
"SnapshotId": "snap-example",
"StartTime": "start time",
"State": "completed",
"VolumeId": "volume id",
"VolumeSize": 32
}
]
But what I would like to have in that output is also a volume name:
Snapshots: [
{
"Description": "some description",
"Encrypted": false,
"OwnerId": "someownerid",
"Progress": "100%",
"SnapshotId": "snap-example",
"StartTime": "start time",
"State": "completed",
"VolumeId": "volume id",
"VolumeSize": 32,
"VolumeName": "Volume Name" #additional key:val
}
]
The aws ec2 describe-snapshots does return tags on snapshots if they are present.
Something similar to this:
{
"Description": "This snapshot is created by the AWS Backup service.",
"Tags": [
{
"Value": "On",
"Key": "Backup"
},
{
"Value": "Jenkins_Machine",
"Key": "Name"
},
{
"Value": "*********",
"Key": "aws:backup:source-resource"
}
],
"Encrypted": false,
"VolumeId": "vol-*****",
"State": "completed",
"VolumeSize": 250,
"StartTime": "2019-08-01T11:29:31.654Z",
"Progress": "100%",
"OwnerId": "******",
"SnapshotId": "snap-******"
}
To be able to see the name (Assuming your snapshots have them) do this:
aws ec2 describe-snapshots --snapshot-id snap-**** --query 'Snapshots[*].{Description:Description,Name:Tags[?Key==`Name`].Value|[0],State:State}'
This should give you output like this:
[
{
"State": "completed",
"Description": "This snapshot is created by the AWS Backup service.",
"Name": "Jenkins_Machine"
}
]
The fields are curtailed but you can add fields that you need at the end of the query like this ...State:State,VolumeId:VolumeId}, where I have newly added the VolumeId.
If you remove the --snapshot-id parameter, the above command should return you all snapshots, however for snapshots that don't have the Name tag its going to print null.
Edit:
As #krishna_mee2004 pointed out, the OP is probably looking for snapshots for a particular volume. If that is the case you can still do it using this command. The filters option can be used to filter based on volume ID.
aws ec2 describe-snapshots --filters Name=volume-id,Values=vol-***** --query 'Snapshots[*].{Description:Description,Name:Tags[?Key==`Name`].Value|[0],State:State,VolumeId:VolumeId}'
If you are referring to snapshot's name tag, you can write a simple python or ruby script using aws sdk. For example, a ruby code to list the snapshot id and value of its name tag will look like this:
require 'aws-sdk'
# provide region and credentials in parameter
ec2 = Aws::EC2::Client.new
# paginate if you have a big list
resp = ec2.describe_snapshots
# iterate snapshots
resp.snapshots.each do |snapshot|
# iterate tags and print if it has a name tag.
snapshot.tags.each do |tag|
# print whatever is required/available in the response structure
puts "#{snapshot.snapshot_id} has the name tag with value #{tag.value}" if tag.key.casecmp? 'Name'
end
end
Refer the respective language api documentation to understand more about the usage of the sdk and the api calls. Make sure to setup the sdk before using and it varies based on the language you choose. For example, steps for setting up the ruby sdk is outlined here. You may also want to checkout the API reference for describe_snaphots used in the above code.
Related
I have private snapshots in one account (source) that I have shared with another account (target). I am able to see the snapshots themselves from the target account, but the tags are not available, neither on the console nor via the cli. This makes it impossible to filter for a desired snapshot from the target account. For background, the user in the target account has the following policy in effect:
"Effect": "Allow",
"Action": "ec2:*",
"Resource": "*"
Here's an example of what I'm seeing; from the source account:
$ aws --region us-east-2 ec2 describe-snapshots --snapshot-ids snap-XXXXX
{
"Snapshots": [
{
"Description": "snapshot for testing",
"VolumeSize": 50,
"Tags": [
{
"Value": "test-snapshot",
"Key": "Name"
}
],
"Encrypted": true,
"VolumeId": "vol-XXXXX",
"State": "completed",
"KmsKeyId": "arn:aws:kms:us-east-2:XXXXX:key/mrk-XXXXX",
"StartTime": "2022-04-19T18:29:36.069Z",
"Progress": "100%",
"OwnerId": "XXXXX",
"SnapshotId": "snap-XXXXX"
}
]
}
but from the target account
$ aws --region us-east-2 ec2 describe-snapshots --owner-ids 012345678900 --snapshot-ids snap-11111111111111111
{
"Snapshots": [
{
"Description": "snapshot for testing",
"VolumeSize": 50,
"Encrypted": true,
"VolumeId": "vol-22222222222222222",
"State": "completed",
"KmsKeyId": "arn:aws:kms:us-east-2:012345678900:key/mrk-00000000000000000000000000000000",
"StartTime": "2022-04-19T18:29:36.069Z",
"Progress": "100%",
"OwnerId": "012345678900",
"SnapshotId": "snap-11111111111111111"
}
]
}
Any ideas on what's going on here?
Cheers!
From https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html#tag-restrictions
When you tag public or shared resources, the tags you assign are
available only to your AWS account; no other AWS account will have
access to those tags. For tag-based access control to shared
resources, each AWS account must assign its own set of tags to control
access to the resource.
I'm a beginner in using AWS.
I just want to stop and start several EC2 instances automatically and periodically(Not reboot).
Is there any recommended way to do this?
Amazon recently (Feb 2018) released the EC2 instance scheduler tool:
The AWS Instance Scheduler is a simple AWS-provided solution that
enables customers to easily configure custom start and stop schedules
for their Amazon Elastic Compute Cloud (Amazon EC2) and Amazon
Relational Database Service (Amazon RDS) instances. The solution is
easy to deploy and can help reduce operational costs for both
development and production environments. Customers who use this
solution to run instances during regular business hours can save up to
70% compared to running those instances 24 hours a day.
I had this up and running in my account in 15 minutes; very simple to use, and practically free.
https://aws.amazon.com/answers/infrastructure-management/instance-scheduler/
AWS has a good doc explaining how you can achieve this using Lambda and Cloudwatch events. You can refer it - https://aws.amazon.com/premiumsupport/knowledge-center/start-stop-lambda-cloudwatch/
This solution can be modified to get the EC2 list dynamically, or operate on a set of instances which can be identified based on a certain tag.
Yes, you can do that using AWS Lambda. You can select the trigger in Cloudwatch which runs on Cron expressions on UTC.
Here is a related link https://aws.amazon.com/premiumsupport/knowledge-center/start-stop-lambda-cloudwatch/
Another alternative is to use awscli which is available from pip, apt-get, yum or brew, and then running aws configure with your credentials from IAM and executing the following bash script, to stop an EC2 that has been tagged with Name: Appname and Value: Appname Prod. You can use awscli to tag your instances or tag it manually from the AWS console. aws ec2 stop-instances will stop the instance and jq is used to filter the json query and fetch the correct instance id using the tags from aws ec2 describe-instances.
To verify that aws configure was successful and returns json output run aws ec2 describe-instances and your running instance id should be there in the output. Here is a sample output
{
"Reservations": [
{
"Instances": [
{
"Monitoring": {
"State": "disabled"
},
"PublicDnsName": "ec2-xxx.ap-south-1.compute.amazonaws.com",
"State": {
"Code": xx,
"Name": "running"
},
"EbsOptimized": false,
"LaunchTime": "20xx-xx-xxTxx:16:xx.000Z",
"PublicIpAddress": "xx.127.24.xxx",
"PrivateIpAddress": "xxx.31.3.xxx",
"ProductCodes": [],
"VpcId": "vpc-aaxxxxx",
"StateTransitionReason": "",
"InstanceId": "i-xxxxxxxx",
"ImageId": "ami-xxxxxxx",
"PrivateDnsName": "ip-xxxx.ap-south-1.compute.internal",
"KeyName": "node",
"SecurityGroups": [
{
"GroupName": "xxxxxx",
"GroupId": "sg-xxxx"
}
],
"ClientToken": "",
"SubnetId": "subnet-xxxx",
"InstanceType": "t2.xxxxx",
"NetworkInterfaces": [
{
"Status": "in-use",
"MacAddress": "0x:xx:xx:xx:xx:xx",
"SourceDestCheck": true,
"VpcId": "vpc-xxxxxx",
"Description": "",
"NetworkInterfaceId": "eni-xxxx",
"PrivateIpAddresses": [
{
"PrivateDnsName": "ip-xx.ap-south-1.compute.internal",
"PrivateIpAddress": "xx.31.3.xxx",
"Primary": true,
"Association": {
"PublicIp": "xx.127.24.xxx",
"PublicDnsName": "ec2-xx.ap-south-1.compute.amazonaws.com",
"IpOwnerId": "xxxxx"
}
}
],
"PrivateDnsName": "ip-xxx-31-3-xxx.ap-south-1.compute.internal",
"Attachment": {
"Status": "attached",
"DeviceIndex": 0,
"DeleteOnTermination": true,
"AttachmentId": "xxx",
"AttachTime": "20xx-xx-30Txx:16:xx.000Z"
},
"Groups": [
{
"GroupName": "xxxx",
"GroupId": "sg-xxxxx"
}
],
"Ipv6Addresses": [],
"OwnerId": "xxxx",
"PrivateIpAddress": "xx.xx.xx.xxx",
"SubnetId": "subnet-xx",
"Association": {
"PublicIp": "xx.xx.xx.xxx",
"PublicDnsName": "ec2-xx.ap-south-1.compute.amazonaws.com",
"IpOwnerId": "xxxx"
}
}
],
"SourceDestCheck": true,
"Placement": {
"Tenancy": "default",
"GroupName": "",
"AvailabilityZone": "xx"
},
"Hypervisor": "xxx",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/xxx",
"Ebs": {
"Status": "attached",
"DeleteOnTermination": true,
"VolumeId": "vol-xxx",
"AttachTime": "20xxx-xx-xxTxx:16:xx.000Z"
}
}
],
"Architecture": "x86_64",
"RootDeviceType": "ebs",
"RootDeviceName": "/dev/xxx",
"VirtualizationType": "xxx",
"Tags": [
{
"Value": "xxxx centxx",
"Key": "Name"
}
],
"AmiLaunchIndex": 0
}
],
"ReservationId": "r-xxxx",
"Groups": [],
"OwnerId": "xxxxx"
}
]
}
The following bash script is stop-ec2.sh in /home/centos/cron-scripts/
(instance=$(aws ec2 describe-instances | jq '.Reservations[].Instances | select(.[].Tags[].Value | startswith("Appname Prod") ) | select(.[].Tags[].Key == "Appname") | {InstanceId: .[].InstanceId, PublicDnsName: .[].PublicDnsName, State: .[].State, LaunchTime: .[].LaunchTime, Tags: .[].Tags} | [.]' | jq -r .[].InstanceId) && aws ec2 stop-instances --instance-ids ${instance} )
Run the file using sh /home/centos/cron-scripts/stop-ec2.sh and verify that the EC2 instance gets stopped. To debug run aws ec2 describe-instances | jq '.Reservations[].Instances | select(.[].Tags[].Value | startswith("Appname Prod") ) | select(.[].Tags[].Key == "Appname") | {InstanceId: .[].InstanceId, PublicDnsName: .[].PublicDnsName, State: .[].State, LaunchTime: .[].LaunchTime, Tags: .[].Tags} | [.]' | jq -r .[].InstanceId and see that it returns the correct instance ID which has been tagged.
Then in crontab -e the following line can be added
30 14 * * * sh /home/centos/cron-scripts/stop-ec2.sh >> /tmp/stop
which will log the output to /tmp/stop. The 30 14 * * * is the UTC cron expression that you can check in https://crontab.guru/
Lambda script to stop instance:
import json
import boto3
# Enter the region your instances are in. Include only the region without specifying Availability Zone; e.g., 'us-east-1'
region = 'us-east-1'
def lambda_handler(event, context):
ec2 = boto3.client('ec2', region_name=region)
filter = [{'Name': 'tag:Name', 'Values': ['****-env']}] //give instance name here in place of ****-env
instances = ec2.describe_instances(Filters=filter)
#ec2.stop_instances(InstanceIds=instances)
stop_instance = instances.get('Reservations')[0].get('Instances')[0].get('InstanceId')
stop_instances = []
stop_instances.append(stop_instance)
ec2.stop_instances(InstanceIds=stop_instances)
Lambda script to start instance:
import json
import boto3
# Enter the region your instances are in. Include only the region without specifying Availability Zone; e.g., 'us-east-1'
region = 'us-east-1'
def lambda_handler(event, context):
ec2 = boto3.client('ec2', region_name=region)
filter = [{'Name': 'tag:Name', 'Values': ['****-env']}]
instances = ec2.describe_instances(Filters=filter)
#ec2.stop_instances(InstanceIds=instances)
start_instance = instances.get('Reservations')[0].get('Instances')[0].get('InstanceId')
start_instances = []
start_instances.append(start_instance)
ec2.start_instances(InstanceIds=start_instances)
ASG scheduler is the best and easiest option to mange the EC2 instance if you are using ASG. If not using ASG, then you can use either AWS instance scheduler CF solution or lambda with cloudwatch Cron event.
I have existing infrastructure in us-east-1 region which needed to be cloned exactly to us-east-2 region. Used AWS CloudFormer to generate the JSON template from existing us-east-1 region, replaced all the us-east-1 with us-east-2 and started creating the stack but getting errors saying "Resource creation cancelled", specifically for all the EC2 instances
A snapshot of the template (only EC2 instance):
"instancei071dd59b": {
"Type": "AWS::EC2::Instance",
"Properties": {
"DisableApiTermination": "false",
"InstanceInitiatedShutdownBehavior": "stop",
"ImageId": "ami-1a41b377",
"InstanceType": "t2.medium",
"KeyName": "MyServer",
"Monitoring": "false",
"Tags": [
{
"Key": "MyServer OS",
"Value": "Windows Server"
},
{
"Key": "Name",
"Value": "MyServer_WEB_TEST_2"
}
],
"Volumes": [
{
"Device": "xvdb",
"VolumeId": {
"Ref": "volumevol9124b841"
}
}
],
"NetworkInterfaces": [
{
"DeleteOnTermination": "true",
"DeviceIndex": 0,
"SubnetId": {
"Ref": "subnet24031c0f"
},
"PrivateIpAddresses": [
{
"PrivateIpAddress": "172.31.53.184",
"Primary": "true"
}
],
"GroupSet": [
{
"Ref": "sgMyServerWEB"
}
],
"AssociatePublicIpAddress": "true"
}
]
}
},
"volumevol9124b841": {
"Type": "AWS::EC2::Volume",
"Properties": {
"AvailabilityZone": "us-east-2b",
"Size": "30",
"SnapshotId": "snap-95288b92",
"VolumeType": "gp2"
}
}
Before going with cloudformation template you will need to make sure you have following things in place :
Move your instance AMI to us-east-2 region then replace the snapshot id and AMI id in your template
Create a security group replace the security group id in your template
Replace subnet ID in your CF template with the one in us-east-2 region
The reason you will have to do this is every resource on AWS has unique IDs which cannot be replicated, if you want to replicate same you will need different Ids for that you need to create seperate resources and use them in your template.
If your doing this for a single instance only then you might do it manually by exporting AMI to us-east-2 region.
For collecting AMI ID in different region, I'd recommend to use the image name instead the AMI ID as the key.
To build resources to be placed in different regions, definitely is better to use CloudFormation. In this case you can use the lambda cli2cloudformation (https://github.com/lucioveloso/cli2cloudformation).
Using it, you can get the AMI ID across all regions and whatever other information that you are able to get using CLI.
To collect the AMI ID, create a lambda with cli2cloudformation and inside your template, create a custom resource as bellow:
"imageIdNameBased": {
"Type": "Custom::cli2cfnLambda",
"Properties": {
"ServiceToken": "arn:aws:lambda:eu-west-1:123456789012:function:cli2cfnLambda",
"CliCommandCreate": "ec2 describe-images --filters 'Name=name,Values=amzn-ami-hvm-2017.03.0.20170417-x86_64-gp2' --query 'Images[0]'"
}
}
In this case, I'm getting the AMI ID to the Image named 'amzn-ami-hvm-2017.03.0.20170417-x86_64-gp2'. You can change to your image name.
After that, you can retrieve it in any point of your CloudFormation stack.
"Fn::GetAtt" : ["imageIdNameBased", "ImageId"]
I've built a CloudWatch dashboard, and I'd like to display it on a wall-mounted screen. The problem I'm facing is access: I'm using an IAM user with limited privileges to connect to the dashboard, and the user gets disconnected after 12 hours.
However, I'd like to show the dashboard indefinitely, and I don't want to have to manually login every day.
Is there a better way to publish an AWS CloudWatch dashboard? Is there a way for sessions to last longer?
You could use the GetMetricWidgetImage API or get-metric-widget-image command to achieve that.
An example get-metric-widget-image command line:
aws cloudwatch get-metric-widget-image --metric-widget '
{
"metrics": [
[ { "expression": "AVG(METRICS())", "label": "Average Access Speed", "id": "e1", "region": "eu-central-1" } ],
[ "...", "www.xyz.ee", { "label": "[avg: ${AVG}] www.xyz.ee", "id": "m2", "visible": false } ],
[ "...", "www.abc.com", { "label": "[avg: ${AVG}] www.abc.com", "id": "m3", "visible": false } ],
],
"view": "timeSeries",
"stacked": false,
"region": "eu-central-1",
"title": "Response Time",
"period": 300,
"stat": "Average"
}
' | jq -r .MetricWidgetImage | base64 -d | display
In order to get the metric-widget source, it is the easiest to go the cloudwatch dashboard, select the widget for editing, and select the "Source" tab. There you can copy the source code and use it in the above command line.
There is an also a thread about how to use the command: How to use aws cloudwatch get-metric-widget-image?
Amazon EC2 pricing api provides different attributes for each type of pricing, how am i able to know under which pricing my ec2 instance is running. Because in pricing api i.e. json file, amazon provides few attributes and out of these attributes i am only able to fetch instanceType from inside of an instance. how to get others?
[
{
"TDVRYW6K68T4XJHJ.JRTCKXETXF": {
"effectiveDate": "2016-01-01T00:00:00Z",
"offerTermCode": "JRTCKXETXF",
"priceDimensions": {
"TDVRYW6K68T4XJHJ.JRTCKXETXF.6YS6EN2CT7": {
"appliesTo": [],
"beginRange": "0",
"description": "$4.900 per On Demand Linux hs1.8xlarge Instance Hour",
"endRange": "Inf",
"pricePerUnit": {
"USD": "4.9000000000"
},
"rateCode": "TDVRYW6K68T4XJHJ.JRTCKXETXF.6YS6EN2CT7",
"unit": "Hrs"
}
},
"sku": "TDVRYW6K68T4XJHJ",
"termAttributes": {}
},
"attributes": {
"clockSpeed": "2 GHz",
"currentGeneration": "No",
"instanceFamily": "Storage optimized",
"instanceType": "hs1.8xlarge",
"licenseModel": "No License required",
"location": "EU (Ireland)",
"locationType": "AWS Region",
"memory": "117 GiB",
"networkPerformance": "10 Gigabit",
"operatingSystem": "Linux",
"operation": "RunInstances",
"physicalProcessor": "Intel Xeon E5-2650",
"preInstalledSw": "NA",
"processorArchitecture": "64-bit",
"servicecode": "AmazonEC2",
"storage": "24 x 2000",
"tenancy": "Shared",
"usagetype": "EU-BoxUsage:hs1.8xlarge",
"vcpu": "17"
}
}
]
1) find your instance size and AZ. For example
[ec2-user#ip-10-50-1-171 temp]$ ec2-metadata |grep placement
placement: eu-west-1a
[ec2-user#ip-10-50-1-171 temp]$ ec2-metadata |grep instance-type
instance-type: t2.micro
2) pull the correct file for the pricing of the EC2, for example at the moment it is
https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/current/index.json
3) within this file there are "products". So for instance within the products find a t2.micro for eu-west
"SYEPG42MVWFMUBT6" : {
"sku" : "SYEPG42MVWFMUBT6",
"productFamily" : "Compute Instance",
"attributes" : {
"servicecode" : "AmazonEC2",
"location" : "EU (Ireland)",
"locationType" : "AWS Region",
"instanceType" : "t2.micro",
"instanceFamily" : "General purpose",
"vcpu" : "1",
"physicalProcessor" : "Intel Xeon Family",
"clockSpeed" : "Up to 3.3 GHz",
"memory" : "1 GiB",
"storage" : "EBS only",
"networkPerformance" : "Low to Moderate",
"processorArchitecture" : "32-bit or 64-bit",
"tenancy" : "Shared",
"operatingSystem" : "SUSE",
"licenseModel" : "No License required",
"usagetype" : "EU-BoxUsage:t2.micro",
"operation" : "RunInstances:000g",
"preInstalledSw" : "NA",
"processorFeatures" : "Intel AVX; Intel Turbo"
}
},
Note the SKU for this product
4) next find the "terms" section in the json file. There are sections for "OnDemand" and "Reserved". In "OnDemand" the SKU for the product of interest (in the example above SYEPG42MVWFMUBT6) is mentioned once. In the "Reserved" there are several entries with different terms
If you need to do all these steps programmatically you'd have to use either a shell script and a tool like jq or a library for json processing like the one included with python
I know this question is old, and I don't have any definitive proof (someone please correct me if its wrong) But through experimenting I've found that to get your specific running instance cost, you really cannot use a combination of the EC2 Metadata and the https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/price-changes.html API.
This is because the information returned from the price API is for current offers available in the near term for instances to be purchased not your specific running instance.
Specifically what you would want to find is the Ratecode associated with your specific instance, and this is not found through calling DescribeInstances. You can apply a series of filters to get a pretty good guess, as to what the instance cost is likely for a specific instance running in your account. However, I am unable to uniquely define a specific instance even with some specific filters like the following
{
Filters: [
{
Type: 'TERM_MATCH',
Field: 'ServiceCode',
Value: 'AmazonEC2',
},
{
Type: 'TERM_MATCH',
Field: 'regionCode',
Value: 'us-east-1',
},
{
Type: 'TERM_MATCH',
Field: 'instanceType',
Value: 't3.medium',
},
{
Type: 'TERM_MATCH',
Field: 'marketoption',
Value: 'OnDemand',
},
{
Type: 'TERM_MATCH',
Field: 'operatingSystem',
Value: 'Linux',
},
{
Type: 'TERM_MATCH',
Field: 'tenancy',
Value: 'Shared',
},
],
FormatVersion: 'aws_v1',
NextToken: null,
ServiceCode: 'AmazonEC2',
};
(The above filter returns like ~50 different price offerings when used to query the GetProductsAPI )
If its any help here is some code I've been using to muck around
I haven't tested it but it might just be easier to Crawl the pricing page
EDIT:
I worked with AWS support a bit and found a workable solution set of filters. Copying the response from AWS here:
I understand that you want to use aws price list query API to output the pricing of onDemand t3.medium instance, however it is throwing results for lot of instances of same instance type instead of getting output for the exact ec2 instance your queried for.
I was able to reproduce the same behavior from my end when I used the same filters you provided over an aws cli get-products request1. After digging into this a bit, I was able to substantially bring down the search result using the below filters with the help of a guide2.
Command:
aws pricing get-products --filters file://filters2.json --format-version aws_v1 --service-code AmazonEC2
Filter json file:
[
{
"Type": "TERM_MATCH",
"Field": "ServiceCode",
"Value": "AmazonEC2"
},
{
"Type": "TERM_MATCH",
"Field": "regionCode",
"Value": "us-east-1"
},
{
"Type": "TERM_MATCH",
"Field": "instanceType",
"Value": "t3.medium"
},
{
"Type": "TERM_MATCH",
"Field": "marketoption",
"Value": "OnDemand"
},
{
"Type": "TERM_MATCH",
"Field": "operatingSystem",
"Value": "Linux"
},
{
"Type": "TERM_MATCH",
"Field": "tenancy",
"Value": "Shared"
},
{
"Type": "TERM_MATCH",
"Field": "preInstalledSw",
"Value": "NA"
},
{
"Type": "TERM_MATCH",
"Field": "licenseModel",
"Value": "No License required"
},
{
"Type": "TERM_MATCH",
"Field": "capacitystatus",
"Value": "Used"
}
]
The following were the results in a nutshell:
On Demand Instance price for the instance matched in filter.
Reserved Instances:
2.1: Term: 1 year or 3 year
2.2: Upfront: none, partial or all
2.3: Convertable: standard or convertable
I understand that you have applied a filter that matches key value 'marketoption:OnDemand', but in the output there is a seperate category called "terms" within "serviceCode" key. The terms then is then a nested array containing different keys for 'OnDemand' and 'Reserved' etc which would not be filtered by the above filters normally.
As for a workaround to filter out just the pricing of On Demand instance, I am afraid you would have to create custon json query to filter out only the values of the On demand instance returned from the output of the updated script.