boto3 aws api - Listing available instance types

拜拜、爱过 提交于 2019-11-30 19:26:43

The EC2 API does not provide a way to get a list of all EC2 instance types. I wish it did. Some people have cobbled together their own lists of valid types by scraping sites like this but for now that is the only way.

This information can be retrieved in the JSON provided by the recently-announced AWS Price List API. As a simple example using the Python requests module:

#!/usr/bin/env python
# List EC2 Instance Types
# see: https://aws.amazon.com/blogs/aws/new-aws-price-list-api/

import requests

offers = requests.get(
    'https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/index.json'
)
ec2_offer_path = offers.json()['offers']['AmazonEC2']['currentVersionUrl']
ec2offer = requests.get(
    'https://pricing.us-east-1.amazonaws.com%s' % ec2_offer_path
).json()

uniq = set()
for sku, data in ec2offer['products'].items():
    if data['productFamily'] != 'Compute Instance':
        # skip anything that's not an EC2 Instance
        continue
    uniq.add(data['attributes']['instanceType'])
for itype in sorted(uniq):
    print(itype)

Note that this might take a while... as of today, the current EC2 Offers JSON file ( https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/current/index.json ) is 173MB, so it takes a while both to retrieve and to parse. The current result is 99 distinct instance types.

Try this

'''
Created on Mar 22, 2017

@author: ijessop
'''

import boto3
import urllib2
from bs4 import BeautifulSoup as soup

class EnumEc2():

    def __init__(self, region):

        self.client = boto3.client(
                                   'ec2',
                                   aws_access_key_id = 'YOUR_KEY' ,  
                                   aws_secret_access_key='YOUR_SECRET',
                                   region_name = region
                                   )
        self.instance_types = None
        self.instance_table_headers = None
        self.max_col_width = {}


    def getInstanceTypes(self):
        mp = soup(urllib2.urlopen('https://aws.amazon.com/ec2/instance-types').read(),'html.parser')
        imx = mp.find(id="instance-type-matrix")
        trs = imx.parent.parent.parent.next_sibling.next_sibling.find_all('tr')

        rt = []
        first_row = True
        for trow in trs:
            td_strs = []

            for td in trow.find_all("td"):
                td_nested = []
                for s in td.strings:
                    s.strip()
                    td_nested.append(s)

                td_all = " ".join(td_nested).strip()
                td_strs.append(td_all)

            if first_row is True:
                header_row = td_strs
                for head in header_row:
                    self.max_col_width.update({head:(len(head) + 2)})
                first_row = False

            else:
                dr = dict(zip(header_row,td_strs))
                for k,v in dr.items():
                    cw = len(v)
                    if k in self.max_col_width.keys():
                        if cw >= self.max_col_width.get(k):
                            self.max_col_width.update({k:(cw +2)})

                    else:
                        self.max_col_width.update({k:cw})

                rt.append(dr)

        self.instance_table_headers = header_row
        self.instance_types = rt



if __name__ == '__main__':

    myen = EnumEc2('us-west-2')
    myen.getInstanceTypes()
    heads_I_want_to_see = ['Instance Type', u'vCPU', u'Memory (GiB)', u'Storage (GB)','Physical Processor', u'Clock Speed (GHz)']
    out_str ="|"
    for h in heads_I_want_to_see:
        out_str = "%s%s|" % (out_str,h.ljust(myen.max_col_width.get(h)))
    print "%s" % "-" * len(out_str)
    print "%s" % out_str
    print "%s" % "-" * len(out_str)
    for i in myen.instance_types:
        out_str ="|"
        for k in myen.instance_table_headers: # to preserve the table column order
            if k in heads_I_want_to_see:
                out_str = "%s%s|" % (out_str, i.get(k).ljust(myen.max_col_width.get(k)))
        print "%s" % out_str
        print "%s" % "-" * len(out_str)
gougou maomao

I need it too, however, there are no suitable codes for this purpose. I modify one by myself. Enjoy! May someone need it also.

Following code is modified from libcloud/contrib/scrape-ec2-prices.py And this program will generate a dict about available instance types

#!/usr/bin/env python

import os
import re
import json
import time
from collections import defaultdict, OrderedDict

import requests
import demjson

LINUX_PRICING_URLS = [
    # Deprecated instances (JSON format)
    'https://aws.amazon.com/ec2/pricing/json/linux-od.json',
    # Previous generation instances (JavaScript file)
    'https://a0.awsstatic.com/pricing/1/ec2/previous-generation/linux-od.min.js',
    # New generation instances (JavaScript file)
    'https://a0.awsstatic.com/pricing/1/ec2/linux-od.min.js'
]

