def attach_volume(nova_client, cinder_client, **kwargs): server_id = ctx.source.instance.runtime_properties[OPENSTACK_ID_PROPERTY] volume_id = ctx.target.instance.runtime_properties[OPENSTACK_ID_PROPERTY] if is_external_relationship(ctx): ctx.logger.info('Validating external volume and server ' 'are connected') attachment = volume.get_attachment(cinder_client=cinder_client, volume_id=volume_id, server_id=server_id) if attachment: return else: raise NonRecoverableError( 'Expected external resources server {0} and volume {1} to be ' 'connected'.format(server_id, volume_id)) # Note: The 'device_name' property should actually be a property of the # relationship between a server and a volume; It'll move to that # relationship type once relationship properties are better supported. device = ctx.target.node.properties[volume.DEVICE_NAME_PROPERTY] nova_client.volumes.create_server_volume(server_id, volume_id, device) volume.wait_until_status(cinder_client=cinder_client, volume_id=volume_id, status=volume.VOLUME_STATUS_IN_USE)
def _detach_volume(nova_client, cinder_client, server_id, volume_id): attachment = volume.get_attachment(cinder_client=cinder_client, volume_id=volume_id, server_id=server_id) if attachment: nova_client.volumes.delete_server_volume(server_id, attachment['id']) volume.wait_until_status(cinder_client=cinder_client, volume_id=volume_id, status=volume.VOLUME_STATUS_AVAILABLE)
def detach_volume(nova_client, cinder_client, **kwargs): if is_external_relationship(ctx): ctx.logger.info('Not detaching volume from server since ' 'external volume and server are being used') return server_id = ctx.target.instance.runtime_properties[OPENSTACK_ID_PROPERTY] volume_id = ctx.source.instance.runtime_properties[OPENSTACK_ID_PROPERTY] attachment = volume.get_attachment(cinder_client=cinder_client, volume_id=volume_id, server_id=server_id) if attachment: nova_client.volumes.delete_server_volume(server_id, attachment['id']) volume.wait_until_status(cinder_client=cinder_client, volume_id=volume_id, status=volume.VOLUME_STATUS_AVAILABLE)
def attach_volume(nova_client, cinder_client, status_attempts, status_timeout, **kwargs): server_id = get_openstack_id(ctx.target) volume_id = get_openstack_id(ctx.source) if is_external_relationship_not_conditionally_created(ctx): ctx.logger.info('Validating external volume and server ' 'are connected') attachment = volume.get_attachment(cinder_client=cinder_client, volume_id=volume_id, server_id=server_id) if attachment: return else: raise NonRecoverableError( 'Expected external resources server {0} and volume {1} to be ' 'connected'.format(server_id, volume_id)) # Note: The 'device_name' property should actually be a property of the # relationship between a server and a volume; It'll move to that # relationship type once relationship properties are better supported. device = ctx.source.node.properties[volume.DEVICE_NAME_PROPERTY] nova_client.volumes.create_server_volume( server_id, volume_id, device if device != 'auto' else None) try: vol, wait_succeeded = volume.wait_until_status( cinder_client=cinder_client, volume_id=volume_id, status=volume.VOLUME_STATUS_IN_USE, num_tries=status_attempts, timeout=status_timeout ) if not wait_succeeded: raise RecoverableError( 'Waiting for volume status {0} failed - detaching volume and ' 'retrying..'.format(volume.VOLUME_STATUS_IN_USE)) if device == 'auto': # The device name was assigned automatically so we # query the actual device name attachment = volume.get_attachment( cinder_client=cinder_client, volume_id=volume_id, server_id=server_id ) device_name = attachment['device'] ctx.logger.info('Detected device name for attachment of volume ' '{0} to server {1}: {2}' .format(volume_id, server_id, device_name)) ctx.source.instance.runtime_properties[ volume.DEVICE_NAME_PROPERTY] = device_name except Exception, e: if not isinstance(e, NonRecoverableError): _prepare_attach_volume_to_be_repeated( nova_client, cinder_client, server_id, volume_id, status_attempts, status_timeout) raise
def attach_volume(nova_client, cinder_client, status_attempts, status_timeout, **kwargs): server_id = ctx.target.instance.runtime_properties[OPENSTACK_ID_PROPERTY] volume_id = ctx.source.instance.runtime_properties[OPENSTACK_ID_PROPERTY] if is_external_relationship_not_conditionally_created(ctx): ctx.logger.info('Validating external volume and server ' 'are connected') attachment = volume.get_attachment(cinder_client=cinder_client, volume_id=volume_id, server_id=server_id) if attachment: return else: raise NonRecoverableError( 'Expected external resources server {0} and volume {1} to be ' 'connected'.format(server_id, volume_id)) # Note: The 'device_name' property should actually be a property of the # relationship between a server and a volume; It'll move to that # relationship type once relationship properties are better supported. device = ctx.source.node.properties[volume.DEVICE_NAME_PROPERTY] nova_client.volumes.create_server_volume( server_id, volume_id, device if device != 'auto' else None) try: vol, wait_succeeded = volume.wait_until_status( cinder_client=cinder_client, volume_id=volume_id, status=volume.VOLUME_STATUS_IN_USE, num_tries=status_attempts, timeout=status_timeout ) if not wait_succeeded: raise RecoverableError( 'Waiting for volume status {0} failed - detaching volume and ' 'retrying..'.format(volume.VOLUME_STATUS_IN_USE)) if device == 'auto': # The device name was assigned automatically so we # query the actual device name attachment = volume.get_attachment( cinder_client=cinder_client, volume_id=volume_id, server_id=server_id ) device_name = attachment['device'] ctx.logger.info('Detected device name for attachment of volume ' '{0} to server {1}: {2}' .format(volume_id, server_id, device_name)) ctx.source.instance.runtime_properties[ volume.DEVICE_NAME_PROPERTY] = device_name except Exception, e: if not isinstance(e, NonRecoverableError): _prepare_attach_volume_to_be_repeated( nova_client, cinder_client, server_id, volume_id, status_attempts, status_timeout) raise
def test_wait_until_status(self, cinder_m): cinder_instance = cinder_m.return_value volume_ctx, volume_id = self._simple_volume_ctx() # ready by first call volume_mock = mock.Mock() volume_mock.status = "ready" cinder_instance.volumes.get = mock.Mock(return_value=volume_mock) with mock.patch('openstack_plugin_common._find_context_in_kw', return_value=volume_ctx): volume.wait_until_status(volume_id=volume_id, status='ready', num_tries=1, timeout=1) cinder_instance.volumes.get.assert_called_once_with(volume_id) # unready by first call volume_mock = mock.Mock() volume_mock.status = "unready" cinder_instance.volumes.get = mock.Mock(return_value=volume_mock) with mock.patch('openstack_plugin_common._find_context_in_kw', return_value=volume_ctx): self.assertEqual( volume.wait_until_status(volume_id=volume_id, status='ready', num_tries=2, timeout=1), (volume_mock, False) ) cinder_instance.volumes.get.assert_has_calls([ mock.call(volume_id), mock.call(volume_id)]) # volume error volume_mock = mock.Mock() volume_mock.status = volume.VOLUME_STATUS_ERROR cinder_instance.volumes.get = mock.Mock(return_value=volume_mock) with mock.patch('openstack_plugin_common._find_context_in_kw', return_value=volume_ctx): with self.assertRaises(cfy_exc.NonRecoverableError): volume.wait_until_status(volume_id=volume_id, status='ready', num_tries=2, timeout=1) cinder_instance.volumes.get.assert_called_once_with(volume_id)