components/openstack/nova/files/solariszones/driver.py
branchs11u3-sru
changeset 5410 2fe121cb8570
parent 5409 2c588e2f06d9
child 5411 27ae522d32d7
equal deleted inserted replaced
5409:2c588e2f06d9 5410:2fe121cb8570
   681                                   attached to the instance.
   681                                   attached to the instance.
   682         :param preserve_ephemeral: True if the default ephemeral storage
   682         :param preserve_ephemeral: True if the default ephemeral storage
   683                                    partition must be preserved on rebuild
   683                                    partition must be preserved on rebuild
   684         """
   684         """
   685         raise NotImplementedError()
   685         raise NotImplementedError()
       
   686 
       
   687     def _get_extra_specs(self, instance):
       
   688         """Retrieve extra_specs of an instance."""
       
   689         flavor = flavor_obj.Flavor.get_by_id(
       
   690             nova_context.get_admin_context(read_deleted='yes'),
       
   691             instance['instance_type_id'])
       
   692         return flavor['extra_specs'].copy()
   686 
   693 
   687     def _fetch_image(self, context, instance):
   694     def _fetch_image(self, context, instance):
   688         """Fetch an image using Glance given the instance's image_ref."""
   695         """Fetch an image using Glance given the instance's image_ref."""
   689         glancecache_dirname = CONF.glancecache_dirname
   696         glancecache_dirname = CONF.glancecache_dirname
   690         fileutils.ensure_tree(glancecache_dirname)
   697         fileutils.ensure_tree(glancecache_dirname)
   877         except Exception as reason:
   884         except Exception as reason:
   878             LOG.error(_("Unable to create root zpool volume for instance '%s'"
   885             LOG.error(_("Unable to create root zpool volume for instance '%s'"
   879                         ": %s") % (instance['name'], reason))
   886                         ": %s") % (instance['name'], reason))
   880             raise
   887             raise
   881 
   888 
   882     def _connect_boot_volume(self, volume, mountpoint, context, instance,
   889     def _connect_boot_volume(self, volume, mountpoint, context, instance):
   883                              extra_specs):
       
   884         """Connect a (Cinder) volume service backed boot volume"""
   890         """Connect a (Cinder) volume service backed boot volume"""
   885         brand = extra_specs.get('zonecfg:brand', ZONE_BRAND_SOLARIS)
       
   886         instance_uuid = instance['uuid']
   891         instance_uuid = instance['uuid']
   887         volume_id = volume['id']
   892         volume_id = volume['id']
   888 
   893 
   889         connector = self.get_volume_connector(instance)
   894         connector = self.get_volume_connector(instance)
   890         connection_info = self._volume_api.initialize_connection(
   895         connection_info = self._volume_api.initialize_connection(
   892 
   897 
   893         # Check connection_info to determine if the provided volume is
   898         # Check connection_info to determine if the provided volume is
   894         # local to this compute node. If it is, then don't use it for
   899         # local to this compute node. If it is, then don't use it for
   895         # Solaris branded zones in order to avoid a known ZFS deadlock issue
   900         # Solaris branded zones in order to avoid a known ZFS deadlock issue
   896         # when using a zpool within another zpool on the same system.
   901         # when using a zpool within another zpool on the same system.
       
   902         extra_specs = self._get_extra_specs(instance)
       
   903         brand = extra_specs.get('zonecfg:brand', ZONE_BRAND_SOLARIS)
   897         if brand == ZONE_BRAND_SOLARIS:
   904         if brand == ZONE_BRAND_SOLARIS:
   898             driver_type = connection_info['driver_volume_type']
   905             driver_type = connection_info['driver_volume_type']
   899             if driver_type == 'local':
   906             if driver_type == 'local':
   900                 msg = _("Detected 'local' zvol driver volume type "
   907                 msg = _("Detected 'local' zvol driver volume type "
   901                         "from volume service, which should not be "
   908                         "from volume service, which should not be "
  1125         if hostname_needed and name is not None:
  1132         if hostname_needed and name is not None:
  1126             fp = os.path.join(sc_dir, 'hostname.xml')
  1133             fp = os.path.join(sc_dir, 'hostname.xml')
  1127             sysconfig.create_sc_profile(fp, sysconfig.create_hostname(name))
  1134             sysconfig.create_sc_profile(fp, sysconfig.create_hostname(name))
  1128 
  1135 
  1129     def _create_config(self, context, instance, network_info,
  1136     def _create_config(self, context, instance, network_info,
  1130                        connection_info, extra_specs, sc_dir):
  1137                        connection_info, sc_dir):
  1131         """Create a new Solaris Zone configuration."""
  1138         """Create a new Solaris Zone configuration."""
  1132         name = instance['name']
  1139         name = instance['name']
  1133         if self._get_zone_by_name(name) is not None:
  1140         if self._get_zone_by_name(name) is not None:
  1134             raise exception.InstanceExists(name=name)
  1141             raise exception.InstanceExists(name=name)
       
  1142 
       
  1143         extra_specs = self._get_extra_specs(instance)
  1135 
  1144 
  1136         # If unspecified, default zone brand is ZONE_BRAND_SOLARIS
  1145         # If unspecified, default zone brand is ZONE_BRAND_SOLARIS
  1137         brand = extra_specs.get('zonecfg:brand', ZONE_BRAND_SOLARIS)
  1146         brand = extra_specs.get('zonecfg:brand', ZONE_BRAND_SOLARIS)
  1138         template = ZONE_BRAND_TEMPLATE.get(brand)
  1147         template = ZONE_BRAND_TEMPLATE.get(brand)
  1139         # TODO(dcomay): Detect capability via libv12n(3LIB) or virtinfo(1M).
  1148         # TODO(dcomay): Detect capability via libv12n(3LIB) or virtinfo(1M).
  1333                           console_fmri)
  1342                           console_fmri)
  1334             return True
  1343             return True
  1335         except processutils.ProcessExecutionError as err:
  1344         except processutils.ProcessExecutionError as err:
  1336             return False
  1345             return False
  1337 
  1346 
  1338     def _install(self, instance, image, extra_specs, sc_dir):
  1347     def _install(self, instance, image, sc_dir):
  1339         """Install a new Solaris Zone root file system."""
  1348         """Install a new Solaris Zone root file system."""
  1340         name = instance['name']
  1349         name = instance['name']
  1341         zone = self._get_zone_by_name(name)
  1350         zone = self._get_zone_by_name(name)
  1342         if zone is None:
  1351         if zone is None:
  1343             raise exception.InstanceNotFound(instance_id=name)
  1352             raise exception.InstanceNotFound(instance_id=name)
  1438         :param network_info:
  1447         :param network_info:
  1439            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
  1448            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
  1440         :param block_device_info: Information about block devices to be
  1449         :param block_device_info: Information about block devices to be
  1441                                   attached to the instance.
  1450                                   attached to the instance.
  1442         """
  1451         """
  1443         inst_type = flavor_obj.Flavor.get_by_id(
       
  1444             nova_context.get_admin_context(read_deleted='yes'),
       
  1445             instance['instance_type_id'])
       
  1446         extra_specs = inst_type['extra_specs'].copy()
       
  1447 
       
  1448         image = self._fetch_image(context, instance)
  1452         image = self._fetch_image(context, instance)
  1449         self._validate_image(image, instance)
  1453         self._validate_image(image, instance)
  1450 
  1454 
  1451         # create a new directory for SC profiles
  1455         # create a new directory for SC profiles
  1452         sc_dir = tempfile.mkdtemp(prefix="nova-sysconfig-",
  1456         sc_dir = tempfile.mkdtemp(prefix="nova-sysconfig-",
  1459         # c1d0 is the standard dev for for default boot device.
  1463         # c1d0 is the standard dev for for default boot device.
  1460         # Irrelevant value for ZFS, but Cinder gets stroppy without it.
  1464         # Irrelevant value for ZFS, but Cinder gets stroppy without it.
  1461         mountpoint = "c1d0"
  1465         mountpoint = "c1d0"
  1462         try:
  1466         try:
  1463             connection_info = self._connect_boot_volume(volume, mountpoint,
  1467             connection_info = self._connect_boot_volume(volume, mountpoint,
  1464                                                         context, instance,
  1468                                                         context, instance)
  1465                                                         extra_specs)
       
  1466         except exception.InvalidVolume as badvol:
  1469         except exception.InvalidVolume as badvol:
  1467             # This Cinder volume is not usable for ZOSS so discard it.
  1470             # This Cinder volume is not usable for ZOSS so discard it.
  1468             # zonecfg will apply default zonepath dataset configuration
  1471             # zonecfg will apply default zonepath dataset configuration
  1469             # instead. Carry on
  1472             # instead. Carry on
  1470             LOG.warning(_("Volume '%s' is being discarded: %s")
  1473             LOG.warning(_("Volume '%s' is being discarded: %s")
  1481         name = instance['name']
  1484         name = instance['name']
  1482 
  1485 
  1483         LOG.debug(_("creating zone configuration for '%s' (%s)") %
  1486         LOG.debug(_("creating zone configuration for '%s' (%s)") %
  1484                   (name, instance['display_name']))
  1487                   (name, instance['display_name']))
  1485         self._create_config(context, instance, network_info,
  1488         self._create_config(context, instance, network_info,
  1486                             connection_info, extra_specs, sc_dir)
  1489                             connection_info, sc_dir)
  1487         try:
  1490         try:
  1488             self._install(instance, image, extra_specs, sc_dir)
  1491             self._install(instance, image, sc_dir)
  1489             self._power_on(instance)
  1492             self._power_on(instance)
  1490         except Exception as reason:
  1493         except Exception as reason:
  1491             LOG.error(_("Unable to spawn instance '%s' via zonemgr(3RAD): %s")
  1494             LOG.error(_("Unable to spawn instance '%s' via zonemgr(3RAD): %s")
  1492                       % (name, reason))
  1495                       % (name, reason))
  1493             self._uninstall(instance)
  1496             self._uninstall(instance)
  1840 
  1843 
  1841     def attach_volume(self, context, connection_info, instance, mountpoint,
  1844     def attach_volume(self, context, connection_info, instance, mountpoint,
  1842                       disk_bus=None, device_type=None, encryption=None):
  1845                       disk_bus=None, device_type=None, encryption=None):
  1843         """Attach the disk to the instance at mountpoint using info."""
  1846         """Attach the disk to the instance at mountpoint using info."""
  1844         # TODO(npower): Apply mountpoint in a meaningful way to the zone
  1847         # TODO(npower): Apply mountpoint in a meaningful way to the zone
  1845         # (I don't think this is even possible for Solaris brand zones)
  1848         # For security reasons this is not permitted in a Solaris branded zone.
  1846         name = instance['name']
  1849         name = instance['name']
  1847         zone = self._get_zone_by_name(name)
  1850         zone = self._get_zone_by_name(name)
  1848         if zone is None:
  1851         if zone is None:
  1849             raise exception.InstanceNotFound(instance_id=name)
  1852             raise exception.InstanceNotFound(instance_id=name)
  1850 
  1853 
  1851         zprop = lookup_resource_property_value(zone, "global", "brand",
  1854         extra_specs = self._get_extra_specs(instance)
  1852                                                ZONE_BRAND_SOLARIS_KZ)
  1855         brand = extra_specs.get('zonecfg:brand', ZONE_BRAND_SOLARIS)
  1853         if not zprop:
  1856         if brand != ZONE_BRAND_SOLARIS_KZ:
  1854             # Only Solaris Kernel zones are currently supported.
  1857             # Only Solaris kernel zones are currently supported.
  1855             raise NotImplementedError()
  1858             reason = (_("'%s' branded zones are not currently supported")
       
  1859                       % brand)
       
  1860             raise NotImplementedError(reason)
  1856 
  1861 
  1857         suri = self._suri_from_volume_info(connection_info)
  1862         suri = self._suri_from_volume_info(connection_info)
  1858 
  1863 
  1859         with ZoneConfig(zone) as zc:
  1864         with ZoneConfig(zone) as zc:
  1860             zc.addresource("device", [zonemgr.Property("storage", suri)])
  1865             zc.addresource("device", [zonemgr.Property("storage", suri)])
  1865         name = instance['name']
  1870         name = instance['name']
  1866         zone = self._get_zone_by_name(name)
  1871         zone = self._get_zone_by_name(name)
  1867         if zone is None:
  1872         if zone is None:
  1868             raise exception.InstanceNotFound(instance_id=name)
  1873             raise exception.InstanceNotFound(instance_id=name)
  1869 
  1874 
  1870         zprop = lookup_resource_property_value(zone, "global", "brand",
  1875         extra_specs = self._get_extra_specs(instance)
  1871                                                ZONE_BRAND_SOLARIS_KZ)
  1876         brand = extra_specs.get('zonecfg:brand', ZONE_BRAND_SOLARIS)
  1872         if not zprop:
  1877         if brand != ZONE_BRAND_SOLARIS_KZ:
  1873             # Only Solaris Kernel zones are currently supported.
  1878             # Only Solaris kernel zones are currently supported.
  1874             raise NotImplementedError()
  1879             reason = (_("'%s' branded zones are not currently supported")
       
  1880                       % brand)
       
  1881             raise NotImplementedError(reason)
  1875 
  1882 
  1876         suri = self._suri_from_volume_info(connection_info)
  1883         suri = self._suri_from_volume_info(connection_info)
  1877 
  1884 
  1878         # Check if the specific property value exists before attempting removal
  1885         # Check if the specific property value exists before attempting removal
  1879         prop = lookup_resource_property_value(zone, "device", "storage", suri)
  1886         prop = lookup_resource_property_value(zone, "device", "storage", suri)