AWS。Lambda--将EC2标签复制到其EBS,第二部分--创建一个Lambda函数

268 阅读6分钟

让我们继续我们的AWS Lambda函数之旅,它将把EC2的AWS标签复制到所有EBS卷上,连接到它。

在第一部分中,AWS:Lambda--将EC2的标签复制到EBS,第一部分--Python和boto3,我们写了一个Python脚本,可以获得AWS区域内的所有EC2实例,然后为每个EC2抓取其EBS卷,然后将所有的AWS标签从EC2复制到其所有EBS,并将添加一个额外的标签。

在这一部分,我们将创建一个AWS Lambda函数,它将被AWS CloudWatch事件触发。

创建一个AWS Lambda函数

进入AWS Lambda,从 "Author from scratch"中创建一个新函数,运行时间设置为Python 3.8。

执行角色中留下 "创建新角色"--稍后,我们将用IAM策略为其添加额外权限。

将脚本的代码粘贴到函数中,在代码的最后更新lambda_hanlder() 执行,并在其参数中代替上一篇文章中的 "0*,0″*,设置为event, context

为了检查context 对象的内容,我们稍后将使用它来获得EC2 ID,将其输出添加到函数的日志中。

添加import jsonprint("CONTEXT: " + json.dumps(event))

另外,对于ec2 = boto3.resource() 调用,删除AWS密钥,并留下资源的唯一类型--"ec2"。

不要忘记按下Deploy按钮,将你的改变应用到AWS Lambda上。

添加一个亚马逊EventBridge(CloudWatch事件)触发器

接下来,我们需要在每次在一个地区启动新的EC2时运行这个函数。

在这里,我们可以使用Amazon EventBridge(原CloudWatch Events)。转到CloudWatch Events > Rules,点击Create rule

事件模式中选择服务名称==EC2,事件类型中选择 "EC2实例状态变化通知",在特定状态中选择运行

在右侧的 "添加目标"中,选择我们上面创建的AWS Lambda函数。

在页面的最后,在*Show sample event(s),*我们可以看到一个event 对象的例子,该对象将被传递给函数以获得EC2 ID。

保存新的规则。

检查它是否作为一个触发器被添加到Lambda函数中。

让我们检查一下这将如何工作。

在CloudWatch规则中,打开规则的监控。

旋转一个新的EC2,例如通过触发一个自动扩展组。

在CloudWatch图表中,我们可以看到,该规则被触发了。

检查Lambda函数的日志。

AWS Lambda。未经授权的操作(UnauthorizedOperation

在日志中,我们对两条记录感兴趣。

第一条--是event 的内容,它是由print("CONTEXT: " + json.dumps(event)) 保存在日志中的。

而第二个是 ***"ClientError:在调用DescribeInstances操作时发生了一个错误(UnauthorizedOperation)。你没有被授权执行这个操作"***错误。

这里的问题很明显:我们的Lambda函数现在正在使用一个IAM角色,这个角色是在函数的创建过程中创建的,它没有对EC2操作的API调用的权限。

进入AWS IAM,找到该角色,点击附加策略

创建一个新的政策。

在这里描述EC2的权限。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeInstances",
                "ec2:DeleteTags",
                "ec2:CreateTags",
                "ec2:DescribeVolumes"
            ],
            "Resource": "*"
        }
    ]
}

保存它。

回到Lambda函数的IAM角色,添加一个新政策。

重复一次新的EC2启动,再次检查函数的日志。

Yay! "它成功了!" (c)

接下来,需要更新代码,从event 对象中获取instance-id

解析一个Lambda event

我们在创建CloudWatch规则时已经看到了event 的例子,我们知道它将作为一个带有一组键的python-dictionary被传递给lambda_handler() 函数。

{
    "version": "0",
    "id": "a99597e5-90a5-5ac3-3aba-da3ecd51452a",
    "detail-type": "EC2 Instance State-change Notification",
    "source": "aws.ec2",
    "account": "534***385",
    "time": "2021-10-11T09:02:09Z",
    "region": "eu-west-3",
    "resources": [
        "arn:aws:ec2:eu-west-3:534***385:instance/i-0cc24729109ba61e5"
    ],
    "detail": {
        "instance-id": "i-0cc24729109ba61e5",
        "state": "running"
    }
}

