I'm trying to list all of my SSM instances (both EC2 and Managed instances), but it seems that I can't do it all in one filter?
I'm using the paginator function to get the information on my instances, and then use this filter:
paginator = ssm_client.get_paginator('describe_instance_information')
response_iterator = paginator.paginate(
Filters=[
{
'Key': 'ResourceType',
'Values': [
'ManagedInstance'],
},
],
PaginationConfig={
# 'MaxItems': 100,
}
)
This filter only gets the ManagedInstance
list.
'Key': 'ResourceType',
'Values': ['ManagedInstance'],
Since the Values
value accepts a list, it seems dumb that it can't take more than one value. If I use something like this:
'Key': 'ResourceType',
'Values': ['ManagedInstance', 'EC2Instance'],
Then I would get this error:
botocore.errorfactory.InvalidInstanceInformationFilterValue: An error occurred (InvalidInstanceInformationFilterValue) when calling the DescribeInstanceInformation operation: ResourceType filter may contain only one value.
Later in my script, I'm looping over that response_iterator
variable. I'm not sure what my workaround should be if I want to loop over all of my instances (both EC2 and Managed).
My loop looks something like this:
for item in response_iterator:
for instance in item['InstanceInformationList']:
if instance.get('PingStatus') == 'Online':
instanceName = instance.get('ComputerName')
etc
What is my best option to bypass this restriction?
Also, is this a boto3 limitation or is it coming from the AWS SDK? I haven't been able to figure it out.
Edit: So one possible solution was the following:
import boto3
ssm_client = boto3.client('ssm')
ec2_client = boto3.client('ec2')
combined = []
rtypes = ['ManagedInstance', 'EC2Instance']
for rtype in rtypes:
paginator = ssm_client.get_paginator('describe_instance_information')
response_iterator = paginator.paginate(
Filters=[
{
'Key': 'ResourceType',
'Values': [rtype],
},
],
PaginationConfig={
# 'MaxItems': 10,
}
)
combined.append(list(response_iterator))
for item in combined:
for instance in item[0]['InstanceInformationList']:
if instance.get('PingStatus') == 'Online':
instanceName = instance.get('ComputerName')
print(instanceName)
It seems like it only prints 10 instances per rtype
which makes me think that the paginator doesn't do it's magic here. It's as if I'm using the regular boto3 describe_instance_information
function which in fact, does only return the first page of the SSM instances.
CodePudding user response:
You can run the paginator twice and create a list with the results. The iterate over the results. I only have one EC2 instance running so validating the nested if statement at the end is difficult to do. But this should get you started.
combined = []
rtypes = ['ManagedInstance', 'EC2Instance']
for rtype in rtypes:
paginator = ssm_client.get_paginator('describe_instance_information')
response_iterator = paginator.paginate(
Filters=[
{
'Key': 'ResourceType',
'Values': [
rtype],
},
],
PaginationConfig={
# 'MaxItems': 100,
}
)
combined.append(list(response_iterator))
print(combined)
for r in combined:
# print(r)
if len(r[0]['InstanceInformationList']) > 0:
# print(r[0]['InstanceInformationList'])
for instance in r[0]['InstanceInformationList']:
if instance.get('PingStatus') == 'Online':
instanceName = instance.get('ComputerName')
print(instanceName)
CodePudding user response:
Looks like I found a workaround. Instead of using the built in paginator, I found another method of creating the pages yourself:
import boto3
ssm_client = boto3.client('ssm')
ec2_client = boto3.client('ec2')
def fetch_instance_pages():
token = ''
while True:
# for i in range(1): # Number of pages - 10 instances per page
page = ssm_client.describe_instance_information(NextToken=token)
yield page
token = page.get('NextToken')
if not token:
break
def fetch_instances():
for page in fetch_instance_pages():
for instance in page['InstanceInformationList']:
yield instance
counter = 0
for instance in fetch_instances():
if instance.get('PingStatus') == 'Online':
counter =1
instanceName = instance.get('ComputerName')
print(counter, instanceName)
Obviously you don't need the counter, it's just there to convenience when you look at the print.