🎃

GithubCopilotにec2関連のスクリプトを作ってもらった

2024/12/18に公開

自力でも作れそうだけど、微妙にめんどくさそうだったので。。。。w

お題

言語による違いがどんな感じになるのかを見たかったので複数の言語で試してみました。

以下の仕様のスクリプトを{{ 言語 }}で書いてー 
(1)インスタンスの終了保護が無効になっているインスタンスを抽出
(2)インスタンス名の一覧を出力

生成されたコード

ruby

require 'aws-sdk-ec2'

def get_instances_with_termination_protection_disabled
  ec2 = Aws::EC2::Client.new(region: 'ap-northeast-1')

  # インスタンスの説明を取得
  instances = ec2.describe_instances.reservations.map(&:instances).flatten

  # インスタンスの終了保護が無効になっているインスタンスを抽出
  instance_ids = instances.select do |instance|
    attribute = ec2.describe_instance_attribute({
      instance_id: instance.instance_id,
      attribute: 'disableApiTermination'
    })
    !attribute.disable_api_termination.value
  end.map(&:instance_id)

  # インスタンス名の一覧を出力
  instance_names = instance_ids.map do |instance_id|
    instance = ec2.describe_instances(instance_ids: [instance_id]).reservations.first.instances.first
    name_tag = instance.tags.find { |tag| tag.key == 'Name' }
    name_tag ? name_tag.value : 'Unnamed'
  end

  instance_names
end

# インスタンス名の一覧を出力
instance_names = get_instances_with_termination_protection_disabled
puts instance_names

python

import boto3

def get_instances_with_termination_protection_disabled():
    ec2 = boto3.client('ec2', region_name='ap-northeast-1')

    # インスタンスの説明を取得
    instances = ec2.describe_instances()
    
    instance_ids = []
    for reservation in instances['Reservations']:
        for instance in reservation['Instances']:
            # インスタンスの終了保護の状態を取得
            attribute = ec2.describe_instance_attribute(
                InstanceId=instance['InstanceId'],
                Attribute='disableApiTermination'
            )
            # 終了保護が無効になっている場合、インスタンスIDを追加
            if not attribute['DisableApiTermination']['Value']:
                instance_ids.append(instance['InstanceId'])

    # インスタンス名の一覧を出力
    instance_names = []
    for instance_id in instance_ids:
        instance = ec2.describe_instances(InstanceIds=[instance_id])
        for reservation in instance['Reservations']:
            for inst in reservation['Instances']:
                name_tag = next((tag['Value'] for tag in inst['Tags'] if tag['Key'] == 'Name'), 'Unnamed')
                instance_names.append(name_tag)

    return instance_names

# インスタンス名の一覧を出力
instance_names = get_instances_with_termination_protection_disabled()
for name in instance_names:
    print(name)

php

<?php

require 'vendor/autoload.php';

use Aws\Ec2\Ec2Client;
use Aws\Exception\AwsException;

function getInstancesWithTerminationProtectionDisabled()
{
    $ec2Client = new Ec2Client([
        'region' => 'ap-northeast-1',
        'version' => 'latest'
    ]);

    try {
        // インスタンスの説明を取得
        $result = $ec2Client->describeInstances();
        $reservations = $result['Reservations'];

        $instanceIds = [];
        foreach ($reservations as $reservation) {
            foreach ($reservation['Instances'] as $instance) {
                // インスタンスの終了保護の状態を取得
                $attribute = $ec2Client->describeInstanceAttribute([
                    'InstanceId' => $instance['InstanceId'],
                    'Attribute' => 'disableApiTermination'
                ]);

                // 終了保護が無効になっている場合、インスタンスIDを追加
                if (!$attribute['DisableApiTermination']['Value']) {
                    $instanceIds[] = $instance['InstanceId'];
                }
            }
        }

        // インスタンス名の一覧を出力
        $instanceNames = [];
        foreach ($instanceIds as $instanceId) {
            $result = $ec2Client->describeInstances([
                'InstanceIds' => [$instanceId]
            ]);
            $reservations = $result['Reservations'];
            foreach ($reservations as $reservation) {
                foreach ($reservation['Instances'] as $instance) {
                    $nameTag = array_filter($instance['Tags'], function ($tag) {
                        return $tag['Key'] === 'Name';
                    });
                    $nameTag = array_values($nameTag);
                    $instanceNames[] = $nameTag ? $nameTag[0]['Value'] : 'Unnamed';
                }
            }
        }

        return $instanceNames;

    } catch (AwsException $e) {
        echo $e->getMessage();
        echo "\n";
        return [];
    }
}

