Fonction Lambda pour effectuer une sauvegarde AMI (python)

Diverses améliorations sont prévues à l'avenir.

Veuillez vous référer à ce qui suit pour les paramètres, etc. http://pict3.hatenablog.com/entry/2015/12/09/104015

#!/usr/bin/python
# -*- coding: utf-8 -*-

import json

import boto3
from boto3.session import Session

import time
from datetime import datetime as dt

import pprint

TAG_KEY_BACKUP_GENERATION = 'Backup-Generation'
TAG_KEY_AUTO_BACKUP       = 'Backup-Type'
TAG_VAL_AUTO_BACKUP       = 'auto'

print('Loading function')

pp = pprint.PrettyPrinter(indent=4)

#Nom de la fonction: lambda_handler
def lambda_handler(event, context):
    print("Received event: " + json.dumps(event, indent=2))

    ec2_client   = boto3.client('ec2')
    ec2_resource = boto3.resource('ec2')

    ret = execute_ami_backup_task(ec2_client, ec2_resource)
    print 'AMI buckup task is completed(%s).' % (ret)

    return 0
    raise Exception('Something went wrong')


#Nom de la fonction: exécuter_ami_backup_task
#Valeur de retour: résultat de l'exécution
#Argument: ec2_client
#       : ec2_resource
#Fonction: effectuer une sauvegarde AMI
def execute_ami_backup_task(ec2_client, ec2_resource):
    response = ec2_client.describe_instances()

    exec_time = dt.now().strftime('%Y%m%d%H%M%S')

    result = True
    for ec2_group in response['Reservations']:
        for instance_info in ec2_group['Instances']:
            ret = is_target(instance_info)
            if (ret == False):
                continue
        
            ret = create_buckup_image(ec2_client, ec2_resource, instance_info, exec_time)
            if not ret:
                print 'create_buckup_image(%s) was failed.' % (instance_info['InstanceId'])
                result = False

                continue

            ret = delete_old_image(ec2_client, ec2_resource, instance_info)
            if not ret:
                print 'delete_old_image(%s) was failed.' % (instance_info['InstanceId'])
                result = False

                continue
    
    return result


#Nom de la fonction: est_target
#Valeur de retour: si une sauvegarde est requise
#Argument: instance_info <dict>
#Fonction: juger de la nécessité d'une sauvegarde
def is_target(instance_info):
    val = get_tag_value(
        instance_info, 
        TAG_KEY_BACKUP_GENERATION
    )

    if val is None:
        return False

    return True


#Nom de la fonction: get_tag_value
#Valeur de retour: valeur de la balise (aucune s'il n'y a pas de correspondance pour la clé)
#Argument: instance_info <dict>
#       : key <str>
#Fonction: obtenir la valeur de balise de la clé spécifiée à partir des informations d'instance
def get_tag_value(instance_info, key):
    tags = instance_info['Tags']
    for tag in tags:
        if not (key == tag['Key']):
            continue
        
        return tag['Value']

    return None


#Nom de la fonction: créer_buckup_image
#Valeur de retour: résultat de l'exécution
#Argument: ec2_client
#       : ec2_resource
#       : instance_info <dict>
#       : exec_time <str>
#Fonction: créer une image de sauvegarde
def create_buckup_image(ec2_client, ec2_resource, instance_info, exec_time):
    inst_id = instance_info['InstanceId']
    name    = get_tag_value(instance_info, 'Name')
    if name is None:
        print('Get name error!!')
        
        return False

    image_name = name + '-' + exec_time

    response = ec2_client.create_image(
        InstanceId  = inst_id,
        Name        = image_name,
        Description = image_name,
        NoReboot    = True
    )

    image_id = response['ImageId']
    print '%s was created.' % (image_id)

    #Juste au cas où, attendez que l'image et l'instantané à étiqueter soient terminés
    time.sleep(10)

    tags  = construct_backup_tags(instance_info)
    image = ec2_resource.Image(image_id)

    set_tags_to_image(image, tags)

    set_tags_to_snapshot(ec2_resource, image, tags, image_name)

    return True


