def test_to_profile_lvm(self): """A profile configuration is requested of the LXD client.""" self.client.host_info['environment']['storage'] = 'lvm' ctx = context.get_admin_context() instance = fake_instance.fake_instance_obj(ctx, name='test', memory_mb=0) network_info = [] block_info = [] expected_config = { 'environment.product_name': 'OpenStack Nova', 'limits.cpu': '1', 'limits.memory': '0MB', 'raw.lxc': ('lxc.console.logfile=/var/log/lxd/{}/console.log\n'.format( instance.name)), } expected_devices = { 'root': { 'path': '/', 'type': 'disk' }, } flavor.to_profile(self.client, instance, network_info, block_info) self.client.profiles.create.assert_called_once_with( instance.name, expected_config, expected_devices)
def test_storage_pools(self): self.client.host_info['api_extensions'].append('storage') self.CONF2.lxd.pool = 'test_pool' ctx = context.get_admin_context() instance = fake_instance.fake_instance_obj(ctx, name='test', memory_mb=0) network_info = [] block_info = [] expected_config = { 'environment.product_name': 'OpenStack Nova', 'limits.cpu': '1', 'limits.memory': '0MB', 'raw.lxc': ('lxc.console.logfile=/var/log/lxd/{}/console.log\n'.format( instance.name)) } expected_devices = { 'root': { 'path': '/', 'type': 'disk', 'pool': 'test_pool', 'size': '0GB' }, } flavor.to_profile(self.client, instance, network_info, block_info) self.client.profiles.create.assert_called_once_with( instance.name, expected_config, expected_devices)
def finish_migration(self, context, migration, instance, disk_info, network_info, image_meta, resize_instance, block_device_info=None, power_on=True): # Ensure that the instance directory exists instance_dir = common.InstanceAttributes(instance).instance_dir if not os.path.exists(instance_dir): fileutils.ensure_tree(instance_dir) # Step 1 - Setup the profile on the dest host flavor.to_profile(self.client, instance, network_info, block_device_info) # Step 2 - Open a websocket on the srct and and # generate the container config self._migrate(migration['source_compute'], instance) # Step 3 - Start the network and container self.plug_vifs(instance, network_info) self.client.container.get(instance.name).start(wait=True)
def test_to_profile_quota_extra_specs_max_iops(self): """A profile configuration is requested of the LXD client.""" ctx = context.get_admin_context() instance = fake_instance.fake_instance_obj( ctx, name='test', memory_mb=0) instance.flavor.extra_specs = { 'quota:disk_total_iops_sec': '500', } network_info = [] block_info = [] expected_config = { 'environment.product_name': 'OpenStack Nova', 'limits.cpu': '1', 'limits.memory': '0MB', 'raw.lxc': ( 'lxc.console.logfile=/var/log/lxd/{}/console.log\n'.format( instance.name)), } expected_devices = { 'root': { 'limits.max': '500iops', 'path': '/', 'size': '0GB', 'type': 'disk' }, } flavor.to_profile(self.client, instance, network_info, block_info) self.client.profiles.create.assert_called_once_with( instance.name, expected_config, expected_devices)
def test_to_profile_idmap(self): self.client.host_info['api_extensions'].append('id_map') ctx = context.get_admin_context() instance = fake_instance.fake_instance_obj( ctx, name='test', memory_mb=0) instance.flavor.extra_specs = { 'lxd:isolated': True, } network_info = [] block_info = [] expected_config = { 'environment.product_name': 'OpenStack Nova', 'security.idmap.isolated': 'True', 'limits.cpu': '1', 'limits.memory': '0MB', 'raw.lxc': ( 'lxc.console.logfile=/var/log/lxd/{}/console.log\n'.format( instance.name)), } expected_devices = { 'root': { 'path': '/', 'size': '0GB', 'type': 'disk' }, } flavor.to_profile(self.client, instance, network_info, block_info) self.client.profiles.create.assert_called_once_with( instance.name, expected_config, expected_devices)
def pre_live_migration(self, context, instance, block_device_info, network_info, disk_info, migrate_data=None): for vif in network_info: self.vif_driver.plug(instance, vif) self.firewall_driver.setup_basic_filtering( instance, network_info) self.firewall_driver.prepare_instance_filter( instance, network_info) self.firewall_driver.apply_instance_filter( instance, network_info) flavor.to_profile(instance, network_info, block_device_info)
def migrate_disk_and_power_off( self, context, instance, dest, _flavor, network_info, block_device_info=None, timeout=0, retry_interval=0): if CONF.my_ip == dest: # Make sure that the profile for the container is up-to-date to # the actual state of the container. flavor.to_profile( self.client, instance, network_info, block_device_info, update=True) container = self.client.containers.get(instance.name) container.stop(wait=True) return ''
def test_to_profile_network_config_peak(self): ctx = context.get_admin_context() instance = fake_instance.fake_instance_obj(ctx, name='test', memory_mb=0) instance.flavor.extra_specs = { 'quota:vif_inbound_peak': '3000000', 'quota:vif_outbound_peak': '4000000', } network_info = [{ 'id': '0123456789abcdef', 'type': network_model.VIF_TYPE_OVS, 'address': '00:11:22:33:44:55', 'network': { 'bridge': 'fakebr' } }] block_info = [] expected_config = { 'environment.product_name': 'OpenStack Nova', 'limits.cpu': '1', 'limits.memory': '0MB', 'raw.lxc': ('lxc.console.logfile=/var/log/lxd/{}/console.log\n'.format( instance.name)), } expected_devices = { 'qbr0123456789a': { 'host_name': 'nic0123456789a', 'hwaddr': '00:11:22:33:44:55', 'nictype': 'bridged', 'parent': 'qbr0123456789a', 'type': 'nic', 'limits.egress': '32000Mbit', 'limits.ingress': '24000Mbit', }, 'root': { 'path': '/', 'size': '0GB', 'type': 'disk' }, } flavor.to_profile(self.client, instance, network_info, block_info) self.client.profiles.create.assert_called_once_with( instance.name, expected_config, expected_devices)
def test_to_profile_ephemeral_storage(self, get_ephemerals): """A profile configuration is requested of the LXD client.""" get_ephemerals.return_value = [ { 'virtual_name': 'ephemeral1' }, ] ctx = context.get_admin_context() instance = fake_instance.fake_instance_obj(ctx, name='test', memory_mb=0) network_info = [] block_info = [] expected_config = { 'environment.product_name': 'OpenStack Nova', 'limits.cpu': '1', 'limits.memory': '0MB', 'raw.lxc': ('lxc.console.logfile=/var/log/lxd/{}/console.log\n'.format( instance.name)), } expected_devices = { 'root': { 'path': '/', 'size': '0GB', 'type': 'disk' }, 'ephemeral1': { 'type': 'disk', 'path': '/mnt', 'source': '/i/{}/storage/ephemeral1'.format(instance.name), }, } flavor.to_profile(self.client, instance, network_info, block_info) self.client.profiles.create.assert_called_once_with( instance.name, expected_config, expected_devices)
def spawn(self, context, instance, image_meta, injected_files, admin_password, network_info=None, block_device_info=None): """Create a new lxd container as a nova instance. Creating a new container requires a number of steps. First, the image is fetched from glance, if needed. Next, the network is connected. A profile is created in LXD, and then the container is created and started. See `nova.virt.driver.ComputeDriver.spawn` for more information. """ try: self.client.containers.get(instance.name) raise exception.InstanceExists(name=instance.name) except lxd_exceptions.LXDAPIException as e: if e.response.status_code != 404: raise # Re-raise the exception if it wasn't NotFound instance_dir = common.InstanceAttributes(instance).instance_dir if not os.path.exists(instance_dir): fileutils.ensure_tree(instance_dir) # Check to see if LXD already has a copy of the image. If not, # fetch it. try: self.client.images.get_by_alias(instance.image_ref) except lxd_exceptions.LXDAPIException as e: if e.response.status_code != 404: raise _sync_glance_image_to_lxd( self.client, context, instance.image_ref) # Plug in the network if network_info: timeout = CONF.vif_plugging_timeout if (utils.is_neutron() and timeout): events = [('network-vif-plugged', vif['id']) for vif in network_info if not vif.get( 'active', True)] else: events = [] try: with self.virtapi.wait_for_instance_event( instance, events, deadline=timeout, error_callback=_neutron_failed_callback): self.plug_vifs(instance, network_info) except eventlet.timeout.Timeout: LOG.warn('Timeout waiting for vif plugging callback for ' 'instance %(uuid)s', {'uuid': instance['name']}) if CONF.vif_plugging_is_fatal: self.destroy( context, instance, network_info, block_device_info) raise exception.InstanceDeployFailure( 'Timeout waiting for vif plugging', instance_id=instance['name']) # Create the profile try: profile = flavor.to_profile( self.client, instance, network_info, block_device_info) except lxd_exceptions.LXDAPIException as e: with excutils.save_and_reraise_exception(): self.cleanup( context, instance, network_info, block_device_info) # Create the container container_config = { 'name': instance.name, 'profiles': [profile.name], 'source': { 'type': 'image', 'alias': instance.image_ref, }, } try: container = self.client.containers.create( container_config, wait=True) except lxd_exceptions.LXDAPIException as e: with excutils.save_and_reraise_exception(): self.cleanup( context, instance, network_info, block_device_info) lxd_config = self.client.host_info storage.attach_ephemeral( self.client, block_device_info, lxd_config, instance) if configdrive.required_by(instance): configdrive_path = self._add_configdrive( context, instance, injected_files, admin_password, network_info) profile = self.client.profiles.get(instance.name) config_drive = { 'configdrive': { 'path': '/config-drive', 'source': configdrive_path, 'type': 'disk', 'readonly': 'True', } } profile.devices.update(config_drive) profile.save() try: self.firewall_driver.setup_basic_filtering( instance, network_info) self.firewall_driver.instance_filter( instance, network_info) container.start(wait=True) self.firewall_driver.apply_instance_filter( instance, network_info) except lxd_exceptions.LXDAPIException as e: with excutils.save_and_reraise_exception(): self.cleanup( context, instance, network_info, block_device_info)