而从这里我们需要抓取detail.instance-id 元素的一个值。

在脚本中添加一个新的变量,让我们称之为instance_id ,它将保留一个来自event["detail"]["instance-id"] 的值,然后通过使用这个ID,我们将创建一个新的ec2.Instance 类的对象,即ec2.Instance(instance_id)

我们不需要手动运行一个新的EC2,而是通过向它传递一个event 对象来为我们的Lambda使用测试

创建一个新的测试事件。

添加一个类似于我们将从CloudWatch获得的数据。

{
    "version": "0",
    "id": "a99597e5-90a5-5ac3-3aba-da3ecd51452a",
    "detail-type": "EC2 Instance State-change Notification",
    "source": "aws.ec2",
    "account": "534***385",
    "time": "2021-10-11T09:02:09Z",
    "region": "eu-west-3",
    "resources": [
        "arn:aws:ec2:eu-west-3:534***385:instance/i-0cc24729109ba61e5"
    ],
    "detail": {
        "instance-id": "i-0cc24729109ba61e5",
        "state": "running"
    }
}

运行测试。

"它成功了!"**(c)

现在让我们启动一个普通的EC2来检查整个方案,包括CloudWatch事件、Lambda的触发器以及其执行结果。

触发一个自动扩展组。

一个新的EC2i-051f2e1f1bc8d332b 被创建,检查Lambda的日志。

找到这个EC2的一个EBS。

并检查其标签。

而现在函数的代码是下一个。

#!/usr/bin/env python

import os
import json
import boto3


def lambda_handler(event, context):

    ec2 = boto3.resource('ec2')
    instance_id = event["detail"]["instance-id"]
    instance = ec2.Instance(instance_id)

    print("[DEBUG] EC2\n\t\tID:  " + str(instance))
    print("\tEBS")

    for vol in instance.volumes.all():

        vol_id = str(vol)
        print("VOLUME: " + str(vol))

        device_id = "ec2.vol.Device('" + str(vol.attachments[0]['Device']) + "')"
        print("\t\tID:  " + vol_id + "\n\t\tDev: " + device_id)

        role_tag = vol.create_tags(Tags=set_role_tag(vol))
        ec2_tags = vol.create_tags(Tags=copy_ec2_tags(instance))
        print("\t\tTags set:\n\t\t\t" + str(role_tag) + "\n\t\t\t" + str(ec2_tags) + "\n")


def is_pvc(vol): 

    try:
        for tag in vol.tags:
            if tag['Key'] == 'kubernetes.io/created-for/pvc/name':
                return True
                break
    except TypeError:
            return False


def set_role_tag(vol):
    
    device = vol.attachments[0]['Device']
    tags_list = []
    values = {}
        
    if is_pvc(vol):
        values['Key'] = "Role"
        values['Value'] = "PvcDisk"
        tags_list.append(values)
    elif device == "/dev/xvda":
        values['Key'] = "Role"
        values['Value'] = "RootDisk"
        tags_list.append(values)
    else:   
        values['Key'] = "Role"
        values['Value'] = "DataDisk"
        tags_list.append(values)

    return tags_list

    
def copy_ec2_tags(instance):
            
    tags_list = []
    values = {} 
        
    for instance_tag in instance.tags:

        if instance_tag['Key'] == 'Env':
            tags_list.append(instance_tag)
        elif instance_tag['Key'] == 'Tier':
            tags_list.append(instance_tag)
        elif instance_tag['Key'] == 'DataClass':
            tags_list.append(instance_tag)
        elif instance_tag['Key'] == 'JiraTicket':
            tags_list.append(instance_tag)

    return tags_list


if __name__ == "__main__":
    lambda_handler(event, context)

完成了。

类似的帖子

The postAWS:Lambda--复制EC2标签到其EBS,第二部分--创建Lambda函数首次出现在RTFM:Linux、DevOps和系统管理上。