From 89eedae5fcc43657aab828f47d50332d284ff3ad Mon Sep 17 00:00:00 2001 From: Marcin Kulisz Date: Sat, 12 Nov 2016 19:58:51 +0000 Subject: [PATCH 1/7] Porting EC2 provider to boto3 --- bootstrapvz/providers/ec2/ebsvolume.py | 50 +++++++++++-------- bootstrapvz/providers/ec2/tasks/ami.py | 44 ++++++++-------- bootstrapvz/providers/ec2/tasks/connection.py | 7 ++- bootstrapvz/providers/ec2/tasks/ebs.py | 7 +++ 4 files changed, 65 insertions(+), 43 deletions(-) diff --git a/bootstrapvz/providers/ec2/ebsvolume.py b/bootstrapvz/providers/ec2/ebsvolume.py index 049094e..a3aa8d8 100644 --- a/bootstrapvz/providers/ec2/ebsvolume.py +++ b/bootstrapvz/providers/ec2/ebsvolume.py @@ -1,6 +1,5 @@ from bootstrapvz.base.fs.volume import Volume from bootstrapvz.base.fs.exceptions import VolumeError -import time class EBSVolume(Volume): @@ -9,21 +8,25 @@ class EBSVolume(Volume): self.fsm.create(connection=conn, zone=zone) def _before_create(self, e): - conn = e.connection + self.conn = e.connection zone = e.zone size = self.size.bytes.get_qty_in('GiB') - self.volume = conn.create_volume(size, zone, volume_type='gp2') - while self.volume.volume_state() != 'available': - time.sleep(5) - self.volume.update() + self.volume = self.conn.create_volume(Size=size, + AvailabilityZone=zone, + VolumeType='gp2') + self.vol_id = self.volume['VolumeId'] + waiter = self.conn.get_waiter('volume_available') + waiter.wait(VolumeIds=[self.vol_id], + Filters=[{'Name': 'status', 'Values': ['available']}]) def attach(self, instance_id): self.fsm.attach(instance_id=instance_id) def _before_attach(self, e): - instance_id = e.instance_id import os.path import string + + self.instance_id = e.instance_id for letter in string.ascii_lowercase[5:]: dev_path = os.path.join('/dev', 'xvd' + letter) if not os.path.exists(dev_path): @@ -34,25 +37,30 @@ class EBSVolume(Volume): if self.device_path is None: raise VolumeError('Unable to find a free block device path for mounting the bootstrap volume') - self.volume.attach(instance_id, self.ec2_device_path) - while self.volume.attachment_state() != 'attached': - time.sleep(2) - self.volume.update() + self.conn.attach_volume(VolumeId=self.vol_id, + InstanceId=self.instance_id, + Device=self.ec2_device_path) + waiter = self.conn.get_waiter('volume_in_use') + waiter.wait(VolumeIds=[self.vol_id], + Filters=[{'Name': 'attachment.status', 'Values': ['attached']}]) def _before_detach(self, e): - self.volume.detach() - while self.volume.attachment_state() is not None: - time.sleep(2) - self.volume.update() + self.conn.detach_volume(VolumeId=self.vol_id, + InstanceId=self.instance_id, + Device=self.ec2_device_path) + waiter = self.conn.get_waiter('volume_available') + waiter.wait(VolumeIds=[self.vol_id], + Filters=[{'Name': 'status', 'Values': ['available']}]) del self.ec2_device_path self.device_path = None def _before_delete(self, e): - self.volume.delete() + self.conn.delete_volume(VolumeId=self.vol_id) def snapshot(self): - snapshot = self.volume.create_snapshot() - while snapshot.status != 'completed': - time.sleep(2) - snapshot.update() - return snapshot + snapshot = self.conn.create_snapshot(VolumeId=self.vol_id) + self.snap_id = snapshot['SnapshotId'] + waiter = self.conn.get_waiter('snapshot_completed') + waiter.wait(SnapshotIds=[self.snap_id], + Filters=[{'Name': 'status', 'Values': ['completed']}]) + return self.snap_id diff --git a/bootstrapvz/providers/ec2/tasks/ami.py b/bootstrapvz/providers/ec2/tasks/ami.py index 48b49e6..77fe195 100644 --- a/bootstrapvz/providers/ec2/tasks/ami.py +++ b/bootstrapvz/providers/ec2/tasks/ami.py @@ -21,9 +21,9 @@ class AMIName(Task): ami_name = info.manifest.name.format(**info.manifest_vars) ami_description = info.manifest.provider['description'].format(**info.manifest_vars) - images = info._ec2['connection'].get_all_images(owners=['self']) + images = info._ec2['connection'].describe_images(Owners=['self'])['Images'] for image in images: - if ami_name == image.name: + if ami_name == image['Name']: msg = 'An image by the name {ami_name} already exists.'.format(ami_name=ami_name) raise TaskError(msg) info._ec2['ami_name'] = ami_name @@ -93,41 +93,45 @@ class RegisterAMI(Task): @classmethod def run(cls, info): - registration_params = {'name': info._ec2['ami_name'], - 'description': info._ec2['ami_description']} - registration_params['architecture'] = {'i386': 'i386', + registration_params = {'Name': info._ec2['ami_name'], + 'Description': info._ec2['ami_description']} + registration_params['Architecture'] = {'i386': 'i386', 'amd64': 'x86_64'}.get(info.manifest.system['architecture']) if info.manifest.volume['backing'] == 's3': - registration_params['image_location'] = info._ec2['manifest_location'] + registration_params['ImageLocation'] = info._ec2['manifest_location'] else: root_dev_name = {'pvm': '/dev/sda', 'hvm': '/dev/xvda'}.get(info.manifest.provider['virtualization']) - registration_params['root_device_name'] = root_dev_name + registration_params['RootDeviceName'] = root_dev_name - from boto.ec2.blockdevicemapping import BlockDeviceType - from boto.ec2.blockdevicemapping import BlockDeviceMapping - block_device = BlockDeviceType(snapshot_id=info._ec2['snapshot'].id, delete_on_termination=True, - size=info.volume.size.bytes.get_qty_in('GiB'), volume_type='gp2') - registration_params['block_device_map'] = BlockDeviceMapping() - registration_params['block_device_map'][root_dev_name] = block_device + block_device = [{'DeviceName': root_dev_name, + 'Ebs': { + 'SnapshotId': info._ec2['snapshot'], + 'VolumeSize': info.volume.size.bytes.get_qty_in('GiB'), + 'VolumeType': 'gp2', + 'DeleteOnTermination': True}}] + registration_params['BlockDeviceMappings'] = block_device if info.manifest.provider['virtualization'] == 'hvm': - registration_params['virtualization_type'] = 'hvm' + registration_params['VirtualizationType'] = 'hvm' else: - registration_params['virtualization_type'] = 'paravirtual' + registration_params['VirtualizationType'] = 'paravirtual' akis_path = rel_path(__file__, 'ami-akis.yml') from bootstrapvz.common.tools import config_get - registration_params['kernel_id'] = config_get(akis_path, [info._ec2['region'], - info.manifest.system['architecture']]) + registration_params['kernel_id'] = config_get(akis_path, + [info._ec2['region'], + info.manifest.system['architecture']]) if info.manifest.provider.get('enhanced_networking', None) == 'simple': - registration_params['sriov_net_support'] = 'simple' + registration_params['SriovNetSupport'] = 'simple' info._ec2['image'] = info._ec2['connection'].register_image(**registration_params) # Setting up tags on the AMI if 'tags' in info.manifest.data: raw_tags = info.manifest.data['tags'] - tags = {k: v.format(**info.manifest_vars) for k, v in raw_tags.items()} - info._ec2['connection'].create_tags(info._ec2['image'], tags) + formatted_tags = {k: v.format(**info.manifest_vars) for k, v in raw_tags.items()} + tags = [{'Key': k, 'Value': v} for k, v in formatted_tags.items()] + info._ec2['connection'].create_tags(Resources=[info._ec2['image']['ImageId']], + Tags=tags) diff --git a/bootstrapvz/providers/ec2/tasks/connection.py b/bootstrapvz/providers/ec2/tasks/connection.py index f597f72..b7302e3 100644 --- a/bootstrapvz/providers/ec2/tasks/connection.py +++ b/bootstrapvz/providers/ec2/tasks/connection.py @@ -64,7 +64,7 @@ class Connect(Task): @classmethod def run(cls, info): - from boto.ec2 import connect_to_region + import boto3 connect_args = { 'aws_access_key_id': info.credentials['access-key'], 'aws_secret_access_key': info.credentials['secret-key'] @@ -73,4 +73,7 @@ class Connect(Task): if 'security-token' in info.credentials: connect_args['security_token'] = info.credentials['security-token'] - info._ec2['connection'] = connect_to_region(info._ec2['region'], **connect_args) + info._ec2['connection'] = boto3.Session(info._ec2['region'], + info.credentials['access-key'], + info.credentials['secret-key']) + info._ec2['connection'] = boto3.client('ec2', region_name=info._ec2['region']) diff --git a/bootstrapvz/providers/ec2/tasks/ebs.py b/bootstrapvz/providers/ec2/tasks/ebs.py index f50aa6b..a5d336f 100644 --- a/bootstrapvz/providers/ec2/tasks/ebs.py +++ b/bootstrapvz/providers/ec2/tasks/ebs.py @@ -28,3 +28,10 @@ class Snapshot(Task): @classmethod def run(cls, info): info._ec2['snapshot'] = info.volume.snapshot() + +# # Setting up tags on the snapshot +# if 'tags' in info.manifest.data: +# raw_tags = info.manifest.data['tags'] +# tags = {k: v.format(**info.manifest_vars) for k, v in raw_tags.items()} +# info._ec2['connection'](Resources=[info._ec2['snapshot']], +# Tags=[tags]) From 07c66e903098f8a0f20205879a5ac1b791cb1d40 Mon Sep 17 00:00:00 2001 From: Marcin Kulisz Date: Sat, 12 Nov 2016 21:47:30 +0000 Subject: [PATCH 2/7] EC2 provider: added ENA driver (installing with + enhanced_networking set to simple) --- bootstrapvz/providers/ec2/__init__.py | 4 +++ bootstrapvz/providers/ec2/tasks/ami.py | 1 + bootstrapvz/providers/ec2/tasks/network.py | 40 ++++++++++++++++++++-- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/bootstrapvz/providers/ec2/__init__.py b/bootstrapvz/providers/ec2/__init__.py index 29eabf1..3bc838a 100644 --- a/bootstrapvz/providers/ec2/__init__.py +++ b/bootstrapvz/providers/ec2/__init__.py @@ -68,6 +68,9 @@ def resolve_tasks(taskset, manifest): tasks.tuning.BlackListModules, boot.BlackListModules, boot.DisableGetTTYs, + tasks.boot.AddXenGrubConsoleOutputDevice, + grub.WriteGrubConfig, + tasks.boot.UpdateGrubConfig, initd.AddExpandRoot, initd.RemoveHWClock, initd.InstallInitScripts, @@ -133,6 +136,7 @@ def resolve_tasks(taskset, manifest): if manifest.provider.get('enhanced_networking', None) == 'simple': taskset.update([kernel.AddDKMSPackages, tasks.network.InstallEnhancedNetworking, + tasks.network.InstallENANetworking, kernel.UpdateInitramfs]) taskset.update([filesystem.Format, diff --git a/bootstrapvz/providers/ec2/tasks/ami.py b/bootstrapvz/providers/ec2/tasks/ami.py index 77fe195..202fb3b 100644 --- a/bootstrapvz/providers/ec2/tasks/ami.py +++ b/bootstrapvz/providers/ec2/tasks/ami.py @@ -125,6 +125,7 @@ class RegisterAMI(Task): if info.manifest.provider.get('enhanced_networking', None) == 'simple': registration_params['SriovNetSupport'] = 'simple' + registration_params['EnaSupport'] = True info._ec2['image'] = info._ec2['connection'].register_image(**registration_params) diff --git a/bootstrapvz/providers/ec2/tasks/network.py b/bootstrapvz/providers/ec2/tasks/network.py index ffcd70e..77b76f8 100644 --- a/bootstrapvz/providers/ec2/tasks/network.py +++ b/bootstrapvz/providers/ec2/tasks/network.py @@ -101,7 +101,8 @@ class InstallEnhancedNetworking(Task): log_check_call(['tar', '--ungzip', '--extract', '--file', archive, - '--directory', os.path.join(info.root, 'usr', 'src')]) + '--directory', os.path.join(info.root, 'usr', + 'src')]) with open(os.path.join(module_path, 'dkms.conf'), 'w') as dkms_conf: dkms_conf.write("""PACKAGE_NAME="ixgbevf" @@ -118,4 +119,39 @@ AUTOINSTALL="yes" for task in ['add', 'build', 'install']: # Invoke DKMS task using specified kernel module (-m) and version (-v) log_check_call(['chroot', info.root, - 'dkms', task, '-m', 'ixgbevf', '-v', version, '-k', info.kernel_version]) + 'dkms', task, '-m', 'ixgbevf', '-v', version, '-k', + info.kernel_version]) + + +class InstallENANetworking(Task): + description = '***** Installing ENA networking kernel driver using DKMS' + phase = phases.system_modification + successors = [kernel.UpdateInitramfs] + + @classmethod + def run(cls, info): + version = '1.0.0' + drivers_url = 'https://github.com/amzn/amzn-drivers' + module_path = os.path.join(info.root, 'usr', 'src', + 'amzn-drivers-%s' % (version)) + + from bootstrapvz.common.tools import log_check_call + log_check_call(['git', 'clone', drivers_url, module_path]) + + with open(os.path.join(module_path, 'dkms.conf'), 'w') as dkms_conf: + dkms_conf.write("""PACKAGE_NAME="ena" +PACKAGE_VERSION="%s" +CLEAN="make -C kernel/linux/ena clean" +MAKE="make -C kernel/linux/ena/ BUILD_KERNEL=${kernelver}" +BUILT_MODULE_NAME[0]="ena" +BUILT_MODULE_LOCATION="kernel/linux/ena" +DEST_MODULE_LOCATION[0]="/updates" +DEST_MODULE_NAME[0]="ena" +AUTOINSTALL="yes" +""" % (version)) + + for task in ['add', 'build', 'install']: + # Invoke DKMS task using specified kernel module (-m) and version (-v) + log_check_call(['chroot', info.root, + 'dkms', task, '-m', 'amzn-drivers', '-v', version, + '-k', info.kernel_version]) From ed33a5f067aefae8990c965c65630ab5db40363a Mon Sep 17 00:00:00 2001 From: Marcin Kulisz Date: Sat, 12 Nov 2016 21:57:42 +0000 Subject: [PATCH 3/7] ec2_launch plugin porting to boto3 + (print_public_ip not working yet) --- bootstrapvz/plugins/ec2_launch/tasks.py | 28 +++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/bootstrapvz/plugins/ec2_launch/tasks.py b/bootstrapvz/plugins/ec2_launch/tasks.py index b0c5add..a1ada4d 100644 --- a/bootstrapvz/plugins/ec2_launch/tasks.py +++ b/bootstrapvz/plugins/ec2_launch/tasks.py @@ -23,19 +23,21 @@ class LaunchEC2Instance(Task): @classmethod def run(cls, info): conn = info._ec2['connection'] - r = conn.run_instances(info._ec2['image'], - security_group_ids=info.manifest.plugins['ec2_launch'].get('security_group_ids'), - key_name=info.manifest.plugins['ec2_launch'].get('ssh_key'), - instance_type=info.manifest.plugins['ec2_launch'].get('instance_type', + r = conn.run_instances(ImageId=info._ec2['image']['ImageId'], + MinCount=1, + MaxCount=1, + SecurityGroupIds=info.manifest.plugins['ec2_launch'].get('security_group_ids'), + KeyName=info.manifest.plugins['ec2_launch'].get('ssh_key'), + InstanceType=info.manifest.plugins['ec2_launch'].get('instance_type', 'm3.medium')) - info._ec2['instance'] = r.instances[0] + info._ec2['instance'] = r['Instances'][0] if 'tags' in info.manifest.plugins['ec2_launch']: - def apply_format(v): - return v.format(**info.manifest_vars) - tags = info.manifest.plugins['ec2_launch']['tags'] - r = {k: apply_format(v) for k, v in tags.items()} - conn.create_tags([info._ec2['instance'].id], r) + raw_tags = info.manifest.plugins['ec2_launch']['tags'] + formatted_tags = {k: v.format(**info.manifest_vars) for k, v in raw_tags.items()} + tags = [{'Key': k, 'Value': v} for k, v in formatted_tags.items()] + conn.create_tags(Resources=[info._ec2['instance']['InstanceId']], + Tags=tags) class PrintPublicIPAddress(Task): @@ -54,11 +56,11 @@ class PrintPublicIPAddress(Task): def instance_has_ip(): ec2['instance'].update() - return ec2['instance'].ip_address + return ec2['instance']['PublicIpAddress'] if waituntil(instance_has_ip, timeout=120, interval=5): - logger.info('******* EC2 IP ADDRESS: %s *******' % ec2['instance'].ip_address) - f.write(ec2['instance'].ip_address) + logger.info('******* EC2 IP ADDRESS: %s *******' % ec2['instance']['PublicIpAddress']) + f.write(ec2['instance']['PublicIpAddress']) else: logger.error('Could not get IP address for the instance') f.write('') From ef698b06caec0f72e48aafa8a025f2c708712571 Mon Sep 17 00:00:00 2001 From: Marcin Kulisz Date: Fri, 20 Jan 2017 13:50:54 +0000 Subject: [PATCH 4/7] Final fix for ec2_launch plugin --- bootstrapvz/plugins/ec2_launch/tasks.py | 17 +++++++++-------- bootstrapvz/providers/ec2/tasks/connection.py | 2 ++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/bootstrapvz/plugins/ec2_launch/tasks.py b/bootstrapvz/plugins/ec2_launch/tasks.py index a1ada4d..20894bc 100644 --- a/bootstrapvz/plugins/ec2_launch/tasks.py +++ b/bootstrapvz/plugins/ec2_launch/tasks.py @@ -48,20 +48,21 @@ class PrintPublicIPAddress(Task): @classmethod def run(cls, info): ec2 = info._ec2 + conn = info._ec2['connection'] logger = logging.getLogger(__name__) filename = info.manifest.plugins['ec2_launch']['print_public_ip'] if not filename: filename = '/dev/null' f = open(filename, 'w') - def instance_has_ip(): - ec2['instance'].update() - return ec2['instance']['PublicIpAddress'] - - if waituntil(instance_has_ip, timeout=120, interval=5): - logger.info('******* EC2 IP ADDRESS: %s *******' % ec2['instance']['PublicIpAddress']) - f.write(ec2['instance']['PublicIpAddress']) - else: + try: + waiter = conn.get_waiter('instance_status_ok') + waiter.wait(InstanceIds=[info._ec2['instance']['InstanceId']], + Filters=[{'Name': 'instance-state-name', 'Values': ['running']}]) + info._ec2['instance'] = conn.describe_instances(InstanceIds=[info._ec2['instance']['InstanceId']])['Reservations'][0]['Instances'][0] + logger.info('******* EC2 IP ADDRESS: %s *******' % info._ec2['instance']['PublicIpAddress'] ) + f.write(info._ec2['instance']['PublicIpAddress']) + except: logger.error('Could not get IP address for the instance') f.write('') diff --git a/bootstrapvz/providers/ec2/tasks/connection.py b/bootstrapvz/providers/ec2/tasks/connection.py index b7302e3..cb9ab2a 100644 --- a/bootstrapvz/providers/ec2/tasks/connection.py +++ b/bootstrapvz/providers/ec2/tasks/connection.py @@ -38,6 +38,7 @@ class GetCredentials(Task): def env_key(key): return ('aws-' + key).upper().replace('-', '_') + if all(getenv(env_key(key)) is not None for key in keys): for key in keys: creds[key] = getenv(env_key(key)) @@ -45,6 +46,7 @@ class GetCredentials(Task): def provider_key(key): return key.replace('-', '_') + import boto.provider provider = boto.provider.Provider('aws') if all(getattr(provider, provider_key(key)) is not None for key in keys): From 6507ccbc0b78a2503fa28866731b21da96e65cf7 Mon Sep 17 00:00:00 2001 From: Marcin Kulisz Date: Sat, 21 Jan 2017 20:38:52 +0000 Subject: [PATCH 5/7] Adding boto3 to setup.py and minor lint fixes --- bootstrapvz/plugins/ec2_launch/tasks.py | 9 ++++----- setup.py | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bootstrapvz/plugins/ec2_launch/tasks.py b/bootstrapvz/plugins/ec2_launch/tasks.py index 20894bc..ec2d7b9 100644 --- a/bootstrapvz/plugins/ec2_launch/tasks.py +++ b/bootstrapvz/plugins/ec2_launch/tasks.py @@ -1,7 +1,7 @@ +import logging from bootstrapvz.base import Task from bootstrapvz.common import phases from bootstrapvz.providers.ec2.tasks import ami -import logging # TODO: Merge with the method available in wip-integration-tests branch @@ -29,7 +29,7 @@ class LaunchEC2Instance(Task): SecurityGroupIds=info.manifest.plugins['ec2_launch'].get('security_group_ids'), KeyName=info.manifest.plugins['ec2_launch'].get('ssh_key'), InstanceType=info.manifest.plugins['ec2_launch'].get('instance_type', - 'm3.medium')) + 'm3.medium')) info._ec2['instance'] = r['Instances'][0] if 'tags' in info.manifest.plugins['ec2_launch']: @@ -47,7 +47,6 @@ class PrintPublicIPAddress(Task): @classmethod def run(cls, info): - ec2 = info._ec2 conn = info._ec2['connection'] logger = logging.getLogger(__name__) filename = info.manifest.plugins['ec2_launch']['print_public_ip'] @@ -58,9 +57,9 @@ class PrintPublicIPAddress(Task): try: waiter = conn.get_waiter('instance_status_ok') waiter.wait(InstanceIds=[info._ec2['instance']['InstanceId']], - Filters=[{'Name': 'instance-state-name', 'Values': ['running']}]) + Filters=[{'Name': 'instance-state-name', 'Values': ['running']}]) info._ec2['instance'] = conn.describe_instances(InstanceIds=[info._ec2['instance']['InstanceId']])['Reservations'][0]['Instances'][0] - logger.info('******* EC2 IP ADDRESS: %s *******' % info._ec2['instance']['PublicIpAddress'] ) + logger.info('******* EC2 IP ADDRESS: %s *******' % info._ec2['instance']['PublicIpAddress']) f.write(info._ec2['instance']['PublicIpAddress']) except: logger.error('Could not get IP address for the instance') diff --git a/setup.py b/setup.py index bffe5bf..5c3e05f 100644 --- a/setup.py +++ b/setup.py @@ -24,6 +24,7 @@ setup(name='bootstrap-vz', 'jsonschema >= 2.3.0', 'pyyaml >= 3.10', 'boto >= 2.14.0', + 'boto3 >= 1.4.2', 'docopt >= 0.6.1', 'pyrfc3339 >= 1.0', 'requests >= 2.4.3', From d92123c9dd6e34762b8e7f004e3ff53966f3aa41 Mon Sep 17 00:00:00 2001 From: Marcin Kulisz Date: Sat, 21 Jan 2017 21:13:07 +0000 Subject: [PATCH 6/7] Small update to Stretch EC2 manifest --- manifests/official/ec2/ebs-stretch-amd64-hvm.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/official/ec2/ebs-stretch-amd64-hvm.yml b/manifests/official/ec2/ebs-stretch-amd64-hvm.yml index 2b92b2d..a710b2f 100644 --- a/manifests/official/ec2/ebs-stretch-amd64-hvm.yml +++ b/manifests/official/ec2/ebs-stretch-amd64-hvm.yml @@ -2,7 +2,7 @@ name: debian-{system.release}-{system.architecture}-{provider.virtualization}-{%Y}-{%m}-{%d}-{%H}{%M}-ebs tags: Name: "Stretch 9.0 alpha" - Debian: "9.0~{%Y}{%m}{%d}" + Debian: "9.0~{%Y}{%m}{%d}{%H}{%M}" provider: name: ec2 virtualization: hvm From 673260ec63b0290c6f5d109ad8d2eeabfff76647 Mon Sep 17 00:00:00 2001 From: Marcin Kulisz Date: Sat, 21 Jan 2017 22:44:16 +0000 Subject: [PATCH 7/7] EC2 provider: fixing snapshot tagging --- bootstrapvz/providers/ec2/tasks/ebs.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bootstrapvz/providers/ec2/tasks/ebs.py b/bootstrapvz/providers/ec2/tasks/ebs.py index a5d336f..5efd805 100644 --- a/bootstrapvz/providers/ec2/tasks/ebs.py +++ b/bootstrapvz/providers/ec2/tasks/ebs.py @@ -29,9 +29,10 @@ class Snapshot(Task): def run(cls, info): info._ec2['snapshot'] = info.volume.snapshot() -# # Setting up tags on the snapshot -# if 'tags' in info.manifest.data: -# raw_tags = info.manifest.data['tags'] -# tags = {k: v.format(**info.manifest_vars) for k, v in raw_tags.items()} -# info._ec2['connection'](Resources=[info._ec2['snapshot']], -# Tags=[tags]) + # Setting up tags on the snapshot + if 'tags' in info.manifest.data: + raw_tags = info.manifest.data['tags'] + formatted_tags = {k: v.format(**info.manifest_vars) for k, v in raw_tags.items()} + tags = [{'Key': k, 'Value': v} for k, v in formatted_tags.items()] + info._ec2['connection'].create_tags(Resources=[info._ec2['snapshot']], + Tags=tags)