EC2_REGIONS = [
    'us-east-1',
    'us-east-2',
    'us-west-1',
    'us-west-2',
    'us-gov-west-1',
    'eu-west-1',
    'eu-west-2',
    'eu-central-1',
    'ca-central-1',
    'ap-southeast-1',
    'ap-southeast-2',
    'ap-northeast-1',
    'ap-northeast-2',
    'ap-south-1',
    'sa-east-1',
    'cn-north-1',
]

INSTANCE_SIZES = [
    'micro',
    'small',
    'medium',
    'large',
    'xlarge',
    'x-large',
    'extra-large'
]

RE_NUMERIC_OTHER = re.compile(r'(?:([0-9]+)|([-A-Z_a-z]+)|([^-0-9A-Z_a-z]+))')

PRICING_FILE_PATH = './price.json'
PRICING_FILE_PATH = os.path.abspath(PRICING_FILE_PATH)


def scrape_ec2_pricing():
    result = {}
    result['regions'] = []
    result['prices'] = defaultdict(OrderedDict)
    result['models'] = defaultdict(OrderedDict)

    for url in LINUX_PRICING_URLS:
        response = requests.get(url)

        if re.match('.*?\.json$', url):
            data = response.json()
        elif re.match('.*?\.js$', url):
            data = response.content
            match = re.match('^.*callback\((.*?)\);?$', data,
                             re.MULTILINE | re.DOTALL)
            data = match.group(1)
            # demjson supports non-strict mode and can parse unquoted objects
            data = demjson.decode(data)

        regions = data['config']['regions']

        for region_data in regions:

            region_name = region_data['region']

            if region_name not in result['regions']:
                result['regions'].append(region_name)

            libcloud_region_name = region_name
            instance_types = region_data['instanceTypes']

            for instance_type in instance_types:
                sizes = instance_type['sizes']
                for size in sizes:

                    price = size['valueColumns'][0]['prices']['USD']
                    if str(price).lower() == 'n/a':
                        # Price not available
                        continue

                    if not result['models'][libcloud_region_name].has_key(size['size']):
                        result['models'][libcloud_region_name][size['size']] = {}
                        result['models'][libcloud_region_name][size['size']]['CPU'] = int(size['vCPU'])

                        if size['ECU'] == 'variable':
                            ecu = 0
                        else:
                            ecu = float(size['ECU'])

                        result['models'][libcloud_region_name][size['size']]['ECU'] = ecu

                        result['models'][libcloud_region_name][size['size']]['memoryGiB'] = float(size['memoryGiB'])

                        result['models'][libcloud_region_name][size['size']]['storageGB'] = size['storageGB']

                    result['prices'][libcloud_region_name][size['size']] = float(price)

    return result


def update_pricing_file(pricing_file_path, pricing_data):
    ##    with open(pricing_file_path, 'r') as fp:
    #        content = fp.read()

    data = {'compute': {}}  # json.loads(content)
    data['updated'] = int(time.time())
    data['compute'].update(pricing_data)

    # Always sort the pricing info
    data = sort_nested_dict(data)

    content = json.dumps(data, indent=4)
    lines = content.splitlines()
    lines = [line.rstrip() for line in lines]
    content = '\n'.join(lines)

    with open(pricing_file_path, 'w') as fp:
        fp.write(content)


def sort_nested_dict(value):
    """
    Recursively sort a nested dict.
    """
    result = OrderedDict()

    for key, value in sorted(value.items(), key=sort_key_by_numeric_other):
        if isinstance(value, (dict, OrderedDict)):
            result[key] = sort_nested_dict(value)
        else:
            result[key] = value

    return result


def sort_key_by_numeric_other(key_value):
    """
    Split key into numeric, alpha and other part and sort accordingly.
    """
    return tuple((
                     int(numeric) if numeric else None,
                     INSTANCE_SIZES.index(alpha) if alpha in INSTANCE_SIZES else alpha,
                     other
                 ) for (numeric, alpha, other) in RE_NUMERIC_OTHER.findall(key_value[0]))


def main():
    print('Scraping EC2 pricing data')

    pricing_data = scrape_ec2_pricing()
    update_pricing_file(pricing_file_path=PRICING_FILE_PATH,
                        pricing_data=pricing_data)

    print('Pricing data updated')


if __name__ == '__main__':
    main()
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!