def test_launch_config_add_with_block_device_mapping(sys, user_input): sys.argv = [ 'autoscaler_launch_config', 'add', 'web', ] # "image_id", "key_name", "security_groups", "user_data", "instance_type", # "kernel_id", "ramdisk_id", "block_device_mappings", "instance_monitoring", # "instance_profile_name", "spot_price", "ebs_optimized", "associate_public_ip_address" user_input.side_effect = [ 'ami-1234abcd', 'the_key', "default,web", "echo 'web' > /etc/config", "m1.small", "", "", "/dev/xvda=:100,/dev/xvdb=:200,/dev/xvdc=snap-1234abcd:10", "yes", "arn:aws:iam::123456789012:instance-profile/tester", "0.2", "yes", "", ] # Simulate CLI call launch_config() # Build a fake block device mapping bdm = BlockDeviceMapping() bdm['/dev/xvda'] = BlockDeviceType(volume_id='/dev/xvda', size=100) bdm['/dev/xvdb'] = BlockDeviceType(volume_id='/dev/xvdb', size=200) bdm['/dev/xvdc'] = BlockDeviceType(volume_id='/dev/xvdc', snapshot_id="snap-1234abcd", size=10) conn = boto.connect_autoscale(use_block_device_types=True) configs = conn.get_all_launch_configurations() configs.should.have.length_of(1) config = configs[0] config.name.should.equal("web") config.image_id.should.equal("ami-1234abcd") config.key_name.should.equal("the_key") set(config.security_groups).should.equal(set(["web", "default"])) config.user_data.should.equal("echo 'web' > /etc/config") config.instance_type.should.equal("m1.small") config.kernel_id.should.equal("") config.ramdisk_id.should.equal("") config.instance_monitoring.enabled.should.equal('true') config.spot_price.should.equal(0.2) config.ebs_optimized.should.equal(True) config.associate_public_ip_address.should.equal(False) config.block_device_mappings.keys().should.equal(bdm.keys()) config.block_device_mappings['/dev/xvda'].size.should.equal(100) config.block_device_mappings['/dev/xvdb'].size.should.equal(200) config.block_device_mappings['/dev/xvdc'].size.should.equal(10) config.block_device_mappings['/dev/xvdc'].snapshot_id.should.equal( "snap-1234abcd")
def do_build(ctxt, **kwargs): conn = ctxt.cnx_ec2 if 'template' in kwargs and kwargs['template']: template_file_name = kwargs['template'] kwargs = parse_template(ctxt, template_file_name, kwargs) del kwargs['template'] defaultrun = {'instance_type': 'm1.large', 'key_name': ctxt.key_name } for key in defaultrun: if key not in kwargs or kwargs[key] == None: kwargs[key] = defaultrun[key] (remote_user, kwargs) = get_remote_user(ctxt, **kwargs) (key_file, kwargs) = get_key_file(ctxt, **kwargs) (tags,kwargs) = do_tags(**kwargs) do_run_scripts = kwargs.pop('run') ########### # Check VM naming ########### if 'Name' not in tags and kwargs['hostname'] is not None: tags['Name'] = kwargs['hostname'] if 'Name' not in tags: yield "instance name is mandatory" return try: oslib.ec2_objects.Instance(ctxt, name=tags['Name']).get() # if get succed, the name already exist, else get throws an exception yield "duplicate name %s" % tags['Name'] return except: pass user_data_properties = {} image = kwargs.pop('image_id', None) ########### # Check device mapping ########### volumes = BlockDeviceMapping(conn) first_volume = 'f' l = first_volume ebs_optimized = False for volume_info in kwargs.pop('volume_size', []): # yaml is not typed, volume_info can be a string or a number if isinstance(volume_info, basestring): options = volume_info.split(',') size = int(oslib.parse_size(options[0], 'G', default_suffix='G')) else: options = [] size = int(volume_info) vol_kwargs = {"connection":conn, "size": size} if len(options) > 1: for opt in options[1:]: parsed = opt.split('=') key = parsed[0] if len(parsed) == 2: value = parsed[1] elif len(parsed) == 1: value = True else: raise OSLibError("can't parse volume argument %s", opt) if key == 'iops': ebs_optimized = True vol_kwargs['volume_type'] = 'io1' vol_kwargs[key] = value volumes["/dev/sd%s"%l] = BlockDeviceType(**vol_kwargs) l = chr( ord(l[0]) + 1) kwargs['ebs_optimized'] = ebs_optimized # if drive letter is not f, some volumes definition was found if l != first_volume: kwargs['block_device_map'] = volumes user_data_properties['volumes'] = ' '.join(volumes.keys()) # after user_data_properties['volumes'] otherwise they will be lvm'ed for snapshot_id in kwargs.pop('snap_id', []): volumes["/dev/sd%s"%l] = BlockDeviceType(connection=conn, snapshot_id=snapshot_id) l = chr( ord(l[0]) + 1) kwargs = build_user_data(user_data_properties, **kwargs) ########### # Check elastic IP ########### if kwargs['elastic_ip']: eip = True else: eip = False del kwargs['elastic_ip'] for k in kwargs.keys()[:]: value = kwargs[k] if kwargs[k] == None: del(kwargs[k]) elif value.__class__ == [].__class__ and len(value) == 0: del(kwargs[k]) if 'private_ip_address' in kwargs and kwargs['private_ip_address']: netif_specification = NetworkInterfaceCollection() netif_kwargs = {} if kwargs['private_ip_address']: netif_kwargs['private_ip_address'] = kwargs['private_ip_address'] del kwargs['private_ip_address'] if 'associate_public_ip_address' in kwargs and kwargs['associate_public_ip_address']: netif_kwargs['associate_public_ip_address'] = kwargs['associate_public_ip_address'] del kwargs['associate_public_ip_address'] if 'security_groups' in kwargs and kwargs['security_groups']: netif_kwargs['groups'] = kwargs['security_groups'] del kwargs['security_groups'] netif_kwargs['subnet_id'] = kwargs['subnet_id'] del kwargs['subnet_id'] print netif_kwargs spec = NetworkInterfaceSpecification(**netif_kwargs) netif_specification.append(spec) kwargs['network_interfaces'] = netif_specification reservation = conn.run_instances(image, **kwargs) instance = reservation.instances[0] # Quick hack to keep the selected remote user instance.remote_user = remote_user if len(tags) > 0: conn.create_tags([ instance.id ], tags) if instance.interfaces and len(instance.interfaces) > 0: for interface in instance.interfaces: conn.create_tags([ interface.id ], {'creator': tags['creator']}) while instance.state != 'running' and instance.state != 'terminated': instance.update(True) yield (".") time.sleep(1) yield ("\n") if eip: ip = conn.allocate_address().public_ip conn.associate_address(instance_id = instance.id, public_ip=ip) conn.create_tags([instance.id], {"EIP": ip}) #Update tag for this instance's volumes for device in instance.block_device_mapping: device_type = instance.block_device_mapping[device] (vol_tags, vol_kwargs) = do_tags(name='%s/%s' % (tags['Name'], device.replace('/dev/',''))) conn.create_tags([ device_type.volume_id ], vol_tags) instance.update(True) windows_instance = instance.platform == 'Windows' if do_run_scripts and not windows_instance: while instance.state != 'terminated': try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(1.0) s.connect((instance.public_dns_name, 22)) s.close() break except socket.error, msg: yield (".") s.close() time.sleep(1) yield ("\n") instance.key_file = key_file remote_setup(instance, remote_user, key_file)
userdata['source'] = src_inst.public_dns_name # Start the destination instance info('Starting EC2 destination instance') dst_inst = ec2dst.run_instance_wait(amazon_linux_ebs_64[args.dst_region], key_name = args.dst_keypair, security_groups = [args.name], user_data = dst_data % userdata, instance_type = args.inst_type, block_device_map = dst_inst_bdm, instance_initiated_shutdown_behavior = 'terminate') # Clean up created volumes dst_inst_bdm = dst_inst.block_device_mapping vol_ids = [] for b in dst_inst_bdm.keys(): if dst_inst_bdm[b].volume_id and b != '/dev/sda1': vol_ids.append(dst_inst_bdm[b].volume_id) vols = ec2dst.get_all_volumes(vol_ids) for v in vols: cleanup.add(v, 'delete', 'Deleting destination volume') cleanup.add(dst_inst, 'terminate_wait', 'Terminating destination instance') info('Tagging EC2 destination instance') ec2dst.create_tags([dst_inst.id], {'Name': args.name}) # Set up security groups for Tsunami info('Allowing TCP access to source instance for tsunamid') src_sg.authorize('tcp', 46224, 46224, dst_inst.ip_address + '/32') src_sg.authorize('tcp', 46224, 46224, dst_inst.private_ip_address + '/32')