def test_list_instances_fail(self): self.ml.container_list.side_effect = ( lxd_exceptions.APIError('Fake', 500)) self.assertRaises( exception.NovaException, self.connection.list_instances )
def test_container_list_fail(self): """ container_list returns an exception.NovaException, if pylxd raises an APIError. """ self.ml.container_list.side_effect = (lxd_exceptions.APIError( 'Fake', 500)) self.assertRaises(exception.NovaException, self.session.container_list)
def test_live_migration_failed(self, mock_migrate): """Verify that an exception is raised when live-migration fails. """ self.flags(my_ip='fakeip') mock_migrate.side_effect = \ lxd_exceptions.APIError(500, 'Fake') self.assertRaises(lxd_exceptions.APIError, self.driver.live_migration, mock.sentinel.context, mock.sentinel.instance, mock.sentinel.dest, mock.sentinel.recover_method, mock.sentinel.block_migration, mock.sentinel.migrate_data)
def test_container_info_fail(self): """ container_info returns a dictionary reprsentation of userful information about a container (ip address, pid, etc). Verify that the container_info returns an exception.NovaException when there is an APIError. """ instance = stubs._fake_instance() self.ml.container_info.side_effect = (lxd_exceptions.APIError( 'Fake', 500)) self.assertRaises(exception.NovaException, self.session.container_info, instance)
def test_container_update_fail(self, tag, side_effect, expected): """ container_update will fail if the container is not found, or the LXD raises an API error. Verify that the exceptions are raised in both scenarios. """ config = mock.Mock() instance = stubs._fake_instance() self.ml.container_update.side_effect = (lxd_exceptions.APIError( 'Fake', 500)) self.assertRaises(expected, self.session.container_update, config, instance)
class SessionSnapshotTest(test.NoDBTestCase): def setUp(self): super(SessionSnapshotTest, self).setUp() """This is so we can mock out pylxd API calls.""" self.ml = stubs.lxd_mock() lxd_patcher = mock.patch('pylxd.api.API', mock.Mock(return_value=self.ml)) lxd_patcher.start() self.addCleanup(lxd_patcher.stop) self.session = session.LXDAPISession() @stubs.annotated_data( ('1,', (200, fake_api.fake_operation_info_ok())) ) def test_container_snapshot(self, tag, side_effect): snapshot = mock.Mock() instance = stubs._fake_instance() self.ml.container_snapshot_create.return_value = side_effect self.assertEqual(None, self.session.container_snapshot(snapshot, instance)) calls = [ mock.call.container_snapshot_create(instance.name, snapshot), mock.call.wait_container_operation('/1.0/operation/1234', 200, -1)] self.assertEqual(calls, self.ml.method_calls) @stubs.annotated_data( ('api_fail', lxd_exceptions.APIError(500, 'Fake'), exception.NovaException) ) def test_container_snapshot_fail(self, tag, side_effect, expected): snapshot = mock.Mock() instance = stubs._fake_instance() self.ml.container_snapshot_create.side_effect = side_effect self.assertRaises(expected, self.session.container_snapshot, instance.name, snapshot) @stubs.annotated_data( (1, (200, fake_api.fake_operation_info_ok())) ) def test_container_publish(self, tag, side_effect): image = mock.Mock() instance = stubs._fake_instance() self.ml.image_export.return_value = True self.assertTrue( self.session.container_publish(image, instance)) calls = [ mock.call.container_publish(image)] self.assertEqual(calls, self.ml.method_calls)
class SessionContainerTest(test.NoDBTestCase): def setUp(self): super(SessionContainerTest, self).setUp() """This is so we can mock out pylxd API calls.""" self.ml = stubs.lxd_mock() lxd_patcher = mock.patch('pylxd.deprecated.api.API', mock.Mock(return_value=self.ml)) lxd_patcher.start() self.addCleanup(lxd_patcher.stop) self.session = session.LXDAPISession() @stubs.annotated_data( ('1', (200, fake_api.fake_operation_info_ok())) ) def test_container_init(self, tag, side_effect): """ conatainer_init creates a container based on given config for a container. Check to see if we are returning the right pylxd calls for the LXD API. """ config = mock.Mock() instance = stubs._fake_instance() self.ml.container_init.return_value = side_effect self.ml.operation_info.return_value = \ (200, fake_api.fake_container_state(200)) self.assertIsNone(self.session.container_init(config, instance)) calls = [mock.call.container_init(config), mock.call.wait_container_operation( '/1.0/operation/1234', 200, -1), mock.call.operation_info('/1.0/operation/1234')] self.assertEqual(calls, self.ml.method_calls) @stubs.annotated_data( ('api_fail', lxd_exceptions.APIError(500, 'Fake'), exception.NovaException), ) def test_container_init_fail(self, tag, side_effect, expected): """ continer_init create as container on a given LXD host. Make sure that we reaise an exception.NovaException if there is an APIError from the LXD API. """ config = mock.Mock() instance = stubs._fake_instance() self.ml.container_init.side_effect = side_effect self.assertRaises(expected, self.session.container_init, config, instance)
def test_destroy_fail(self): instance = stubs._fake_instance() context = mock.Mock() network_info = mock.Mock() self.ml.container_destroy.side_effect = (lxd_exceptions.APIError( 'Fake', 500)) with test.nested( mock.patch.object(session.LXDAPISession, 'container_destroy'), mock.patch.object(session.LXDAPISession, 'container_stop'), mock.patch.object(self.connection, 'cleanup'), mock.patch.object(container_ops.LXDContainerOperations, 'unplug_vifs'), ) as (container_destroy, container_stop, cleanup, unplug_vifs): self.connection.destroy(context, instance, network_info)
def test_container_state_fail(self, tag, container_defined, side_effect, expected): """ container_state translates LXD container status into what nova understands. If the API sends an APIError then raise an power_state.NOSTATE, same if the the container goes missing. """ instance = stubs._fake_instance() if container_defined: self.ml.container_defined.return_value = container_defined self.ml.container_state.side_effect = (lxd_exceptions.APIError( 'Fake', 500)) self.assertEqual(expected, self.session.container_state(instance)) if not container_defined: self.ml.container_defined.return_value = container_defined self.assertEqual(expected, self.session.container_state(instance))
def get_lxd_error(state, data): status_code = data.get("error_code") error = data.get("error") raise exceptions.APIError(error, status_code)
class LXDAPIImageTestObject(LXDAPITestBase): list_data = ( ('list', (), ()), ('search', ({ 'foo': 'bar' }, ), ('foo=bar', )), ) @annotated_data(*list_data) def test_list_images(self, method, args, call_args, ms): ms.return_value = ('200', fake_api.fake_image_list()) self.assertEqual(['trusty'], getattr(self.lxd, 'image_' + method)(*args)) ms.assert_called_once_with('GET', '/1.0/images', *call_args) @annotated_data(*list_data) def test_list_images_fail(self, method, args, call_args, ms): ms.side_effect = exceptions.PyLXDException self.assertRaises(exceptions.PyLXDException, getattr(self.lxd, 'image_' + method), *args) ms.assert_called_once_with('GET', '/1.0/images', *call_args) @annotated_data( (True, (('200', fake_api.fake_image_info()), )), (False, exceptions.APIError("404", 404)), ) def test_image_defined(self, expected, side_effect, ms): ms.side_effect = side_effect self.assertEqual(expected, self.lxd.image_defined('test-image')) ms.assert_called_once_with('GET', '/1.0/images/test-image') @annotated_data( ('APIError', exceptions.APIError("500", 500), exceptions.APIError), ('PyLXDException', exceptions.PyLXDException, exceptions.PyLXDException)) def test_image_defined_fail(self, tag, side_effect, expected, ms): ms.side_effect = side_effect self.assertRaises(expected, self.lxd.image_defined, ('test-image', )) ms.assert_called_once_with('GET', '/1.0/images/test-image') def test_image_info(self, ms): self.assertEqual( { 'image_upload_date': (datetime.datetime.fromtimestamp( 1435669853).strftime('%Y-%m-%d %H:%M:%S')), 'image_created_date': 'Unknown', 'image_expires_date': 'Unknown', 'image_public': False, 'image_size': '63MB', 'image_fingerprint': '04aac4257341478b49c25d22cea8a6ce' '0489dc6c42d835367945e7596368a37f', 'image_architecture': 'x86_64', }, self.lxd.image_info('test-image')) ms.assert_called_once_with('GET', '/1.0/images/test-image') def test_image_info_fail(self, ms): ms.side_effect = exceptions.PyLXDException self.assertRaises(exceptions.PyLXDException, self.lxd.image_info, ('test-image', )) ms.assert_called_once_with('GET', '/1.0/images/test-image') dates_data = ( ('upload', (datetime.datetime.fromtimestamp(1435669853).strftime( '%Y-%m-%d %H:%M:%S'))), ('create', 'Unknown'), ('expire', 'Unknown'), ) @annotated_data(*dates_data) def test_image_date(self, method, expected, ms): self.assertEqual( expected, getattr(self.lxd, 'image_{}_date'.format(method))('test-image', data=None)) ms.assert_called_once_with('GET', '/1.0/images/test-image') @annotated_data(*dates_data) def test_image_date_fail(self, method, expected, ms): ms.side_effect = exceptions.PyLXDException self.assertRaises(exceptions.PyLXDException, getattr(self.lxd, 'image_{}_date'.format(method)), 'test-image', data=None) ms.assert_called_once_with('GET', '/1.0/images/test-image')
def test_profile_list_fail(self): self.ml.profile_list.side_effect = (lxd_exceptions.APIError( 'Fake', 500)) self.assertRaises(exception.NovaException, self.session.profile_list)
class LXDTestDriver(test.NoDBTestCase): @mock.patch.object(driver, 'CONF', stubs.MockConf()) def setUp(self): super(LXDTestDriver, self).setUp() self.ml = stubs.lxd_mock() lxd_patcher = mock.patch('pylxd.api.API', mock.Mock(return_value=self.ml)) lxd_patcher.start() self.addCleanup(lxd_patcher.stop) self.connection = driver.LXDDriver(fake.FakeVirtAPI()) def test_capabilities(self): self.assertFalse(self.connection.capabilities['has_imagecache']) self.assertFalse(self.connection.capabilities['supports_recreate']) self.assertFalse( self.connection.capabilities['supports_migrate_to_same_host']) self.assertTrue( self.connection.capabilities['supports_attach_interface']) def test_init_host(self): self.assertEqual(True, self.connection.init_host(None)) def test_init_host_new_profile(self): self.ml.profile_list.return_value = [] self.assertEqual(True, self.connection.init_host(None)) @stubs.annotated_data( ('no_ping', { 'host_ping.return_value': False }), ('ping_fail', { 'host_ping.side_effect': (lxd_exceptions.APIError('Fake', 500)) }), ) def test_init_host_fail(self, tag, config): self.ml.configure_mock(**config) self.assertRaises(exception.HostNotFound, self.connection.init_host, None) @stubs.annotated_data( ('running', { 'state': 200, 'mem': 0, 'max_mem': 0 }, power_state.RUNNING), ('shutdown', { 'state': 102, 'mem': 0, 'max_mem': 0 }, power_state.SHUTDOWN), ('crashed', { 'state': 108, 'mem': 0, 'max_mem': 0 }, power_state.CRASHED), ('suspend', { 'state': 109, 'mem': 0, 'max_mem': 0 }, power_state.SUSPENDED), ('no_state', { 'state': 401, 'mem': 0, 'max_mem': 0 }, power_state.NOSTATE), ) def test_get_info(self, tag, side_effect, expected): instance = stubs._fake_instance() with mock.patch.object( session.LXDAPISession, "container_state", ) as state: state.return_value = side_effect info = self.connection.get_info(instance) self.assertEqual( dir(hardware.InstanceInfo(state=expected, num_cpu=2)), dir(info)) @stubs.annotated_data( (True, 'mock-instance-1'), (False, 'fake-instance'), ) def test_instance_exists(self, expected, name): self.assertEqual( expected, self.connection.instance_exists(stubs.MockInstance(name=name))) def test_estimate_instance_overhead(self): self.assertEqual({'memory_mb': 0}, self.connection.estimate_instance_overhead( mock.Mock())) def test_list_instances(self): self.assertEqual(['mock-instance-1', 'mock-instance-2'], self.connection.list_instances()) def test_list_instances_fail(self): self.ml.container_list.side_effect = (lxd_exceptions.APIError( 'Fake', 500)) self.assertRaises(exception.NovaException, self.connection.list_instances) @stubs.annotated_data( ('exists', [True], exception.InstanceExists), ('fail', lxd_exceptions.APIError('Fake', 500), exception.NovaException) ) def test_spawn_defined(self, tag, side_effect, expected): instance = stubs.MockInstance() self.ml.container_defined.side_effect = side_effect self.assertRaises(expected, self.connection.spawn, {}, instance, {}, [], 'secret') self.ml.container_defined.called_once_with('mock_instance') @stubs.annotated_data( ('undefined', False), ('404', lxd_exceptions.APIError('Not found', 404)), ) @mock.patch('oslo_concurrency.lockutils.lock') def test_spawn_new(self, tag, side_effect, mc): context = mock.Mock() instance = stubs.MockInstance() image_meta = mock.Mock() injected_files = mock.Mock() network_info = mock.Mock() block_device_info = mock.Mock() self.ml.container_defined.side_effect = [side_effect] with test.nested( mock.patch.object(self.connection.container_ops, 'spawn'), ) as (create_container): self.connection.spawn(context, instance, image_meta, injected_files, None, network_info, block_device_info) self.assertTrue(create_container) def test_destroy_fail(self): instance = stubs._fake_instance() context = mock.Mock() network_info = mock.Mock() self.ml.container_destroy.side_effect = (lxd_exceptions.APIError( 'Fake', 500)) with test.nested( mock.patch.object(session.LXDAPISession, 'container_destroy'), mock.patch.object(session.LXDAPISession, 'container_stop'), mock.patch.object(self.connection, 'cleanup'), mock.patch.object(container_ops.LXDContainerOperations, 'unplug_vifs'), ) as (container_destroy, container_stop, cleanup, unplug_vifs): self.connection.destroy(context, instance, network_info) def test_destroy(self): instance = stubs._fake_instance() context = mock.Mock() network_info = mock.Mock() with test.nested( mock.patch.object(session.LXDAPISession, 'container_stop'), mock.patch.object(session.LXDAPISession, 'container_destroy'), mock.patch.object(self.connection, 'cleanup'), mock.patch.object(container_ops.LXDContainerOperations, 'unplug_vifs'), ) as (container_stop, container_destroy, cleanup, unplug_vifs): self.connection.destroy(context, instance, network_info) self.assertTrue(container_stop) self.assertTrue(container_destroy) self.assertTrue(cleanup) unplug_vifs.assert_called_with(instance, network_info) @mock.patch('os.path.exists', mock.Mock(return_value=True)) @mock.patch('shutil.rmtree') @mock.patch('pwd.getpwuid', mock.Mock(return_value=mock.Mock(pw_uid=1234))) @mock.patch.object(container_ops.utils, 'execute') def test_cleanup(self, mr, mu): instance = stubs.MockInstance() self.assertEqual( None, self.connection.cleanup({}, instance, [], [], None, None, None)) @mock.patch('six.moves.builtins.open') @mock.patch.object(container_ops.utils, 'execute') @mock.patch('pwd.getpwuid', mock.Mock(return_value=mock.Mock(pw_uid=1234))) @mock.patch('os.getuid', mock.Mock()) @mock.patch('os.path.exists', mock.Mock(return_value=True)) def test_get_console_output(self, me, mo): instance = stubs.MockInstance() mo.return_value.__enter__.return_value = six.BytesIO(b'fake contents') self.assertEqual(b'fake contents', self.connection.get_console_output({}, instance)) calls = [ mock.call('chown', '1234:1234', '/var/log/lxd/fake-uuid/console.log', run_as_root=True), mock.call('chmod', '755', '/fake/lxd/root/containers/fake-uuid', run_as_root=True) ] self.assertEqual(calls, me.call_args_list) @mock.patch.object(host.compute_utils, 'get_machine_ips') @stubs.annotated_data( ('found', ['1.2.3.4']), ('not-found', ['4.3.2.1']), ) def test_get_host_ip_addr(self, tag, return_value, mi): mi.return_value = return_value self.assertEqual('1.2.3.4', self.connection.get_host_ip_addr()) @mock.patch('socket.gethostname', mock.Mock(return_value='fake_hostname')) @mock.patch('os.statvfs', return_value=mock.Mock(f_blocks=131072000, f_bsize=8192, f_bavail=65536000)) @mock.patch('six.moves.builtins.open') @mock.patch.object(container_ops.utils, 'execute') def test_get_available_resource(self, me, mo, ms): me.return_value = ('Model name: Fake CPU\n' 'Vendor ID: FakeVendor\n' 'Socket(s): 10\n' 'Core(s) per socket: 5\n' 'Thread(s) per core: 4\n' '\n', None) meminfo = mock.MagicMock() meminfo.__enter__.return_value = six.moves.cStringIO( 'MemTotal: 10240000 kB\n' 'MemFree: 2000000 kB\n' 'Buffers: 24000 kB\n' 'Cached: 24000 kB\n') mo.side_effect = [ six.moves.cStringIO('flags: fake flag goes here\n' 'processor: 2\n' '\n'), meminfo, ] value = self.connection.get_available_resource(None) value['cpu_info'] = json.loads(value['cpu_info']) value['supported_instances'] = [ [arch.I686, hv_type.LXD, vm_mode.EXE], [arch.X86_64, hv_type.LXD, vm_mode.EXE], [arch.I686, hv_type.LXC, vm_mode.EXE], [arch.X86_64, hv_type.LXC, vm_mode.EXE] ] expected = { 'cpu_info': { u'arch': platform.uname()[5], u'features': u'fake flag goes here', u'model': u'Fake CPU', u'topology': { u'cores': u'5', u'sockets': u'10', u'threads': u'4' }, u'vendor': u'FakeVendor' }, 'hypervisor_hostname': 'fake_hostname', 'hypervisor_type': 'lxd', 'hypervisor_version': '011', 'local_gb': 1000, 'local_gb_used': 500, 'memory_mb': 10000, 'memory_mb_used': 8000, 'numa_topology': None, 'supported_instances': [[arch.I686, hv_type.LXD, vm_mode.EXE], [arch.X86_64, hv_type.LXD, vm_mode.EXE], [arch.I686, hv_type.LXC, vm_mode.EXE], [arch.X86_64, hv_type.LXC, vm_mode.EXE]], 'vcpus': 200, 'vcpus_used': 0 } self.assertEqual(expected, value) me.assert_called_once_with('lscpu') self.assertEqual( [mock.call('/proc/cpuinfo', 'r'), mock.call('/proc/meminfo')], mo.call_args_list) ms.assert_called_once_with('/fake/lxd/root') def test_container_reboot(self): instance = stubs._fake_instance() context = mock.Mock() network_info = mock.Mock() reboot_type = 'SOFT' with test.nested( mock.patch.object(self.connection.container_ops, 'reboot')) as (reboot): self.connection.reboot(context, instance, network_info, reboot_type) self.assertTrue(reboot) def test_container_power_off(self): instance = stubs._fake_instance() with test.nested( mock.patch.object(self.connection.container_ops, 'power_off')) as (power_off): self.connection.power_off(instance) self.assertTrue(power_off) def test_container_power_on(self): context = mock.Mock() instance = stubs._fake_instance() network_info = mock.Mock() with test.nested( mock.patch.object(self.connection.container_ops, 'power_on')) as (power_on): self.connection.power_on(context, instance, network_info) self.assertTrue(power_on) @stubs.annotated_data( ('refresh_security_group_rules', (mock.Mock(), )), ('refresh_security_group_members', (mock.Mock(), )), ('refresh_provider_fw_rules', ), ('refresh_instance_security_rules', (mock.Mock(), )), ('ensure_filtering_rules_for_instance', (mock.Mock(), mock.Mock())), ('filter_defer_apply_on', ), ('filter_defer_apply_off', ), ('unfilter_instance', (mock.Mock(), mock.Mock())), ) def test_firewall_calls(self, name, args=()): with mock.patch.object(self.connection.container_firewall, 'firewall_driver') as mf: driver_method = getattr(self.connection, name) firewall_method = getattr(mf, name) self.assertEqual(firewall_method.return_value, driver_method(*args)) firewall_method.assert_called_once_with(*args) @mock.patch.object(host.utils, 'execute') def test_get_host_uptime(self, me): me.return_value = ('out', 'err') self.assertEqual('out', self.connection.get_host_uptime()) @mock.patch('socket.gethostname', mock.Mock(return_value='mock_hostname')) def test_get_available_nodes(self): self.assertEqual(['mock_hostname'], self.connection.get_available_nodes()) @mock.patch('socket.gethostname', mock.Mock(return_value='mock_hostname')) @stubs.annotated_data( ('mock_hostname', True), ('wrong_hostname', False), ) def test_node_is_available(self, nodename, available): self.assertEqual(available, self.connection.node_is_available(nodename))
class SessionContainerTest(test.NoDBTestCase): def setUp(self): super(SessionContainerTest, self).setUp() """This is so we can mock out pylxd API calls.""" self.ml = stubs.lxd_mock() lxd_patcher = mock.patch('pylxd.api.API', mock.Mock(return_value=self.ml)) lxd_patcher.start() self.addCleanup(lxd_patcher.stop) self.session = session.LXDAPISession() @stubs.annotated_data( ('empty', [], []), ('valid', ['test'], ['test']), ) def test_container_list(self, tag, side_effect, expected): """ container_list returns a list of LXD containers found on an LXD host. """ self.ml.container_list.return_value = side_effect self.assertEqual(expected, self.session.container_list()) def test_container_list_fail(self): """ container_list returns an exception.NovaException, if pylxd raises an APIError. """ self.ml.container_list.side_effect = ( lxd_exceptions.APIError('Fake', 500)) self.assertRaises( exception.NovaException, self.session.container_list) def test_container_update(self): """ container_update updates the LXD container configuration, so verify that the correct pylxd calls are made. """ config = mock.Mock() instance = stubs._fake_instance() self.ml.container_update.return_value = \ (200, fake_api.fake_container_config()) self.assertEqual((200, fake_api.fake_container_config()), self.session.container_update(config, instance)) calls = [ mock.call.container_defined(instance.name), mock.call.container_update(instance.name, config)] self.assertEqual(calls, self.ml.method_calls) @stubs.annotated_data( ('api_fail', True, lxd_exceptions.APIError('Fake', 500), exception.NovaException), ('missing_container', False, None, exception.InstanceNotFound) ) def test_container_update_fail(self, tag, container_defined, side_effect, expected): """ container_update will fail if the container is not found, or the LXD raises an API error. Verify that the exceptions are raised in both scenarios. """ config = mock.Mock() instance = stubs._fake_instance() if container_defined: self.ml.container_defined.return_value = container_defined self.ml.container_update.side_effect = ( lxd_exceptions.APIError('Fake', 500)) self.assertRaises( expected, self.session.container_update, config, instance) if not container_defined: self.ml.container_defined.return_value = container_defined self.assertRaises( expected, self.session.container_update, config, instance) @stubs.annotated_data( ('running', True), ('idle', False), ('api_failure', lxd_exceptions.APIError('Fake', '500')), ) def test_container_running(self, tag, side_effect): """ container_running determines if the container is running or not. Verify that we are returning True if the container is running. False if its not, raise an exception if there is an API error. """ instance = stubs._fake_instance() if side_effect: self.ml.container_running.return_value = side_effect self.assertTrue(self.session.container_running(instance)) if not side_effect: self.ml.container_running.return_value = side_effect self.assertFalse(self.session.container_running(instance)) if tag == 'api_failure': self.ml.container_running.side_effect = side_effect self.assertRaises( exception.NovaException, self.session.container_running, instance ) def test_container_state(self): """ container_state translates LXD container status into what nova understands. Verify that status_code sends a power_state.RUNNING and a 108 sends a power_state.CRASHED. """ calls = [] self.assertEqual(calls, self.ml.method_calls) @stubs.annotated_data( ('api_fail', True, lxd_exceptions.APIError('Fake', 500), {'state': power_state.NOSTATE, 'mem': 0, 'max_mem': 0}) ) def test_container_state_fail(self, tag, container_defined, side_effect, expected): """ container_state translates LXD container status into what nova understands. If the API sends an APIError then raise an power_state.NOSTATE, same if the the container goes missing. """ instance = stubs._fake_instance() if container_defined: self.ml.container_defined.return_value = container_defined self.ml.container_state.side_effect = ( lxd_exceptions.APIError('Fake', 500)) self.assertEqual( expected, self.session.container_state(instance)) if not container_defined: self.ml.container_defined.return_value = container_defined self.assertEqual( expected, self.session.container_state(instance)) def test_container_config(self): """ container_config returns a dictionary representation of the LXD container. Verify that the funciton returns a container_config """ instance = stubs._fake_instance() self.ml.get_container_config.return_value = \ (200, fake_api.fake_container_config()) self.assertEqual( (200, fake_api.fake_container_config()), self.session.container_config(instance)) @stubs.annotated_data( ('api_fail', True, lxd_exceptions.APIError('Fake', 500), exception.NovaException), ) def test_container_config_fail(self, tag, container_defined, side_effect, expected): """ container_config returns a dictionary represeation of the LXD container. Verify that the function raises an exception.NovaException when there is a APIError. """ instance = stubs._fake_instance() if container_defined: self.ml.container_defined.return_value = container_defined self.ml.get_container_config.side_effect = side_effect self.assertRaises( expected, self.session.container_config, instance) def test_container_info(self): """ container_info returns a dictonary represenation of useful information about a container, (ip address, pid, etc). Verify that the function returns the approiate dictionary representation for the LXD API. """ instance = stubs._fake_instance() self.ml.container_info.return_value = \ (200, fake_api.fake_container_info()) self.assertEqual( (200, fake_api.fake_container_info()), self.session.container_info(instance)) def test_container_info_fail(self): """ container_info returns a dictionary reprsentation of userful information about a container (ip address, pid, etc). Verify that the container_info returns an exception.NovaException when there is an APIError. """ instance = stubs._fake_instance() self.ml.container_info.side_effect = ( lxd_exceptions.APIError('Fake', 500)) self.assertRaises( exception.NovaException, self.session.container_info, instance) @stubs.annotated_data( ('exists', True), ('missing', False), ) def test_container_defined(self, tag, side_effect): """ container_defined returns True if the container exists on an LXD host, False otherwise, verify the apporiate return value is returned. """ instance = stubs._fake_instance() self.ml.container_defined.return_value = side_effect if side_effect: self.assertTrue(self.session.container_defined( instance.name, instance)) if not side_effect: self.assertFalse(self.session.container_defined( instance.name, instance)) @stubs.annotated_data( ('1', True, (200, fake_api.fake_operation_info_ok())) ) def test_container_start(self, tag, defined, side_effect=None): """ containser_start starts a container on a given LXD host. Verify that the correct pyLXD calls are made. """ instance = stubs._fake_instance() self.ml.container_defined.return_value = defined self.ml.container_start.return_value = side_effect self.assertEqual(None, self.session.container_start(instance.name, instance)) calls = [mock.call.container_defined(instance.name), mock.call.container_start(instance.name, -1), mock.call.wait_container_operation( '/1.0/operation/1234', 200, -1)] self.assertEqual(calls, self.ml.method_calls) @stubs.annotated_data( ('container_missing', False, exception.InstanceNotFound), ('api_error', True, exception.NovaException, lxd_exceptions.APIError('Fake', 500)), ) def test_container_start_fail(self, tag, container_defined, expected, side_effect=None): """ container_start starts a container on a given LXD host. Veify that an exception.InstanceNotFound when the container is not found on an LXD host. Raises an exception.NovaException when there is an APIError. """ instance = stubs._fake_instance() if container_defined: self.ml.container_defined.return_value = container_defined self.ml.container_start.side_effect = side_effect self.assertRaises(expected, self.session.container_start, instance.name, instance) if not container_defined: self.ml.container_defined.return_value = container_defined self.assertRaises(expected, self.session.container_start, instance.name, instance) @stubs.annotated_data( ('1', (200, fake_api.fake_operation_info_ok())) ) def test_container_stop(self, tag, side_effect): """ container_stop stops a container on a given LXD ost. Verifty that that the apprioated pylxd calls are made to the LXD api. """ instance = stubs._fake_instance() self.ml.container_stop.return_value = side_effect self.assertEqual(None, self.session.container_stop(instance.name, instance)) calls = [mock.call.container_defined(instance.name), mock.call.container_stop(instance.name, -1), mock.call.wait_container_operation( '/1.0/operation/1234', 200, -1)] self.assertEqual(calls, self.ml.method_calls) @stubs.annotated_data( ('api_fail', lxd_exceptions.APIError('Fake', 500), exception.NovaException) ) def test_container_stop_fail(self, tag, side_effect, expected): """ contianer_stop stops a container on a given LXD host. Verifty that we raise an exception.NovaException when there is an APIError. """ instance = stubs._fake_instance() self.ml.container_stop.side_effect = side_effect self.assertRaises(expected, self.session.container_stop, instance.name, instance) @stubs.annotated_data( ('1,', (200, fake_api.fake_operation_info_ok())) ) def test_continer_reboot(self, tag, side_effect): """" container_reboot reboots a container on a given LXD host. Verify that the right pylxd calls are made to the LXD host. """ instance = stubs._fake_instance() self.ml.container_reboot.return_value = side_effect self.assertEqual(None, self.session.container_reboot(instance)) calls = [mock.call.container_defined(instance.name), mock.call.container_reboot(instance.name, -1), mock.call.wait_container_operation( '/1.0/operation/1234', 200, -1)] self.assertEqual(calls, self.ml.method_calls) @stubs.annotated_data( ('api_fail', lxd_exceptions.APIError('Fake', 500), exception.NovaException) ) def test_container_reboot_fail(self, tag, side_effect, expected): """ container_reboot reboots a container on a given LXD host. Check that an exception.NovaException is raised when there is an LXD API error. """ instance = stubs._fake_instance() self.ml.container_reboot.side_effect = side_effect self.assertRaises(expected, self.session.container_reboot, instance) @stubs.annotated_data( ('exists', True, (200, fake_api.fake_operation_info_ok())), ('missing', False, (200, fake_api.fake_operation_info_ok())) ) def test_container_destroy(self, tag, container_defined, side_effect): """ container_destroy delete a container from the LXD Host. Check that the approiate pylxd calls are made. """ instance = stubs._fake_instance() if container_defined: self.ml.container_defined.return_value = container_defined self.ml.container_stop.return_value = side_effect self.ml.container_destroy.return_value = side_effect self.assertEqual(None, self.session.container_destroy(instance.name, instance)) calls = [mock.call.container_defined(instance.name), mock.call.container_defined(instance.name), mock.call.container_stop(instance.name, -1), mock.call.wait_container_operation( '/1.0/operation/1234', 200, -1), mock.call.container_destroy(instance.name), mock.call.wait_container_operation( '/1.0/operation/1234', 200, -1)] self.assertEqual(calls, self.ml.method_calls) if not container_defined: self.ml.container_defined.return_value = container_defined self.assertEqual(None, self.session.container_destroy(instance.name, instance)) calls = [mock.call.container_defined(instance.name)] self.assertEqual(calls, self.ml.method_calls) @stubs.annotated_data( ('fail_to_stop', True, 'fail_stop', lxd_exceptions.APIError('Fake', '500'), exception.NovaException), ('fail_to_destroy', True, 'fail_destroy', lxd_exceptions.APIError('Fake', '500'), exception.NovaException) ) def test_container_destroy_fail(self, tag, container_defined, test_type, side_effect, expected): """ container_destroy deletes a container on the LXD host. Check whether an exeption.NovaException is raised when there is an APIError or when the container fails to stop. """ instance = stubs._fake_instance() self.ml.cotnainer_defined.return_value = container_defined if test_type == 'fail_stop': self.ml.container_stop.side_effect = side_effect self.assertRaises(expected, self.session.container_destroy, instance.name, instance) if test_type == 'fail_destroy': self.ml.container_defined.return_value = container_defined self.ml.container_stop.return_value = \ (200, fake_api.fake_operation_info_ok()) self.ml.container_destroy.side_effect = side_effect self.assertRaises(expected, self.session.container_destroy, instance.name, instance) @stubs.annotated_data( ('1', (200, fake_api.fake_operation_info_ok())) ) def fake_container_pause(self, tag, side_effect): """ container_pause pauses a container on a given LXD host. Verify that the appropiate pylxd API calls are made. """ instance = stubs._fake_instance() self.ml.container_suspend.return_value = side_effect self.assertEqual(None, self.session.container_pause(instance.name, instance)) calls = [ mock.call.container_susepnd(instance.name, -1), mock.call.wait_container_operation( '/1.0/operation/1234', 200, -1)] self.assertEqual(calls, self.ml.method_calls) @stubs.annotated_data( ('api_fail', lxd_exceptions.APIError(500, 'Fake'), exception.NovaException) ) def test_container_pause_fail(self, tag, side_effect, expected): """ container_pause pauses a contianer on a LXD host. Verify that an exception.NovaException is raised when there is an APIError. """ instance = stubs._fake_instance() instance = stubs._fake_instance() self.ml.container_suspend.side_effect = side_effect self.assertRaises(expected, self.session.container_pause, instance.name, instance) @stubs.annotated_data( ('1', (200, fake_api.fake_operation_info_ok())) ) def test_container_unpause(self, tag, side_effect): """ container_unpase unpauses a continer on a LXD host. Check that the right pylxd calls are being sent to the LXD API server. """ instance = stubs._fake_instance() self.ml.container_resume.return_value = side_effect self.assertEqual(None, self.session.container_unpause(instance.name, instance)) calls = [ mock.call.container_defined(instance.name), mock.call.container_resume(instance.name, -1), mock.call.wait_container_operation( '/1.0/operation/1234', 200, -1)] self.assertEqual(calls, self.ml.method_calls) @stubs.annotated_data( ('api_fail', lxd_exceptions.APIError(500, 'Fake'), exception.NovaException) ) def test_container_unpause_fail(self, tag, side_effect, expected): """ container_unpause resumes a previously suespended container. Validate that an exception.NovaException is raised when a APIError is sent by the API. """ instance = stubs._fake_instance() self.ml.container_resume.side_effect = side_effect self.assertRaises(expected, self.session.container_unpause, instance.name, instance) @stubs.annotated_data( ('1', (200, fake_api.fake_operation_info_ok())) ) def test_container_init(self, tag, side_effect): """ conatainer_init creates a container based on given config for a container. Check to see if we are returning the right pylxd calls for the LXD API. """ config = mock.Mock() instance = stubs._fake_instance() self.ml.container_init.return_value = side_effect self.ml.operation_info.return_value = \ (200, fake_api.fake_container_state(200)) self.assertEqual(None, self.session.container_init(config, instance)) calls = [mock.call.container_init(config), mock.call.wait_container_operation( '/1.0/operation/1234', 200, -1), mock.call.operation_info('/1.0/operation/1234')] self.assertEqual(calls, self.ml.method_calls) @stubs.annotated_data( ('api_fail', lxd_exceptions.APIError(500, 'Fake'), exception.NovaException), ) def test_container_init_fail(self, tag, side_effect, expected): """ continer_init create as container on a given LXD host. Make sure that we reaise an exception.NovaException if there is an APIError from the LXD API. """ config = mock.Mock() instance = stubs._fake_instance() self.ml.container_init.side_effect = side_effect self.assertRaises(expected, self.session.container_init, config, instance)
class LXDAPIImageTestObject(LXDAPITestBase): list_data = ( ("list", (), ()), ("search", ({ "foo": "bar" }, ), ("foo=bar", )), ) @annotated_data(*list_data) def test_list_images(self, method, args, call_args, ms): ms.return_value = ("200", fake_api.fake_image_list()) self.assertEqual(["trusty"], getattr(self.lxd, "image_" + method)(*args)) ms.assert_called_once_with("GET", "/1.0/images", *call_args) @annotated_data(*list_data) def test_list_images_fail(self, method, args, call_args, ms): ms.side_effect = exceptions.PyLXDException self.assertRaises(exceptions.PyLXDException, getattr(self.lxd, "image_" + method), *args) ms.assert_called_once_with("GET", "/1.0/images", *call_args) @annotated_data( (True, (("200", fake_api.fake_image_info()), )), (False, exceptions.APIError("404", 404)), ) def test_image_defined(self, expected, side_effect, ms): ms.side_effect = side_effect self.assertEqual(expected, self.lxd.image_defined("test-image")) ms.assert_called_once_with("GET", "/1.0/images/test-image") @annotated_data( ("APIError", exceptions.APIError("500", 500), exceptions.APIError), ("PyLXDException", exceptions.PyLXDException, exceptions.PyLXDException), ) def test_image_defined_fail(self, tag, side_effect, expected, ms): ms.side_effect = side_effect self.assertRaises(expected, self.lxd.image_defined, ("test-image", )) ms.assert_called_once_with("GET", "/1.0/images/test-image") def test_image_info(self, ms): self.assertEqual( { "image_upload_date": (datetime.datetime.fromtimestamp( 1435669853).strftime("%Y-%m-%d %H:%M:%S")), "image_created_date": "Unknown", "image_expires_date": "Unknown", "image_public": False, "image_size": "63MB", "image_fingerprint": "04aac4257341478b49c25d22cea8a6ce" "0489dc6c42d835367945e7596368a37f", "image_architecture": "x86_64", }, self.lxd.image_info("test-image"), ) ms.assert_called_once_with("GET", "/1.0/images/test-image") def test_image_info_fail(self, ms): ms.side_effect = exceptions.PyLXDException self.assertRaises(exceptions.PyLXDException, self.lxd.image_info, ("test-image", )) ms.assert_called_once_with("GET", "/1.0/images/test-image") dates_data = ( ( "upload", (datetime.datetime.fromtimestamp(1435669853).strftime( "%Y-%m-%d %H:%M:%S")), ), ("create", "Unknown"), ("expire", "Unknown"), ) @annotated_data(*dates_data) def test_image_date(self, method, expected, ms): self.assertEqual( expected, getattr(self.lxd, "image_{}_date".format(method))("test-image", data=None), ) ms.assert_called_once_with("GET", "/1.0/images/test-image") @annotated_data(*dates_data) def test_image_date_fail(self, method, expected, ms): ms.side_effect = exceptions.PyLXDException self.assertRaises( exceptions.PyLXDException, getattr(self.lxd, "image_{}_date".format(method)), "test-image", data=None, ) ms.assert_called_once_with("GET", "/1.0/images/test-image")