#Nom de la fonction: construct_backup_tags
#Valeur de retour: groupe de balises
#Argument: instance_info <dict>
#Fonction: configurer un groupe de balises pour les paramètres de sauvegarde
def construct_backup_tags(instance_info):
    ret_tags = []
    tags = instance_info['Tags']
    for tag in tags:
        if (TAG_KEY_BACKUP_GENERATION == tag['Key']):
            continue

        ret_tags.append(tag)

    t = {u'Value': TAG_VAL_AUTO_BACKUP, u'Key': TAG_KEY_AUTO_BACKUP}
    ret_tags.append(t)

    return ret_tags


#Nom de la fonction: set_tags_to_image
#Valeur de retour: non
#Argument: image
#       : tags <list>
#Fonction: définir les informations de balise dans l'image AMI
def set_tags_to_image(image, tags):
    image.create_tags(Tags = tags)

    return


#Nom de la fonction: set_tags_to_snapshot
#Valeur de retour: non
#Argument: ec2_resource
#       : image
#       : tags <list>
#       : image_name <str>
#Fonction: définir les informations de balise dans l'instantané
def set_tags_to_snapshot(ec2_resource, image, tags, image_name):
    for dev in image.block_device_mappings:
        #Non applicable sauf pour EBS
        if not dev.has_key('Ebs'):
            continue

        #Supprimé une fois pour remplacer l'étiquette de nom
        name_idx = get_name_tag_index(tags)
        tags.pop(name_idx)

        #Paramètre de balise de nom
        dev_name = dev['DeviceName'][5:]
        name = image_name + '-' + dev_name
        t = {u'Value': name, u'Key': 'Name'}
        tags.append(t)
       
        snapshot_id = dev['Ebs']['SnapshotId']
        snapshot = ec2_resource.Snapshot(snapshot_id)

        snapshot.create_tags(Tags = tags)

    return


#Nom de la fonction: get_name_tag_index
#Valeur de retour: position d'index de la balise Name (Aucune s'il n'y a pas de correspondance pour la clé)
#Arguments: balises<list>
#Fonction: obtenir la position d'index de la balise Name dans la liste des balises
def get_name_tag_index(tags):
    idx = 0
    for tag in tags:
        if tag['Key'] == 'Name':
            return idx

        idx += 1

    return None


#Nom de la fonction: supprimer_old_image
#Valeur de retour: résultat de l'exécution
#Argument: ec2_client
#       : ec2_resource
#       : instance_info <dict>
#Fonction: supprime les images antérieures à la génération de rétention
def delete_old_image(ec2_client, ec2_resource, instance_info):
    sorted_images = get_sorted_images(ec2_client, instance_info)

    generation = int(get_tag_value(instance_info, TAG_KEY_BACKUP_GENERATION))
    cnt = 0
    for img in sorted_images:
        cnt += 1
        if generation >= cnt:
            continue

        image_id  = img['ImageId']
        snapshots = get_snapshots(ec2_resource, image_id)

        #Libérez l'image AMI
        ec2_client.deregister_image(
            ImageId = image_id
        )
        print '%s was deregistered.' % (image_id)

        #Attendez que la version soit terminée
        time.sleep(10)

        #Supprimer l'instantané correspondant
        for snapshot in snapshots:
            snapshot.delete()
            print '%s was deleted.' % (snapshot)

    return True


#Nom de la fonction: get_sorted_images
#Valeur de retour: image triée<list>
#Argument: ec2_client
#       : instance_info <dict>
#Fonction: Obtenez la liste d'images AMI triée dans l'ordre de création
def get_sorted_images(ec2_client, instance_info):
    sorted_images = []
    name     = get_tag_value(instance_info, 'Name')
    response = ec2_client.describe_images(
        Owners  = ['self'],
        Filters = [{'Name': 'tag:Name',                   'Values': [name]},
                   {'Name': 'tag:' + TAG_KEY_AUTO_BACKUP, 'Values': [TAG_VAL_AUTO_BACKUP]}]
    )

    images = response['Images']
    sorted_images = sorted(
        images, 
        key = lambda x: x['CreationDate'], 
        reverse = True
    )

    return sorted_images


