Home > Software engineering >  SSM Describe Instance Information can only accept 1 value in the filter
SSM Describe Instance Information can only accept 1 value in the filter

Time:10-05

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.

  • Related