Ansibleからaws cliを実行する

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

渡辺です。 AnsibleによるAWSリソースの構成管理シリーズの5回目は、どうしても避けられない新機能のサポートに関わるトピックです。

AWSの新機能とツールのサポート時期

AWSでは毎週のように新機能がリリースされています。 非常に魅力的な新機能も多く、「これが欲しかったんだ!」と思うこともしばしばです。 一方、原則としては新機能がデフォルトで有効になることはありません。 既存のシステムの挙動が変わり、トラブルになる可能性を考慮すれば当然でしょう。

新機能を利用するには、明示的に、マネジメントコンソールなどを利用して設定を行わなければなりません。 各インターフェイスの提供時期は概ね次のようになります。

インターフェイス 時期 説明
AWS CLI 新機能リリースと同時
AWS SDK 新機能リリースと同時が多い
マネジメントコンソール 新機能リリースと同時が多いが、遅れる場合もある
CloudFormation 数ヶ月程度で対応する場合も多いが、なかなか提供されないこともある
サードパーティツール Ansibleなど、リリースサイクルに依存

AWSはAPIを重視しているため、原則としてAWS CLIは新機能のリリースと同時にその機能に対応します。 またSDKやマネジメントコンソールも、新機能のリリースとほぼ同時に利用できることがほとんどです。

CloudFormationはAWSの純正ツールになりますが、新機能のサポートタイミングはまちまちです。 なかなかサポートされないケースもあるのが現実です。

一方、Ansibleなどサードパーティーツールでの新機能サポートは遅れがちです。 AWSの新機能リリースのサイクルが早く多いため追いつくのが難しいというのが現実でしょう。 このため、「XXで構成管理はしているけどZZ機能をサポートしていないので、そこは手組で…」となりがちです。 ここがサードパーティーツールを利用する時のジレンマとなっています。

AnsibleからAWS CLIを叩く

Ansibleの強みはモジュールが充実しており、簡潔な設定ファイルで構成管理を行うことです。 しかし、構成管理上、直接スクリプトやコマンドを実行せざるを得ないケースは少なからずあり、Ansibleではそれらをshellモジュールcommandモジュールを利用してカバーできます。 勿論、モジュールで実現できる範囲はモジュールを利用すべきですが、どうしようもない場合はshellモジュールやcommandモジュールを利用します。

そう、モジュールでサポートされない新機能は、AWS CLIを叩けばいいのです。

サンプルとして、VPCピアリングのDNSサポート機能をAnsibleから有効にしてみたいと思います。

リソースのステータスを取得し、冪等性を保つ

command系モジュールを利用するポイントは、チェックと更新のタスクをそれぞれ定義することです。 はじめにaws ec2 describe-vpc-peering-connectionsコマンドで、AllowDnsResolutionFromRemoteVpcの値を取得します。 コマンドラインから実行するのであれば次のようなコマンドです。

aws ec2 describe-vpc-peering-connections \
   --vpc-peering-connection-id pcx-xxxxxxxx --profile hogehoge

実行結果はJSONでこんなイメージです。

{
    "VpcPeeringConnections": [
        {
            "Status": {
                "Message": "Active", 
                "Code": "active"
            }, 
            "Tags": [], 
            "AccepterVpcInfo": {
                "PeeringOptions": {
                    "AllowEgressFromLocalVpcToRemoteClassicLink": false, 
                    "AllowDnsResolutionFromRemoteVpc": false, 
                    "AllowEgressFromLocalClassicLinkToRemoteVpc": false
                }, 
                "OwnerId": "xxxxxxxx", 
                "VpcId": "vpc-xxxxxxxx", 
                "CidrBlock": "10.0.0.0/16"
            }, 
            "VpcPeeringConnectionId": "pcx-xxxxxxxx", 
            "RequesterVpcInfo": {
                "PeeringOptions": {
                    "AllowEgressFromLocalVpcToRemoteClassicLink": false, 
                    "AllowDnsResolutionFromRemoteVpc": false, 
                    "AllowEgressFromLocalClassicLinkToRemoteVpc": false
                }, 
                "OwnerId": "xxxxxxxx", 
                "VpcId": "vpc-xxxxxxxx", 
                "CidrBlock": "10.1.0.0/16"
            }
        }
    ]
}

--queryオプションでRequesterVpcInfoAllowDnsResolutionFromRemoteVpcを抽出します。

aws ec2 describe-vpc-peering-connections \
  --vpc-peering-connection-id pcx-xxxxxxxx --profile hogehoge \
  --query VpcPeeringConnections[0].RequesterVpcInfo.PeeringOptions.AllowDnsResolutionFromRemoteVpc

AWS CLIで確認したならば、Playbookのタスクとしてregisterで結果を保持します。

    - name: check DNS Options / Requester
      command: "aws ec2 describe-vpc-peering-connections --vpc-peering-connection-id {{ _vpc_peer.peering_id }} --profile {{ profile }} --query VpcPeeringConnections[0].RequesterVpcInfo.PeeringOptions.AllowDnsResolutionFromRemoteVpc"
      changed_when: False
      register: _dns_options_vpc_peer_req

冪等性を確保したいので、changed_whenFalseに設定することを忘れないでください。

AWS CLIでリソースを更新する

チェックした値を元に、必要があればAWS CLIを利用してDNSオプションを有効化します。

有効化するためのコマンドは次のようになります。

aws ec2 modify-vpc-peering-connection-options \
   --vpc-peering-connection-id pcx-xxxxxxxx --profile hogehoge \
   --requester-peering-connection-options AllowDnsResolutionFromRemoteVpc=true

--dry-runオプションを付与してコマンドラインから実行確認します。 確認したならば、Playbookのタスクを定義しましょう。

    - name: Modify Peering Options / Requester
      command: "aws ec2 modify-vpc-peering-connection-options --vpc-peering-connection-id {{ _vpc_peer.peering_id }} --profile {{ profile }} --requester-peering-connection-options AllowDnsResolutionFromRemoteVpc=true"
      when: _dns_options_vpc_peer_req.stdout == 'false'

チェック時にコマンドの実行結果を_dns_options_vpc_peer_reqに登録しました。 whenを使い、stdout属性を参照しfalseの場合のみ、こののタスクを実行します。

まとめ

AnsibleでAWSリソースを管理する場合に懸念点になる新機能サポートですが、commandモジュールからAWS CLIを叩くことで回避することができました。 本当はすべてモジュールで管理したいところですが、AWSの新機能リリースの状況を考慮すると、完璧に行うことは困難です。 とはいえ、構成管理で一部手動となることは、可能な限り避けたいところです。 うまくバランスをとりながら、AnsibleからAWS CLIを実行しましょう。