#Nom de la fonction: get_snapshots
#Valeur de retour: groupe de clichés<list>
#Argument: ec2_resource
#       : image_id <str>
#Fonction: acquiert des instantanés inclus dans l'image AMI
def get_snapshots(ec2_resource, image_id):
    snapshots = []
    image     = ec2_resource.Image(image_id)

    for dev in image.block_device_mappings:
        if not dev.has_key('Ebs'):
            continue

        snapshot_id = dev['Ebs']['SnapshotId']
        snapshot    = ec2_resource.Snapshot(snapshot_id)
            
        snapshots.append(snapshot)

    return snapshots

Recommended Posts

Fonction Lambda pour effectuer une sauvegarde AMI (python)
Comment utiliser Python lambda
[Présentation de l'application Udemy Python3 +] 58. Lambda
[Lambda] [Python] Publier sur Twitter depuis Lambda!
Ecrire une fonction AWS Lambda en Python
Comment utiliser la fonction zip de python
fonction python ①
[Python 3.8 ~] Comment définir intelligemment des fonctions récursives avec des expressions lambda
[Python] fonction
fonction python ②
[Introduction à l'application Udemy Python3 +] 48. Définition des fonctions
[python] Comment utiliser __command__, explication des fonctions
[Introduction à l'application Udemy Python3 +] 45. fonction enumerate
[Introduction à l'application Udemy Python3 +] 41. fonction d'entrée
Fonction pour enregistrer les images par date [python3]
[Introduction à l'application Udemy Python3 +] 44. fonction range
Comment accéder à RDS depuis Lambda (python)
[Introduction à l'application Udemy Python3 +] 46. fonction zip
Connectez-vous à s3 avec AWS Lambda Python
[Route vers Python intermédiaire] Utiliser des expressions lambda
Les espaces de travail MAUVAIS redémarrent Lambda réécrit en python
Mis à jour vers Python 2.7.9
python3x: fonction lambda
Enregistrer automatiquement les arguments de fonction dans argparse en Python
fonction d'énumération python
Python: j'ai pu récurer en lambda
Python> fonction> Fermeture
[Python] Fonction de générateur
N'hésitez pas à transformer Python en utilisant la bibliothèque en une fonction AWS Lambda
Exemple de notification Slack avec python lambda
Exporter un instantané RDS vers S3 avec Lambda (Python)
[Python] Comment utiliser la fonction de hachage et taple.
[AWS / Lambda] Comment charger une bibliothèque externe Python
Télécharger des fichiers sur Google Drive avec Lambda (Python)
Python> fonction> Fonction interne
Résumé de l'étude de Python pour utiliser AWS Lambda
Décorateur de fonction Python
"Backport" vers python 2
[Introduction à Python] Utilisation de base des expressions lambda
[Introduction à Python] Comment itérer avec la fonction range?
Introduire l'opérateur pipe et la composition de fonction à Python (provisoire)
Créer une fonction Lambda de version Python (+ couche Lambda) avec Serverless Framework
[Route vers Python intermédiaire] Définir la fonction __getattr__ dans la classe
J'ai essayé d'obtenir une AMI en utilisant AWS Lambda
Déployer la fonction Python 3 avec Serverless Framework sur AWS Lambda
Écrire plusieurs enregistrements dans DynamoDB avec Lambda (Python, JavaScript)
Je veux AWS Lambda avec Python sur Mac!
python Spécifie la fonction à exécuter lorsque le programme se termine
Envisagez la conversion de Python récursif en non récursif
Exécuter la fonction Python à partir de Powershell (comment passer des arguments)
Python: peut être répété en lambda
Re: Python lambda est inutile ^ H ^ H ^ H ^ H ^ H Difficile à utiliser
Description à afficher avec Python> fonction> Docstrings> help () / .__ doc__
[Python] Comment appeler une fonction de c depuis python (édition ctypes)
À propos des arguments de fonction (python)
[Python] Prenez une capture d'écran
Comment installer Python
Temps d'exécution de la fonction (Python)
Changements de Python 3.0 à Python 3.5
Changements de Python 2 à Python 3.0