AWS SDK for Python (Boto3)のboto3.resource(‘ec2’)でハマったこと

python

ご機嫌いかがでしょうか、豊崎です。

Lambdaを触わることも、Pythonでスクリプトを書くことも初心者の私は、 まず基本のキとして、python SDKを使ってローカル環境からEC2の起動を行おうと考えました。

AWS CLIと勝手が違いつまづいた箇所があったので、ここに書き残したいと思います。

やりたかったこと

タグでフィルタしたEC2の起動

つまづいたこと

boto3.resource('ec2')で取得した"ec2.Instance"の要素を一覧でみれない

aws ec2 describe-instancesライクに参照したい。

ハマりポイントまでご一緒にお付き合いください。

目的のEC2の起動を目指してまずは、対象のEC2にタグづけをしました

Key:start_target
Value:True

そして対象を取得するために以下の様にFileterをしました。 まったく問題ありませんでした。

result = ec2.instances.filter(
  Filters=[{
    'Name': 'tag:start_target',
    'Values': ['true']
  }]
)

そしてFilterしたインスタンスが合っているか確認しました。 ここも問題なさそうです。

for i in result:
  print i

ec2.Instance(id='i-XXXXXXXXXXXXXXXXX')
ec2.Instance(id='i-YYYYYYYYYYYYYYYYY')

さらにresultに格納した要素を一覧で(aws ec2 describe-instancesの結果の様に)みたいな。などとこだわったところ、結構な時間を要しました。 (boto3.client('ec2')であればdict型で一覧表示できますが、boto3.resource('ec2')が使いたかったので…) 以下のように1つずつのアトリビュートではなく、全要素を一度に参照したかったんです…

for i in result:
  print i.tags

[{u'Value': 'demo-1', u'Key': 'Name'}, {u'Value': 'true', u'Key': 'start_target'}]
[{u'Value': 'demo-2', u'Key': 'Name'}, {u'Value': 'true', u'Key': 'start_target'}]

以下を一度に表示したい。
attributes:

  • ami_launch_index
  • architecture
  • block_device_mappings
  • client_token
  • ebs_optimized
  • ena_support
  • hypervisor
  • iam_instance_profile
  • image_id
  • instance_id
  • instance_lifecycle
  • instance_type
  • kernel_id
  • key_name
  • launch_time
  • monitoring
  • network_interfaces_attribute
  • placement
  • platform
  • private_dns_name
  • private_ip_address
  • product_codes
  • public_dns_name
  • public_ip_address
  • ramdisk_id
  • root_device_name
  • root_device_type
  • security_groups
  • source_dest_check
  • spot_instance_request_id
  • sriov_net_support
  • state
  • state_reason
  • state_transition_reason
  • subnet_id
  • tags
  • virtualization_type
  • vpc_id

references:

  • classic_address
  • image
  • key_pair
  • network_interfaces
  • placement_group
  • subnet
  • vpc

いろいろ調べた(そして教えてもらった)結果として各アトリビュートや、リファレンスをそれぞれ確認するということになりそうでした。

アトリビュートだったら、このように確認することに決めました。

[(i.ami_launch_index,
i.architecture,
i.block_device_mappings,
i.client_token,
i.ebs_optimized,
i.ena_support,
i.hypervisor,
i.iam_instance_profile,
i.image_id,
i.instance_id,
i.instance_lifecycle,
i.instance_type,
i.kernel_id,
i.key_name,
i.launch_time,
i.monitoring,
i.network_interfaces_attribute,
i.placement,
i.platform,
i.private_dns_name,
i.private_ip_address,
i.product_codes,
i.public_dns_name,
i.public_ip_address,
i.ramdisk_id,
i.root_device_name,
i.root_device_type,
i.security_groups,
i.source_dest_check,
i.spot_instance_request_id,
i.sriov_net_support,
i.state,
i.state_reason,
i.state_transition_reason,
i.subnet_id,
i.tags,
i.virtualization_type,
i.vpc_id) 
for i in result]

そして、リファレンスだったら、このように確認することに決めました。

[(i.classic_address,
i.image,
i.key_pair,
i.network_interfaces,
i.placement_group,
i.subnet,
i.vpc) for i in result]

(記事なので可読性を考慮し、改行をしています)

目的は達成

結果として目的は達成していたので良しとしようと思います。

import boto3

def get_ec2():
    ec2 = boto3.resource('ec2')
    result = ec2.instances.filter(
      Filters=[{
        'Name': 'tag:start_target',
        'Values': ['true']
      }]
    )
    return result

def lambda_handler(event,context):

    instances = get_ec2()
    instances.start()
    response = {
        "StartInstances"    : [(i.id) for i in instances]
    }

    return response

まとめ

python初心者ですので、生暖かく見守ってください。
同じことに時間を費やしそうになった方が見てくれたらいいなと思います。

参考

https://boto3.readthedocs.io/en/latest/reference/services/ec2.html#EC2.Instance

AWS Cloud Roadshow 2017 福岡