// インスタンス名の一覧を出力
$instanceNames = getInstancesWithTerminationProtectionDisabled();
foreach ($instanceNames as $name) {
    echo $name . "\n";
}

go

const AWS = require('aws-sdk');
const ec2 = new AWS.EC2({ region: 'ap-northeast-1' });

async function getInstancesWithTerminationProtectionDisabled() {
    try {
        // インスタンスの説明を取得
        const describeInstancesResult = await ec2.describeInstances().promise();
        const reservations = describeInstancesResult.Reservations;

        const instanceIds = [];
        for (const reservation of reservations) {
            for (const instance of reservation.Instances) {
                // インスタンスの終了保護の状態を取得
                const describeInstanceAttributeResult = await ec2.describeInstanceAttribute({
                    InstanceId: instance.InstanceId,
                    Attribute: 'disableApiTermination'
                }).promise();

                // 終了保護が無効になっている場合、インスタンスIDを追加
                if (!describeInstanceAttributeResult.DisableApiTermination.Value) {
                    instanceIds.push(instance.InstanceId);
                }
            }
        }

        // インスタンス名の一覧を出力
        const instanceNames = [];
        for (const instanceId of instanceIds) {
            const describeInstancesResult = await ec2.describeInstances({
                InstanceIds: [instanceId]
            }).promise();
            const reservations = describeInstancesResult.Reservations;
            for (const reservation of reservations) {
                for (const instance of reservation.Instances) {
                    const nameTag = instance.Tags.find(tag => tag.Key === 'Name');
                    instanceNames.push(nameTag ? nameTag.Value : 'Unnamed');
                }
            }
        }

        return instanceNames;
    } catch (error) {
        console.error(error);
        return [];
    }
}

// インスタンス名の一覧を出力
getInstancesWithTerminationProtectionDisabled().then(instanceNames => {
    instanceNames.forEach(name => console.log(name));
});

Rust

use aws_config::meta::region::RegionProviderChain;
use aws_sdk_ec2::Client;
use aws_sdk_ec2::model::Filter;
use aws_sdk_ec2::types::SdkError;
use aws_sdk_ec2::error::DescribeInstancesError;
use aws_sdk_ec2::output::DescribeInstancesOutput;

#[tokio::main]
async fn main() -> Result<(), SdkError<DescribeInstancesError>> {
    let region_provider = RegionProviderChain::default_provider().or_else("ap-northeast-1");
    let config = aws_config::from_env().region(region_provider).load().await;
    let client = Client::new(&config);

    // インスタンスの説明を取得
    let describe_instances_output = client.describe_instances().send().await?;

    // インスタンスの終了保護が無効になっているインスタンスを抽出
    let mut instance_ids = Vec::new();
    if let Some(reservations) = describe_instances_output.reservations {
        for reservation in reservations {
            if let Some(instances) = reservation.instances {
                for instance in instances {
                    if let Some(instance_id) = instance.instance_id {
                        let describe_instance_attribute_output = client
                            .describe_instance_attribute()
                            .instance_id(instance_id.clone())
                            .attribute("disableApiTermination")
                            .send()
                            .await?;

                        if let Some(disable_api_termination) = describe_instance_attribute_output.disable_api_termination {
                            if !disable_api_termination.value.unwrap_or(true) {
                                instance_ids.push(instance_id);
                            }
                        }
                    }
                }
            }
        }
    }

    // インスタンス名の一覧を出力
    for instance_id in instance_ids {
        let describe_instances_output = client
            .describe_instances()
            .instance_ids(instance_id.clone())
            .send()
            .await?;

        if let Some(reservations) = describe_instances_output.reservations {
            for reservation in reservations {
                if let Some(instances) = reservation.instances {
                    for instance in instances {
                        if let Some(tags) = instance.tags {
                            for tag in tags {
                                if let Some(key) = tag.key {
                                    if key == "Name" {
                                        if let Some(value) = tag.value {
                                            println!("{}", value);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    Ok(())
}

感想

基本的には、ec2のdescribe_instancesとdescribe_instance_attributeを組み合わせて情報を取得&成形して出力するって感じですが、比較的にライトに書けているのはrubyかなーという印象でした。結果jsonをコネコネするのはrubyが長けているところがあるのかな?
いずれにせよ、このレベルのスクリプトはAIがベースを作ってくれるので便利ですね!

NaviPlusテックブログ

Discussion