def test_validate_ec2_req_timestamp_Expires(self): # EC2 request with both Timestamp and Expires params = {'Timestamp': '2011-04-22T11:29:49Z', 'Expires': ec2api_timeutils.isotime()} self.assertRaises(exception.InvalidRequest, ec2utils.is_ec2_timestamp_expired, params)
def test_validate_ec2_req_timestamp_Expires(self): # EC2 request with both Timestamp and Expires params = { 'Timestamp': '2011-04-22T11:29:49Z', 'Expires': ec2api_timeutils.isotime() } self.assertRaises(exception.InvalidRequest, ec2utils.is_ec2_timestamp_expired, params)
def _attach_network_interface_item(context, network_interface, instance_id, device_index, attach_time=None, delete_on_termination=False): if not attach_time: attach_time = timeutils.isotime(None, True) network_interface.update({ 'instance_id': instance_id, 'device_index': device_index, 'attach_time': attach_time, 'delete_on_termination': delete_on_termination}) db_api.update_item(context, network_interface)
def _attach_network_interface_item(context, network_interface, instance_id, device_index, attach_time=None, delete_on_termination=False): if not attach_time: attach_time = timeutils.isotime(None, True) network_interface.update({ 'instance_id': instance_id, 'device_index': device_index, 'attach_time': attach_time, 'delete_on_termination': delete_on_termination }) db_api.update_item(context, network_interface)
def test_validate_ec2_req_expired(self): params = {'Expires': ec2api_timeutils.isotime()} expired = ec2utils.is_ec2_timestamp_expired(params) self.assertTrue(expired)
def test_validate_ec2_req_timestamp_not_expired(self): params = {'Timestamp': ec2api_timeutils.isotime()} expired = ec2utils.is_ec2_timestamp_expired(params, expires=15) self.assertFalse(expired)
def create_image(context, instance_id, name=None, description=None, no_reboot=False, block_device_mapping=None): instance = ec2utils.get_db_item(context, instance_id) if not instance_api._is_ebs_instance(context, instance['os_id']): msg = _('Instance does not have a volume attached at root (null).') raise exception.InvalidParameterValue(value=instance_id, parameter='InstanceId', reason=msg) nova = clients.nova(context) os_instance = nova.servers.get(instance['os_id']) restart_instance = False if not no_reboot and os_instance.status != 'SHUTOFF': if os_instance.status != 'ACTIVE': # TODO(ft): Change the error code and message with the real AWS # ones msg = _('Instance must be run or stopped') raise exception.IncorrectState(reason=msg) restart_instance = True # meaningful image name name_map = dict(instance=instance['os_id'], now=timeutils.isotime()) name = name or _('image of %(instance)s at %(now)s') % name_map def delayed_create(context, image, name, os_instance): try: os_instance.stop() # wait instance for really stopped start_time = time.time() while os_instance.status != 'SHUTOFF': time.sleep(1) os_instance.get() # NOTE(yamahata): timeout and error. 1 hour for now for safety. # Is it too short/long? # Or is there any better way? timeout = 1 * 60 * 60 if time.time() > start_time + timeout: err = (_("Couldn't stop instance within %d sec") % timeout) raise exception.EC2Exception(message=err) # NOTE(ft): create an image with ec2_id metadata to let other code # link os and db objects in race conditions os_image_id = os_instance.create_image( name, metadata={'ec2_id': image['id']}) image['os_id'] = os_image_id db_api.update_item(context, image) except Exception: LOG.exception(_LE('Failed to complete image %s creation'), image.id) try: image['state'] = 'failed' db_api.update_item(context, image) except Exception: LOG.warning(_LW("Couldn't set 'failed' state for db image %s"), image.id, exc_info=True) try: os_instance.start() except Exception: LOG.warning(_LW('Failed to start instance %(i_id)s after ' 'completed creation of image %(image_id)s'), { 'i_id': instance['id'], 'image_id': image['id'] }, exc_info=True) image = {'is_public': False, 'description': description} if restart_instance: # NOTE(ft): image type is hardcoded, because we don't know it now, # but cannot change it later. But Nova doesn't specify container format # for snapshots of volume backed instances, so that it is 'ami' in fact image = db_api.add_item(context, 'ami', image) eventlet.spawn_n(delayed_create, context, image, name, os_instance) else: glance = clients.glance(context) with common.OnCrashCleaner() as cleaner: os_image_id = os_instance.create_image(name) cleaner.addCleanup(glance.images.delete, os_image_id) # TODO(andrey-mp): snapshot and volume also must be deleted in case # of error os_image = glance.images.get(os_image_id) image['os_id'] = os_image_id image = db_api.add_item(context, _get_os_image_kind(os_image), image) return {'imageId': image['id']}
def create_image(context, instance_id, name=None, description=None, no_reboot=False, block_device_mapping=None): instance = ec2utils.get_db_item(context, instance_id) if not instance_api._is_ebs_instance(context, instance['os_id']): msg = _('Instance does not have a volume attached at root (null).') raise exception.InvalidParameterValue(value=instance_id, parameter='InstanceId', reason=msg) nova = clients.nova(context) os_instance = nova.servers.get(instance['os_id']) restart_instance = False if not no_reboot and os_instance.status != 'SHUTOFF': if os_instance.status != 'ACTIVE': # TODO(ft): Change the error code and message with the real AWS # ones msg = _('Instance must be run or stopped') raise exception.IncorrectState(reason=msg) restart_instance = True # meaningful image name name_map = dict(instance=instance['os_id'], now=timeutils.isotime()) name = name or _('image of %(instance)s at %(now)s') % name_map def delayed_create(context, image, name, os_instance): try: os_instance.stop() # wait instance for really stopped start_time = time.time() while os_instance.status != 'SHUTOFF': time.sleep(1) os_instance.get() # NOTE(yamahata): timeout and error. 1 hour for now for safety. # Is it too short/long? # Or is there any better way? timeout = 1 * 60 * 60 if time.time() > start_time + timeout: err = (_("Couldn't stop instance within %d sec") % timeout) raise exception.EC2Exception(message=err) # NOTE(ft): create an image with ec2_id metadata to let other code # link os and db objects in race conditions os_image_id = os_instance.create_image( name, metadata={'ec2_id': image['id']}) image['os_id'] = os_image_id db_api.update_item(context, image) except Exception: LOG.exception(_LE('Failed to complete image %s creation'), image.id) try: image['state'] = 'failed' db_api.update_item(context, image) except Exception: LOG.warning(_LW("Couldn't set 'failed' state for db image %s"), image.id, exc_info=True) try: os_instance.start() except Exception: LOG.warning(_LW('Failed to start instance %(i_id)s after ' 'completed creation of image %(image_id)s'), {'i_id': instance['id'], 'image_id': image['id']}, exc_info=True) image = {'is_public': False, 'description': description} if restart_instance: # NOTE(ft): image type is hardcoded, because we don't know it now, # but cannot change it later. But Nova doesn't specify container format # for snapshots of volume backed instances, so that it is 'ami' in fact image = db_api.add_item(context, 'ami', image) eventlet.spawn_n(delayed_create, context, image, name, os_instance) else: glance = clients.glance(context) with common.OnCrashCleaner() as cleaner: os_image_id = os_instance.create_image(name) cleaner.addCleanup(glance.images.delete, os_image_id) # TODO(andrey-mp): snapshot and volume also must be deleted in case # of error os_image = glance.images.get(os_image_id) image['os_id'] = os_image_id image = db_api.add_item(context, _get_os_image_kind(os_image), image) return {'imageId': image['id']}