components/openstack/nova/files/solariszones/driver.py
branchs11-update
changeset 4072 db0cec748ec0
parent 3809 eb8d6ce0657e
child 4569 e6bd6f2f307f
equal deleted inserted replaced
4067:4be1f488dda8 4072:db0cec748ec0
     1 # vim: tabstop=4 shiftwidth=4 softtabstop=4
       
     2 
       
     3 # Copyright 2011 Justin Santa Barbara
     1 # Copyright 2011 Justin Santa Barbara
     4 # All Rights Reserved.
     2 # All Rights Reserved.
     5 #
     3 #
     6 # Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
     4 # Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
     7 #
     5 #
     8 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
     6 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
     9 #    not use this file except in compliance with the License. You may obtain
     7 #    not use this file except in compliance with the License. You may obtain
    10 #    a copy of the License at
     8 #    a copy of the License at
    11 #
     9 #
    43 from oslo.config import cfg
    41 from oslo.config import cfg
    44 
    42 
    45 from nova.compute import power_state
    43 from nova.compute import power_state
    46 from nova.compute import task_states
    44 from nova.compute import task_states
    47 from nova.compute import vm_states
    45 from nova.compute import vm_states
       
    46 from nova.console import type as ctype
    48 from nova import conductor
    47 from nova import conductor
    49 from nova import context as nova_context
    48 from nova import context as nova_context
    50 from nova import exception
    49 from nova import exception
       
    50 from nova.i18n import _
    51 from nova.image import glance
    51 from nova.image import glance
    52 from nova.network import neutronv2
    52 from nova.network import neutronv2
       
    53 from nova.objects import flavor as flavor_obj
    53 from nova.openstack.common import fileutils
    54 from nova.openstack.common import fileutils
    54 from nova.openstack.common.gettextutils import _
       
    55 from nova.openstack.common import jsonutils
    55 from nova.openstack.common import jsonutils
    56 from nova.openstack.common import log as logging
    56 from nova.openstack.common import log as logging
    57 from nova.openstack.common import loopingcall
    57 from nova.openstack.common import loopingcall
    58 from nova.openstack.common import processutils
    58 from nova.openstack.common import processutils
    59 from nova.openstack.common import strutils
    59 from nova.openstack.common import strutils
   280     """
   280     """
   281 
   281 
   282     capabilities = {
   282     capabilities = {
   283         "has_imagecache": False,
   283         "has_imagecache": False,
   284         "supports_recreate": False,
   284         "supports_recreate": False,
   285     }
   285         }
   286 
   286 
   287     def __init__(self, virtapi):
   287     def __init__(self, virtapi):
   288         self.virtapi = virtapi
   288         self.virtapi = virtapi
   289         self._compute_event_callback = None
   289         self._compute_event_callback = None
   290         self._conductor_api = conductor.API()
   290         self._conductor_api = conductor.API()
   293         self._fc_wwpns = None
   293         self._fc_wwpns = None
   294         self._host_stats = {}
   294         self._host_stats = {}
   295         self._initiator = None
   295         self._initiator = None
   296         self._install_engine = None
   296         self._install_engine = None
   297         self._pagesize = os.sysconf('SC_PAGESIZE')
   297         self._pagesize = os.sysconf('SC_PAGESIZE')
       
   298         self._rad_connection = None
   298         self._uname = os.uname()
   299         self._uname = os.uname()
   299         self._validated_archives = list()
   300         self._validated_archives = list()
   300         self._volume_api = volume.API()
   301         self._volume_api = volume.API()
       
   302 
       
   303     @property
       
   304     def rad_connection(self):
       
   305         if self._rad_connection is None:
       
   306             self._rad_connection = rad.connect.connect_unix()
       
   307         else:
       
   308             # taken from rad.connect.RadConnection.__repr__ to look for a
       
   309             # closed connection
       
   310             if self._rad_connection._closed is not None:
       
   311                 # the RAD connection has been lost.  Reconnect to RAD
       
   312                 self._rad_connection = rad.connect.connect_unix()
       
   313 
       
   314         return self._rad_connection
   301 
   315 
   302     def _init_rad(self):
   316     def _init_rad(self):
   303         """Connect to RAD providers for kernel statistics and Solaris
   317         """Connect to RAD providers for kernel statistics and Solaris
   304         Zones. By connecting to the local rad(1M) service through a
   318         Zones. By connecting to the local rad(1M) service through a
   305         UNIX domain socket, kernel statistics can be read via
   319         UNIX domain socket, kernel statistics can be read via
   306         kstat(3RAD) and Solaris Zones can be configured and controlled
   320         kstat(3RAD) and Solaris Zones can be configured and controlled
   307         via zonemgr(3RAD).
   321         via zonemgr(3RAD).
   308         """
   322         """
   309 
   323 
   310         # TODO(dcomay): Arrange to call this in the event of losing the
   324         try:
   311         # connection to RAD.
   325             self._kstat_control = self.rad_connection.get_object(
   312         try:
       
   313             self._rad_instance = rad.connect.connect_unix()
       
   314             self._kstat_control = self._rad_instance.get_object(
       
   315                 kstat.Control())
   326                 kstat.Control())
   316         except Exception as reason:
   327         except Exception as reason:
   317             msg = (_('Unable to connect to svc:/system/rad:local: %s')
   328             msg = (_('Unable to connect to svc:/system/rad:local: %s')
   318                    % reason)
   329                    % reason)
   319             raise exception.NovaException(msg)
   330             raise exception.NovaException(msg)
   322         """Initialize anything that is necessary for the driver to function,
   333         """Initialize anything that is necessary for the driver to function,
   323         including catching up with currently running VM's on the given host.
   334         including catching up with currently running VM's on the given host.
   324         """
   335         """
   325         # TODO(Vek): Need to pass context in for access to auth_token
   336         # TODO(Vek): Need to pass context in for access to auth_token
   326         self._init_rad()
   337         self._init_rad()
       
   338 
       
   339     def cleanup_host(self, host):
       
   340         """Clean up anything that is necessary for the driver gracefully stop,
       
   341         including ending remote sessions. This is optional.
       
   342         """
       
   343         pass
   327 
   344 
   328     def _get_fc_hbas(self):
   345     def _get_fc_hbas(self):
   329         """Get Fibre Channel HBA information."""
   346         """Get Fibre Channel HBA information."""
   330         if self._fc_hbas:
   347         if self._fc_hbas:
   331             return self._fc_hbas
   348             return self._fc_hbas
   418             return None
   435             return None
   419 
   436 
   420     def _get_zone_by_name(self, name):
   437     def _get_zone_by_name(self, name):
   421         """Return a Solaris Zones object via RAD by name."""
   438         """Return a Solaris Zones object via RAD by name."""
   422         try:
   439         try:
   423             zone = self._rad_instance.get_object(
   440             zone = self.rad_connection.get_object(
   424                 zonemgr.Zone(), rad.client.ADRGlobPattern({'name': name}))
   441                 zonemgr.Zone(), rad.client.ADRGlobPattern({'name': name}))
   425         except rad.client.NotFoundError:
   442         except rad.client.NotFoundError:
   426             return None
   443             return None
   427         except Exception:
   444         except Exception:
   428             raise
   445             raise
   438 
   455 
   439     def _get_max_mem(self, zone):
   456     def _get_max_mem(self, zone):
   440         """Return the maximum memory in KBytes allowed."""
   457         """Return the maximum memory in KBytes allowed."""
   441         max_mem = lookup_resource_property(zone, 'capped-memory', 'physical')
   458         max_mem = lookup_resource_property(zone, 'capped-memory', 'physical')
   442         if max_mem is not None:
   459         if max_mem is not None:
   443             return strutils.to_bytes(max_mem) / 1024
   460             return strutils.string_to_bytes("%sB" % max_mem) / 1024
   444 
   461 
   445         # If physical property in capped-memory doesn't exist, this may
   462         # If physical property in capped-memory doesn't exist, this may
   446         # represent a non-global zone so just return the system's total
   463         # represent a non-global zone so just return the system's total
   447         # memory.
   464         # memory.
   448         return self._pages_to_kb(os.sysconf('SC_PHYS_PAGES'))
   465         return self._pages_to_kb(os.sysconf('SC_PHYS_PAGES'))
   497             'instance': instance,
   514             'instance': instance,
   498             'name':     name
   515             'name':     name
   499         }
   516         }
   500         try:
   517         try:
   501             self._kstat_control.update()
   518             self._kstat_control.update()
   502             kstat_object = self._rad_instance.get_object(
   519             kstat_object = self.rad_connection.get_object(
   503                 kstat.Kstat(), rad.client.ADRGlobPattern(pattern))
   520                 kstat.Kstat(), rad.client.ADRGlobPattern(pattern))
   504         except Exception as reason:
   521         except Exception as reason:
   505             LOG.info(_("Unable to retrieve kstat object '%s:%s:%s' of class "
   522             LOG.info(_("Unable to retrieve kstat object '%s:%s:%s' of class "
   506                        "'%s' via kstat(3RAD): %s")
   523                        "'%s' via kstat(3RAD): %s")
   507                      % (module, instance, name, kstat_class, reason))
   524                      % (module, instance, name, kstat_class, reason))
   525 
   542 
   526         return kstat_data['cpu_nsec_kernel'] + kstat_data['cpu_nsec_user']
   543         return kstat_data['cpu_nsec_kernel'] + kstat_data['cpu_nsec_user']
   527 
   544 
   528     def get_info(self, instance):
   545     def get_info(self, instance):
   529         """Get the current status of an instance, by name (not ID!)
   546         """Get the current status of an instance, by name (not ID!)
       
   547 
       
   548         :param instance: nova.objects.instance.Instance object
   530 
   549 
   531         Returns a dict containing:
   550         Returns a dict containing:
   532 
   551 
   533         :state:           the running state, one of the power_state codes
   552         :state:           the running state, one of the power_state codes
   534         :max_mem:         (int) the maximum memory in KBytes allowed
   553         :max_mem:         (int) the maximum memory in KBytes allowed
   564             encouraged to override this method with something more
   583             encouraged to override this method with something more
   565             efficient.
   584             efficient.
   566         """
   585         """
   567         return len(self.list_instances())
   586         return len(self.list_instances())
   568 
   587 
   569     def instance_exists(self, instance_id):
   588     def instance_exists(self, instance):
   570         """Checks existence of an instance on the host.
   589         """Checks existence of an instance on the host.
   571 
   590 
   572         :param instance_id: The ID / name of the instance to lookup
   591         :param instance: The instance to lookup
   573 
   592 
   574         Returns True if an instance with the supplied ID exists on
   593         Returns True if an instance with the supplied ID exists on
   575         the host, False otherwise.
   594         the host, False otherwise.
   576 
   595 
   577         .. note::
   596         .. note::
   579             This implementation works for all drivers, but it is
   598             This implementation works for all drivers, but it is
   580             not particularly efficient. Maintainers of the virt drivers are
   599             not particularly efficient. Maintainers of the virt drivers are
   581             encouraged to override this method with something more
   600             encouraged to override this method with something more
   582             efficient.
   601             efficient.
   583         """
   602         """
   584         return instance_id in self.list_instances()
   603         try:
       
   604             return instance.uuid in self.list_instance_uuids()
       
   605         except NotImplementedError:
       
   606             return instance.name in self.list_instances()
   585 
   607 
   586     def estimate_instance_overhead(self, instance_info):
   608     def estimate_instance_overhead(self, instance_info):
   587         """Estimate the virtualization overhead required to build an instance
   609         """Estimate the virtualization overhead required to build an instance
   588         of the given flavor.
   610         of the given flavor.
   589 
   611 
   595         """
   617         """
   596         return {'memory_mb': 0}
   618         return {'memory_mb': 0}
   597 
   619 
   598     def _get_list_zone_object(self):
   620     def _get_list_zone_object(self):
   599         """Return a list of all Solaris Zones objects via RAD."""
   621         """Return a list of all Solaris Zones objects via RAD."""
   600         return self._rad_instance.list_objects(zonemgr.Zone())
   622         return self.rad_connection.list_objects(zonemgr.Zone())
   601 
   623 
   602     def list_instances(self):
   624     def list_instances(self):
   603         """
   625         """Return the names of all the instances known to the virtualization
   604         Return the names of all the instances known to the virtualization
       
   605         layer, as a list.
   626         layer, as a list.
   606         """
   627         """
   607         # TODO(Vek): Need to pass context in for access to auth_token
   628         # TODO(Vek): Need to pass context in for access to auth_token
   608         instances_list = []
   629         instances_list = []
   609         for zone in self._get_list_zone_object():
   630         for zone in self._get_list_zone_object():
   610             instances_list.append(self._rad_instance.get_object(zone).name)
   631             instances_list.append(self.rad_connection.get_object(zone).name)
   611 
       
   612         return instances_list
   632         return instances_list
   613 
   633 
   614     def list_instance_uuids(self):
   634     def list_instance_uuids(self):
   615         """
   635         """Return the UUIDS of all the instances known to the virtualization
   616         Return the UUIDS of all the instances known to the virtualization
       
   617         layer, as a list.
   636         layer, as a list.
       
   637         """
       
   638         raise NotImplementedError()
       
   639 
       
   640     def rebuild(self, context, instance, image_meta, injected_files,
       
   641                 admin_password, bdms, detach_block_devices,
       
   642                 attach_block_devices, network_info=None,
       
   643                 recreate=False, block_device_info=None,
       
   644                 preserve_ephemeral=False):
       
   645         """Destroy and re-make this instance.
       
   646 
       
   647         A 'rebuild' effectively purges all existing data from the system and
       
   648         remakes the VM with given 'metadata' and 'personalities'.
       
   649 
       
   650         This base class method shuts down the VM, detaches all block devices,
       
   651         then spins up the new VM afterwards. It may be overridden by
       
   652         hypervisors that need to - e.g. for optimisations, or when the 'VM'
       
   653         is actually proxied and needs to be held across the shutdown + spin
       
   654         up steps.
       
   655 
       
   656         :param context: security context
       
   657         :param instance: nova.objects.instance.Instance
       
   658                          This function should use the data there to guide
       
   659                          the creation of the new instance.
       
   660         :param image_meta: image object returned by nova.image.glance that
       
   661                            defines the image from which to boot this instance
       
   662         :param injected_files: User files to inject into instance.
       
   663         :param admin_password: Administrator password to set in instance.
       
   664         :param bdms: block-device-mappings to use for rebuild
       
   665         :param detach_block_devices: function to detach block devices. See
       
   666             nova.compute.manager.ComputeManager:_rebuild_default_impl for
       
   667             usage.
       
   668         :param attach_block_devices: function to attach block devices. See
       
   669             nova.compute.manager.ComputeManager:_rebuild_default_impl for
       
   670             usage.
       
   671         :param network_info:
       
   672            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
       
   673         :param recreate: True if the instance is being recreated on a new
       
   674             hypervisor - all the cleanup of old state is skipped.
       
   675         :param block_device_info: Information about block devices to be
       
   676                                   attached to the instance.
       
   677         :param preserve_ephemeral: True if the default ephemeral storage
       
   678                                    partition must be preserved on rebuild
   618         """
   679         """
   619         raise NotImplementedError()
   680         raise NotImplementedError()
   620 
   681 
   621     def _fetch_image(self, context, instance):
   682     def _fetch_image(self, context, instance):
   622         """Fetch an image using Glance given the instance's image_ref."""
   683         """Fetch an image using Glance given the instance's image_ref."""
   960         zone = self._get_zone_by_name(name)
  1021         zone = self._get_zone_by_name(name)
   961         if zone is None:
  1022         if zone is None:
   962             raise exception.InstanceNotFound(instance_id=name)
  1023             raise exception.InstanceNotFound(instance_id=name)
   963 
  1024 
   964         tenant_id = None
  1025         tenant_id = None
       
  1026         network_plugin = neutronv2.get_client(context)
   965         for netid, network in enumerate(network_info):
  1027         for netid, network in enumerate(network_info):
   966             if tenant_id is None:
  1028             if tenant_id is None:
   967                 tenant_id = network['network']['meta']['tenant_id']
  1029                 tenant_id = network['network']['meta']['tenant_id']
   968             network_uuid = network['network']['id']
       
   969             port_uuid = network['id']
  1030             port_uuid = network['id']
       
  1031             port = network_plugin.show_port(port_uuid)['port']
       
  1032             evs_uuid = port['network_id']
       
  1033             vport_uuid = port['id']
   970             ip = network['network']['subnets'][0]['ips'][0]['address']
  1034             ip = network['network']['subnets'][0]['ips'][0]['address']
   971             ip_version = network['network']['subnets'][0]['version']
  1035             ip_version = network['network']['subnets'][0]['version']
   972             route = network['network']['subnets'][0]['gateway']['address']
  1036             route = network['network']['subnets'][0]['gateway']['address']
   973             dns_list = network['network']['subnets'][0]['dns']
  1037             dns_list = network['network']['subnets'][0]['dns']
   974             nameservers = []
  1038             nameservers = []
   977                     nameservers.append(dns['address'])
  1041                     nameservers.append(dns['address'])
   978 
  1042 
   979             with ZoneConfig(zone) as zc:
  1043             with ZoneConfig(zone) as zc:
   980                 if netid == 0:
  1044                 if netid == 0:
   981                     zc.setprop('anet', 'configure-allowed-address', 'false')
  1045                     zc.setprop('anet', 'configure-allowed-address', 'false')
   982                     zc.setprop('anet', 'evs', network_uuid)
  1046                     zc.setprop('anet', 'evs', evs_uuid)
   983                     zc.setprop('anet', 'vport', port_uuid)
  1047                     zc.setprop('anet', 'vport', vport_uuid)
   984                 else:
  1048                 else:
   985                     zc.addresource(
  1049                     zc.addresource(
   986                         'anet',
  1050                         'anet',
   987                         [zonemgr.Property('configure-allowed-address',
  1051                         [zonemgr.Property('configure-allowed-address',
   988                                           'false'),
  1052                                           'false'),
   989                          zonemgr.Property('evs', network_uuid),
  1053                          zonemgr.Property('evs', evs_uuid),
   990                          zonemgr.Property('vport', port_uuid)])
  1054                          zonemgr.Property('vport', vport_uuid)])
   991 
  1055 
   992                 filter = [zonemgr.Property('vport', port_uuid)]
  1056                 filter = [zonemgr.Property('vport', vport_uuid)]
   993                 if brand == ZONE_BRAND_SOLARIS:
  1057                 if brand == ZONE_BRAND_SOLARIS:
   994                     linkname = lookup_resource_property(zc.zone, 'anet',
  1058                     linkname = lookup_resource_property(zc.zone, 'anet',
   995                                                         'linkname', filter)
  1059                                                         'linkname', filter)
   996                 else:
  1060                 else:
   997                     id = lookup_resource_property(zc.zone, 'anet', 'id',
  1061                     id = lookup_resource_property(zc.zone, 'anet', 'id',
   998                                                   filter)
  1062                                                   filter)
   999                     linkname = 'net%s' % id
  1063                     linkname = 'net%s' % id
  1000 
  1064 
  1001             # create the required sysconfig file
  1065             # create the required sysconfig file
  1002             network_plugin = neutronv2.get_client(context)
       
  1003             port = network_plugin.show_port(port_uuid)['port']
       
  1004             subnet_uuid = port['fixed_ips'][0]['subnet_id']
  1066             subnet_uuid = port['fixed_ips'][0]['subnet_id']
  1005             subnet = network_plugin.show_subnet(subnet_uuid)['subnet']
  1067             subnet = network_plugin.show_subnet(subnet_uuid)['subnet']
  1006 
  1068 
  1007             if subnet['enable_dhcp']:
  1069             if subnet['enable_dhcp']:
  1008                 tree = sysconfig.create_ncp_defaultfixed('dhcp', linkname,
  1070                 tree = sysconfig.create_ncp_defaultfixed('dhcp', linkname,
  1101             elif os.path.isdir(sc_profile):
  1163             elif os.path.isdir(sc_profile):
  1102                 shutil.copytree(sc_profile, os.path.join(sc_dir, 'sysconfig'))
  1164                 shutil.copytree(sc_profile, os.path.join(sc_dir, 'sysconfig'))
  1103 
  1165 
  1104         self._verify_sysconfig(sc_dir, instance)
  1166         self._verify_sysconfig(sc_dir, instance)
  1105 
  1167 
  1106         zonemanager = self._rad_instance.get_object(zonemgr.ZoneManager())
  1168         zonemanager = self.rad_connection.get_object(zonemgr.ZoneManager())
  1107         try:
  1169         try:
  1108             zonemanager.create(name, None, template)
  1170             zonemanager.create(name, None, template)
  1109             self._set_global_properties(name, extra_specs, brand)
  1171             self._set_global_properties(name, extra_specs, brand)
  1110             if connection_info:
  1172             if connection_info:
  1111                 self._set_boot_device(name, connection_info, brand)
  1173                 self._set_boot_device(name, connection_info, brand)
  1333         """Delete an existing Solaris Zone configuration."""
  1395         """Delete an existing Solaris Zone configuration."""
  1334         name = instance['name']
  1396         name = instance['name']
  1335         if self._get_zone_by_name(name) is None:
  1397         if self._get_zone_by_name(name) is None:
  1336             raise exception.InstanceNotFound(instance_id=name)
  1398             raise exception.InstanceNotFound(instance_id=name)
  1337 
  1399 
  1338         zonemanager = self._rad_instance.get_object(zonemgr.ZoneManager())
  1400         zonemanager = self.rad_connection.get_object(zonemgr.ZoneManager())
  1339         try:
  1401         try:
  1340             zonemanager.delete(name)
  1402             zonemanager.delete(name)
  1341         except Exception as reason:
  1403         except Exception as reason:
  1342             LOG.error(_("Unable to delete configuration for instance '%s' via "
  1404             LOG.error(_("Unable to delete configuration for instance '%s' via "
  1343                         "zonemgr(3RAD): %s") % (name, reason))
  1405                         "zonemgr(3RAD): %s") % (name, reason))
  1344             raise
  1406             raise
  1345 
  1407 
  1346     def spawn(self, context, instance, image_meta, injected_files,
  1408     def spawn(self, context, instance, image_meta, injected_files,
  1347               admin_password, network_info=None, block_device_info=None):
  1409               admin_password, network_info=None, block_device_info=None):
  1348         """
  1410         """Create a new instance/VM/domain on the virtualization platform.
  1349         Create a new instance/VM/domain on the virtualization platform.
       
  1350 
  1411 
  1351         Once this successfully completes, the instance should be
  1412         Once this successfully completes, the instance should be
  1352         running (power_state.RUNNING).
  1413         running (power_state.RUNNING).
  1353 
  1414 
  1354         If this fails, any partial instance should be completely
  1415         If this fails, any partial instance should be completely
  1355         cleaned up, and the virtualization platform should be in the state
  1416         cleaned up, and the virtualization platform should be in the state
  1356         that it was before this call began.
  1417         that it was before this call began.
  1357 
  1418 
  1358         :param context: security context
  1419         :param context: security context
  1359         :param instance: Instance object as returned by DB layer.
  1420         :param instance: nova.objects.instance.Instance
  1360                          This function should use the data there to guide
  1421                          This function should use the data there to guide
  1361                          the creation of the new instance.
  1422                          the creation of the new instance.
  1362         :param image_meta: image object returned by nova.image.glance that
  1423         :param image_meta: image object returned by nova.image.glance that
  1363                            defines the image from which to boot this instance
  1424                            defines the image from which to boot this instance
  1364         :param injected_files: User files to inject into instance.
  1425         :param injected_files: User files to inject into instance.
  1366         :param network_info:
  1427         :param network_info:
  1367            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
  1428            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
  1368         :param block_device_info: Information about block devices to be
  1429         :param block_device_info: Information about block devices to be
  1369                                   attached to the instance.
  1430                                   attached to the instance.
  1370         """
  1431         """
  1371         inst_type = self.virtapi.instance_type_get(
  1432         inst_type = flavor_obj.Flavor.get_by_id(
  1372             nova_context.get_admin_context(read_deleted='yes'),
  1433             nova_context.get_admin_context(read_deleted='yes'),
  1373             instance['instance_type_id'])
  1434             instance['instance_type_id'])
  1374         extra_specs = inst_type['extra_specs'].copy()
  1435         extra_specs = inst_type['extra_specs'].copy()
  1375 
  1436 
  1376         image = self._fetch_image(context, instance)
  1437         image = self._fetch_image(context, instance)
  1384         # Attempt to provision a (Cinder) volume service backed boot volume
  1445         # Attempt to provision a (Cinder) volume service backed boot volume
  1385         connection_info = self._connect_boot_volume(context, instance,
  1446         connection_info = self._connect_boot_volume(context, instance,
  1386                                                     extra_specs)
  1447                                                     extra_specs)
  1387         name = instance['name']
  1448         name = instance['name']
  1388 
  1449 
  1389         def _ai_health_check(zone):
       
  1390             # TODO(npower) A hung kernel zone installation will not always
       
  1391             # be detected by zoneadm in the host global zone, which locks
       
  1392             # out other zoneadm commands.
       
  1393             # Workaround:
       
  1394             # Check the state of the auto-installer:default SMF service in
       
  1395             # the kernel zone. If installation failed, it should be in the
       
  1396             # 'maintenance' state. Unclog zoneadm by executing a shutdown
       
  1397             # inside the kernel zone if that's the case.
       
  1398             # Eventually we'll be able to pass a boot option to the zone
       
  1399             # to have it automatically shutdown if the installation fails.
       
  1400             if instance['vm_state'] == vm_states.BUILDING:
       
  1401                 if self._get_zone_auto_install_state(name) == 'maintenance':
       
  1402                     # Poweroff the zone. This will cause the current call to
       
  1403                     # self._install() to catch an exception and tear down
       
  1404                     # the kernel zone.
       
  1405                     LOG.error(_("Automated installation of instance '%s' "
       
  1406                               "failed. Powering off the kernel zone '%s'.")
       
  1407                               % (instance['display_name'], name))
       
  1408                     try:
       
  1409                         utils.execute('/usr/sbin/zlogin', '-S', name,
       
  1410                                       '/usr/sbin/poweroff')
       
  1411                     except processutils.ProcessExecutionError as err:
       
  1412                         # poweroff pulls the rug from under zlogin, so ignore
       
  1413                         # the anticipated error.
       
  1414                         pass
       
  1415                     finally:
       
  1416                         raise loopingcall.LoopingCallDone()
       
  1417                 else:
       
  1418                     # Looks like it installed OK
       
  1419                     if zone.state == ZONE_STATE_INSTALLED:
       
  1420                         LOG.debug(_("Kernel zone '%s' (%s) state: %s.")
       
  1421                                   % (name, instance['display_name'],
       
  1422                                      zone.state))
       
  1423                         raise loopingcall.LoopingCallDone()
       
  1424                     else:
       
  1425                         return
       
  1426             else:
       
  1427                 # Can't imagine why we'd get here under normal circumstances
       
  1428                 LOG.warning(_("Unexpected vm_state during installation of "
       
  1429                             "'%s' (%s): %s. Zone state: %s")
       
  1430                             % (name, instance['display_name'],
       
  1431                                instance['vm_state'], zone.state))
       
  1432                 raise loopingcall.LoopingCallDone()
       
  1433 
       
  1434         LOG.debug(_("creating zone configuration for '%s' (%s)") %
  1450         LOG.debug(_("creating zone configuration for '%s' (%s)") %
  1435                   (name, instance['display_name']))
  1451                   (name, instance['display_name']))
  1436         self._create_config(context, instance, network_info,
  1452         self._create_config(context, instance, network_info,
  1437                             connection_info, extra_specs, sc_dir)
  1453                             connection_info, extra_specs, sc_dir)
  1438         try:
  1454         try:
  1439             zone = self._get_zone_by_name(name)
  1455             self._install(instance, image, extra_specs, sc_dir)
  1440             is_kz = lookup_resource_property_value(zone, "global", "brand",
       
  1441                                                    ZONE_BRAND_SOLARIS_KZ)
       
  1442             # Monitor kernel zone installation explicitly
       
  1443             if is_kz:
       
  1444                 monitor = loopingcall.FixedIntervalLoopingCall(
       
  1445                     _ai_health_check, zone)
       
  1446                 monitor.start(interval=15, initial_delay=60)
       
  1447                 self._install(instance, image, extra_specs, sc_dir)
       
  1448                 monitor.wait()
       
  1449             else:
       
  1450                 self._install(instance, image, extra_specs, sc_dir)
       
  1451             self._power_on(instance)
  1456             self._power_on(instance)
  1452         except Exception as reason:
  1457         except Exception as reason:
  1453             LOG.error(_("Unable to spawn instance '%s' via zonemgr(3RAD): %s")
  1458             LOG.error(_("Unable to spawn instance '%s' via zonemgr(3RAD): %s")
  1454                       % (name, reason))
  1459                       % (name, reason))
  1455             self._uninstall(instance)
  1460             self._uninstall(instance)
  1466         try:
  1471         try:
  1467             if halt_type == 'SOFT':
  1472             if halt_type == 'SOFT':
  1468                 zone.shutdown()
  1473                 zone.shutdown()
  1469             else:
  1474             else:
  1470                 # 'HARD'
  1475                 # 'HARD'
  1471                 # TODO(npower) See comments for _ai_health_check() for why
  1476                 zone.halt()
  1472                 # it is sometimes necessary to poweroff from within the zone,
       
  1473                 # until zoneadm and auto-install can perform this internally.
       
  1474                 zprop = lookup_resource_property_value(zone, "global", "brand",
       
  1475                                                        ZONE_BRAND_SOLARIS_KZ)
       
  1476                 if zprop and self._get_zone_auto_install_state(name):
       
  1477                     # Don't really care what state the install service is in.
       
  1478                     # Just shut it down ASAP.
       
  1479                     try:
       
  1480                         utils.execute('/usr/sbin/zlogin', '-S', name,
       
  1481                                       '/usr/sbin/poweroff')
       
  1482                     except processutils.ProcessExecutionError as err:
       
  1483                         # Poweroff pulls the rug from under zlogin, so ignore
       
  1484                         # the anticipated error.
       
  1485                         return
       
  1486                 else:
       
  1487                     zone.halt()
       
  1488             return
       
  1489         except rad.client.ObjectError as reason:
  1477         except rad.client.ObjectError as reason:
  1490             result = reason.get_payload()
  1478             result = reason.get_payload()
  1491             if result.code == zonemgr.ErrorCode.COMMAND_ERROR:
  1479             if result.code == zonemgr.ErrorCode.COMMAND_ERROR:
  1492                 LOG.warning(_("Ignoring command error returned while trying "
  1480                 LOG.warning(_("Ignoring command error returned while trying "
  1493                               "to power off instance '%s' via zonemgr(3RAD): "
  1481                               "to power off instance '%s' via zonemgr(3RAD): "
  1496         except Exception as reason:
  1484         except Exception as reason:
  1497             LOG.error(_("Unable to power off instance '%s' via zonemgr(3RAD): "
  1485             LOG.error(_("Unable to power off instance '%s' via zonemgr(3RAD): "
  1498                         "%s") % (name, reason))
  1486                         "%s") % (name, reason))
  1499             raise exception.InstancePowerOffFailure(reason=reason)
  1487             raise exception.InstancePowerOffFailure(reason=reason)
  1500 
  1488 
  1501     def destroy(self, instance, network_info, block_device_info=None,
  1489     def destroy(self, context, instance, network_info, block_device_info=None,
  1502                 destroy_disks=True, context=None):
  1490                 destroy_disks=True, migrate_data=None):
  1503         """Destroy (shutdown and delete) the specified instance.
  1491         """Destroy the specified instance from the Hypervisor.
  1504 
  1492 
  1505         If the instance is not found (for example if networking failed), this
  1493         If the instance is not found (for example if networking failed), this
  1506         function should still succeed.  It's probably a good idea to log a
  1494         function should still succeed.  It's probably a good idea to log a
  1507         warning in that case.
  1495         warning in that case.
  1508 
  1496 
       
  1497         :param context: security context
  1509         :param instance: Instance object as returned by DB layer.
  1498         :param instance: Instance object as returned by DB layer.
  1510         :param network_info:
  1499         :param network_info:
  1511            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
  1500            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
  1512         :param block_device_info: Information about block devices that should
  1501         :param block_device_info: Information about block devices that should
  1513                                   be detached from the instance.
  1502                                   be detached from the instance.
  1514         :param destroy_disks: Indicates if disks should be destroyed
  1503         :param destroy_disks: Indicates if disks should be destroyed
  1515 
  1504         :param migrate_data: implementation specific params
  1516         """
  1505         """
  1517         # TODO(Vek): Need to pass context in for access to auth_token
       
  1518         try:
  1506         try:
  1519             # These methods log if problems occur so no need to double log
  1507             # These methods log if problems occur so no need to double log
  1520             # here. Just catch any stray exceptions and allow destroy to
  1508             # here. Just catch any stray exceptions and allow destroy to
  1521             # proceed.
  1509             # proceed.
  1522             if self._has_vnc_console_service(instance):
  1510             if self._has_vnc_console_service(instance):
  1542                 self._delete_config(instance)
  1530                 self._delete_config(instance)
  1543         except Exception as reason:
  1531         except Exception as reason:
  1544             LOG.warning(_("Unable to destroy instance '%s' via zonemgr(3RAD): "
  1532             LOG.warning(_("Unable to destroy instance '%s' via zonemgr(3RAD): "
  1545                           "%s") % (name, reason))
  1533                           "%s") % (name, reason))
  1546 
  1534 
       
  1535     def cleanup(self, context, instance, network_info, block_device_info=None,
       
  1536                 destroy_disks=True, migrate_data=None, destroy_vifs=True):
       
  1537         """Cleanup the instance resources .
       
  1538 
       
  1539         Instance should have been destroyed from the Hypervisor before calling
       
  1540         this method.
       
  1541 
       
  1542         :param context: security context
       
  1543         :param instance: Instance object as returned by DB layer.
       
  1544         :param network_info:
       
  1545            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
       
  1546         :param block_device_info: Information about block devices that should
       
  1547                                   be detached from the instance.
       
  1548         :param destroy_disks: Indicates if disks should be destroyed
       
  1549         :param migrate_data: implementation specific params
       
  1550         """
       
  1551         raise NotImplementedError()
       
  1552 
  1547     def reboot(self, context, instance, network_info, reboot_type,
  1553     def reboot(self, context, instance, network_info, reboot_type,
  1548                block_device_info=None, bad_volumes_callback=None):
  1554                block_device_info=None, bad_volumes_callback=None):
  1549         """Reboot the specified instance.
  1555         """Reboot the specified instance.
  1550 
  1556 
  1551         After this is called successfully, the instance's state
  1557         After this is called successfully, the instance's state
  1552         goes back to power_state.RUNNING. The virtualization
  1558         goes back to power_state.RUNNING. The virtualization
  1553         platform should ensure that the reboot action has completed
  1559         platform should ensure that the reboot action has completed
  1554         successfully even in cases in which the underlying domain/vm
  1560         successfully even in cases in which the underlying domain/vm
  1555         is paused or halted/stopped.
  1561         is paused or halted/stopped.
  1556 
  1562 
  1557         :param instance: Instance object as returned by DB layer.
  1563         :param instance: nova.objects.instance.Instance
  1558         :param network_info:
  1564         :param network_info:
  1559            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
  1565            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
  1560         :param reboot_type: Either a HARD or SOFT reboot
  1566         :param reboot_type: Either a HARD or SOFT reboot
  1561         :param block_device_info: Info pertaining to attached volumes
  1567         :param block_device_info: Info pertaining to attached volumes
  1562         :param bad_volumes_callback: Function to handle any bad volumes
  1568         :param bad_volumes_callback: Function to handle any bad volumes
  1622                 for line in log.readlines():
  1628                 for line in log.readlines():
  1623                     fragment += line
  1629                     fragment += line
  1624                 console_str = fragment + console_str
  1630                 console_str = fragment + console_str
  1625         return console_str
  1631         return console_str
  1626 
  1632 
  1627     def get_console_output(self, instance):
  1633     def get_console_output(self, context, instance):
  1628         # TODO(Vek): Need to pass context in for access to auth_token
  1634         """Get console output for an instance
       
  1635 
       
  1636         :param context: security context
       
  1637         :param instance: nova.objects.instance.Instance
       
  1638         """
  1629         return self._get_console_output(instance)
  1639         return self._get_console_output(instance)
  1630 
  1640 
  1631     def get_vnc_console(self, instance):
  1641     def get_vnc_console(self, context, instance):
  1632         # TODO(Vek): Need to pass context in for access to auth_token
  1642         """Get connection info for a vnc console.
  1633 
  1643 
       
  1644         :param context: security context
       
  1645         :param instance: nova.objects.instance.Instance
       
  1646 
       
  1647         :returns an instance of console.type.ConsoleVNC
       
  1648         """
  1634         # Do not provide console access prematurely. Zone console access is
  1649         # Do not provide console access prematurely. Zone console access is
  1635         # exclusive and zones that are still installing require their console.
  1650         # exclusive and zones that are still installing require their console.
  1636         # Grabbing the zone console will break installation.
  1651         # Grabbing the zone console will break installation.
  1637         name = instance['name']
  1652         name = instance['name']
  1638         if instance['vm_state'] == vm_states.BUILDING:
  1653         if instance['vm_state'] == vm_states.BUILDING:
  1661             raise
  1676             raise
  1662 
  1677 
  1663         try:
  1678         try:
  1664             out, err = utils.execute('/usr/bin/svcprop', '-p', 'vnc/port',
  1679             out, err = utils.execute('/usr/bin/svcprop', '-p', 'vnc/port',
  1665                                      console_fmri)
  1680                                      console_fmri)
  1666             port = out.strip()
  1681             port = int(out.strip())
  1667             return {'host': '127.0.0.1', 'port': port,
  1682             return ctype.ConsoleVNC(host='127.0.0.1',
  1668                     'internal_access_path': None}
  1683                                     port=port,
       
  1684                                     internal_access_path=None)
  1669         except processutils.ProcessExecutionError as err:
  1685         except processutils.ProcessExecutionError as err:
  1670             LOG.error(_("Unable to read VNC console port from zone VNC "
  1686             LOG.error(_("Unable to read VNC console port from zone VNC "
  1671                         "console SMF service '%s': %s"
  1687                         "console SMF service '%s': %s"
  1672                       % (console_fmri, err)))
  1688                       % (console_fmri, err)))
  1673 
  1689 
  1674     def get_spice_console(self, instance):
  1690     def get_spice_console(self, context, instance):
  1675         # TODO(Vek): Need to pass context in for access to auth_token
  1691         """Get connection info for a spice console.
       
  1692 
       
  1693         :param context: security context
       
  1694         :param instance: nova.objects.instance.Instance
       
  1695 
       
  1696         :returns an instance of console.type.ConsoleSpice
       
  1697         """
       
  1698         raise NotImplementedError()
       
  1699 
       
  1700     def get_rdp_console(self, context, instance):
       
  1701         """Get connection info for a rdp console.
       
  1702 
       
  1703         :param context: security context
       
  1704         :param instance: nova.objects.instance.Instance
       
  1705 
       
  1706         :returns an instance of console.type.ConsoleRDP
       
  1707         """
       
  1708         raise NotImplementedError()
       
  1709 
       
  1710     def get_serial_console(self, context, instance):
       
  1711         """Get connection info for a serial console.
       
  1712 
       
  1713         :param context: security context
       
  1714         :param instance: nova.objects.instance.Instance
       
  1715 
       
  1716         :returns an instance of console.type.ConsoleSerial
       
  1717         """
  1676         raise NotImplementedError()
  1718         raise NotImplementedError()
  1677 
  1719 
  1678     def _get_zone_diagnostics(self, zone):
  1720     def _get_zone_diagnostics(self, zone):
  1679         """Return data about Solaris Zone diagnostics."""
  1721         """Return data about Solaris Zone diagnostics."""
  1680         if zone.id == -1:
  1722         if zone.id == -1:
  1705                 if key not in ('class', 'crtime', 'snaptime'):
  1747                 if key not in ('class', 'crtime', 'snaptime'):
  1706                     diagnostics[key] = kstat_data[key]
  1748                     diagnostics[key] = kstat_data[key]
  1707         return diagnostics
  1749         return diagnostics
  1708 
  1750 
  1709     def get_diagnostics(self, instance):
  1751     def get_diagnostics(self, instance):
  1710         """Return data about VM diagnostics."""
  1752         """Return data about VM diagnostics.
       
  1753 
       
  1754         :param instance: nova.objects.instance.Instance
       
  1755         """
  1711         # TODO(Vek): Need to pass context in for access to auth_token
  1756         # TODO(Vek): Need to pass context in for access to auth_token
  1712         name = instance['name']
  1757         name = instance['name']
  1713         zone = self._get_zone_by_name(name)
  1758         zone = self._get_zone_by_name(name)
  1714         if zone is None:
  1759         if zone is None:
  1715             LOG.error(_("Unable to find instance '%s' via zonemgr(3RAD)")
  1760             LOG.error(_("Unable to find instance '%s' via zonemgr(3RAD)")
  1716                       % name)
  1761                       % name)
  1717             raise exception.InstanceNotFound(instance_id=name)
  1762             raise exception.InstanceNotFound(instance_id=name)
  1718         return self._get_zone_diagnostics(zone)
  1763         return self._get_zone_diagnostics(zone)
  1719 
  1764 
       
  1765     def get_instance_diagnostics(self, instance):
       
  1766         """Return data about VM diagnostics.
       
  1767 
       
  1768         :param instance: nova.objects.instance.Instance
       
  1769         """
       
  1770         raise NotImplementedError()
       
  1771 
  1720     def get_all_bw_counters(self, instances):
  1772     def get_all_bw_counters(self, instances):
  1721         """Return bandwidth usage counters for each interface on each
  1773         """Return bandwidth usage counters for each interface on each
  1722            running VM.
  1774            running VM.
       
  1775 
       
  1776         :param instances: nova.objects.instance.InstanceList
  1723         """
  1777         """
  1724         raise NotImplementedError()
  1778         raise NotImplementedError()
  1725 
  1779 
  1726     def get_all_volume_usage(self, context, compute_host_bdms):
  1780     def get_all_volume_usage(self, context, compute_host_bdms):
  1727         """Return usage info for volumes attached to vms on
  1781         """Return usage info for volumes attached to vms on
  1728            a given host.-
  1782            a given host.-
  1729         """
  1783         """
  1730         raise NotImplementedError()
  1784         raise NotImplementedError()
  1731 
  1785 
  1732     def get_host_ip_addr(self):
  1786     def get_host_ip_addr(self):
  1733         """
  1787         """Retrieves the IP address of the dom0
  1734         Retrieves the IP address of the dom0
       
  1735         """
  1788         """
  1736         # TODO(Vek): Need to pass context in for access to auth_token
  1789         # TODO(Vek): Need to pass context in for access to auth_token
  1737         return CONF.my_ip
  1790         return CONF.my_ip
  1738 
  1791 
  1739     def attach_volume(self, context, connection_info, instance, mountpoint,
  1792     def attach_volume(self, context, connection_info, instance, mountpoint,
  1740                       encryption=None):
  1793                       disk_bus=None, device_type=None, encryption=None):
  1741         """Attach the disk to the instance at mountpoint using info."""
  1794         """Attach the disk to the instance at mountpoint using info."""
  1742         # TODO(npower): Apply mountpoint in a meaningful way to the zone
  1795         # TODO(npower): Apply mountpoint in a meaningful way to the zone
  1743         # (I don't think this is even possible for Solaris brand zones)
  1796         # (I don't think this is even possible for Solaris brand zones)
  1744         name = instance['name']
  1797         name = instance['name']
  1745         zone = self._get_zone_by_name(name)
  1798         zone = self._get_zone_by_name(name)
  1782 
  1835 
  1783         with ZoneConfig(zone) as zc:
  1836         with ZoneConfig(zone) as zc:
  1784             zc.removeresources("device", [zonemgr.Property("storage", suri)])
  1837             zc.removeresources("device", [zonemgr.Property("storage", suri)])
  1785 
  1838 
  1786     def swap_volume(self, old_connection_info, new_connection_info,
  1839     def swap_volume(self, old_connection_info, new_connection_info,
  1787                     instance, mountpoint):
  1840                     instance, mountpoint, resize_to):
  1788         """Replace the disk attached to the instance."""
  1841         """Replace the disk attached to the instance.
       
  1842 
       
  1843         :param instance: nova.objects.instance.Instance
       
  1844         :param resize_to: This parameter is used to indicate the new volume
       
  1845                           size when the new volume lager than old volume.
       
  1846                           And the units is Gigabyte.
       
  1847         """
  1789         raise NotImplementedError()
  1848         raise NotImplementedError()
  1790 
  1849 
  1791     def attach_interface(self, instance, image_meta, vif):
  1850     def attach_interface(self, instance, image_meta, vif):
  1792         """Attach an interface to the instance."""
  1851         """Attach an interface to the instance.
       
  1852 
       
  1853         :param instance: nova.objects.instance.Instance
       
  1854         """
  1793         raise NotImplementedError()
  1855         raise NotImplementedError()
  1794 
  1856 
  1795     def detach_interface(self, instance, vif):
  1857     def detach_interface(self, instance, vif):
  1796         """Detach an interface from the instance."""
  1858         """Detach an interface from the instance.
       
  1859 
       
  1860         :param instance: nova.objects.instance.Instance
       
  1861         """
  1797         raise NotImplementedError()
  1862         raise NotImplementedError()
  1798 
  1863 
  1799     def migrate_disk_and_power_off(self, context, instance, dest,
  1864     def migrate_disk_and_power_off(self, context, instance, dest,
  1800                                    instance_type, network_info,
  1865                                    flavor, network_info,
  1801                                    block_device_info=None):
  1866                                    block_device_info=None,
  1802         """
  1867                                    timeout=0, retry_interval=0):
  1803         Transfers the disk of a running instance in multiple phases, turning
  1868         """Transfers the disk of a running instance in multiple phases, turning
  1804         off the instance before the end.
  1869         off the instance before the end.
  1805         """
  1870 
  1806         raise NotImplementedError()
  1871         :param instance: nova.objects.instance.Instance
  1807 
  1872         :param timeout: time to wait for GuestOS to shutdown
  1808     def live_snapshot(self, context, instance, image_id, update_task_state):
  1873         :param retry_interval: How often to signal guest while
  1809         """
  1874                                waiting for it to shutdown
  1810         Live-snapshots the specified instance (includes ram and proc state).
  1875         """
       
  1876         raise NotImplementedError()
       
  1877 
       
  1878     def snapshot(self, context, instance, image_id, update_task_state):
       
  1879         """Snapshots the specified instance.
  1811 
  1880 
  1812         :param context: security context
  1881         :param context: security context
  1813         :param instance: Instance object as returned by DB layer.
  1882         :param instance: nova.objects.instance.Instance
  1814         :param image_id: Reference to a pre-created image that will
       
  1815                          hold the snapshot.
       
  1816         """
       
  1817         raise NotImplementedError()
       
  1818 
       
  1819     def snapshot(self, context, instance, image_id, update_task_state):
       
  1820         """
       
  1821         Snapshots the specified instance.
       
  1822 
       
  1823         :param context: security context
       
  1824         :param instance: Instance object as returned by DB layer.
       
  1825         :param image_id: Reference to a pre-created image that will
  1883         :param image_id: Reference to a pre-created image that will
  1826                          hold the snapshot.
  1884                          hold the snapshot.
  1827         """
  1885         """
  1828         # Get original base image info
  1886         # Get original base image info
  1829         (base_service, base_id) = glance.get_remote_image_service(
  1887         (base_service, base_id) = glance.get_remote_image_service(
  1844             'name': snapshot['name'],
  1902             'name': snapshot['name'],
  1845             'properties': {
  1903             'properties': {
  1846                 'image_location': 'snapshot',
  1904                 'image_location': 'snapshot',
  1847                 'image_state': 'available',
  1905                 'image_state': 'available',
  1848                 'owner_id': instance['project_id'],
  1906                 'owner_id': instance['project_id'],
       
  1907                 'instance_uuid': instance['uuid'],
  1849             }
  1908             }
  1850         }
  1909         }
  1851         # Match architecture, hypervisor_type and vm_mode properties to base
  1910         # Match architecture, hypervisor_type and vm_mode properties to base
  1852         # image.
  1911         # image.
  1853         for prop in ['architecture', 'hypervisor_type', 'vm_mode']:
  1912         for prop in ['architecture', 'hypervisor_type', 'vm_mode']:
  1865         fileutils.ensure_tree(snapshot_directory)
  1924         fileutils.ensure_tree(snapshot_directory)
  1866         snapshot_name = uuid.uuid4().hex
  1925         snapshot_name = uuid.uuid4().hex
  1867 
  1926 
  1868         with utils.tempdir(dir=snapshot_directory) as tmpdir:
  1927         with utils.tempdir(dir=snapshot_directory) as tmpdir:
  1869             out_path = os.path.join(tmpdir, snapshot_name)
  1928             out_path = os.path.join(tmpdir, snapshot_name)
  1870 
       
  1871             # TODO(npower): archiveadm invocation needs --root-only arg
       
  1872             # passed once it is available. Assume the instance contains
       
  1873             # root pool only for now.
       
  1874             zone_name = instance['name']
  1929             zone_name = instance['name']
  1875             utils.execute('/usr/sbin/archiveadm', 'create', '--root-only',
  1930             utils.execute('/usr/sbin/archiveadm', 'create', '--root-only',
  1876                           '-z', zone_name, out_path)
  1931                           '-z', zone_name, out_path)
  1877 
  1932 
  1878             LOG.info(_("Snapshot extracted, beginning image upload"),
  1933             LOG.info(_("Snapshot extracted, beginning image upload"),
  1879                      instance=instance)
  1934                      instance=instance)
  1880             try:
  1935             try:
  1881                 # Upload the archive image to the image service
  1936                 # Upload the archive image to the image service
  1882                 update_task_state(task_state=task_states.IMAGE_UPLOADING,
  1937                 update_task_state(
  1883                                   expected_state=
  1938                     task_state=task_states.IMAGE_UPLOADING,
  1884                                   task_states.IMAGE_PENDING_UPLOAD)
  1939                     expected_state=task_states.IMAGE_PENDING_UPLOAD)
  1885                 with open(out_path, 'r') as image_file:
  1940                 with open(out_path, 'r') as image_file:
  1886                     snapshot_service.update(context,
  1941                     snapshot_service.update(context,
  1887                                             image_id,
  1942                                             image_id,
  1888                                             metadata,
  1943                                             metadata,
  1889                                             image_file)
  1944                                             image_file)
  1906                                   "'raw' as fallbacks."))
  1961                                   "'raw' as fallbacks."))
  1907             finally:
  1962             finally:
  1908                 # Delete the snapshot image file source
  1963                 # Delete the snapshot image file source
  1909                 os.unlink(out_path)
  1964                 os.unlink(out_path)
  1910 
  1965 
       
  1966     def post_interrupted_snapshot_cleanup(self, context, instance):
       
  1967         """Cleans up any resources left after an interrupted snapshot.
       
  1968 
       
  1969         :param context: security context
       
  1970         :param instance: nova.objects.instance.Instance
       
  1971         """
       
  1972         pass
       
  1973 
  1911     def finish_migration(self, context, migration, instance, disk_info,
  1974     def finish_migration(self, context, migration, instance, disk_info,
  1912                          network_info, image_meta, resize_instance,
  1975                          network_info, image_meta, resize_instance,
  1913                          block_device_info=None, power_on=True):
  1976                          block_device_info=None, power_on=True):
  1914         """Completes a resize.
  1977         """Completes a resize.
  1915 
  1978 
  1916         :param context: the context for the migration/resize
  1979         :param context: the context for the migration/resize
  1917         :param migration: the migrate/resize information
  1980         :param migration: the migrate/resize information
  1918         :param instance: the instance being migrated/resized
  1981         :param instance: nova.objects.instance.Instance being migrated/resized
  1919         :param disk_info: the newly transferred disk information
  1982         :param disk_info: the newly transferred disk information
  1920         :param network_info:
  1983         :param network_info:
  1921            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
  1984            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
  1922         :param image_meta: image object returned by nova.image.glance that
  1985         :param image_meta: image object returned by nova.image.glance that
  1923                            defines the image from which this instance
  1986                            defines the image from which this instance
  1929                          otherwise
  1992                          otherwise
  1930         """
  1993         """
  1931         raise NotImplementedError()
  1994         raise NotImplementedError()
  1932 
  1995 
  1933     def confirm_migration(self, migration, instance, network_info):
  1996     def confirm_migration(self, migration, instance, network_info):
  1934         """Confirms a resize, destroying the source VM."""
  1997         """Confirms a resize, destroying the source VM.
       
  1998 
       
  1999         :param instance: nova.objects.instance.Instance
       
  2000         """
  1935         # TODO(Vek): Need to pass context in for access to auth_token
  2001         # TODO(Vek): Need to pass context in for access to auth_token
  1936         raise NotImplementedError()
  2002         raise NotImplementedError()
  1937 
  2003 
  1938     def finish_revert_migration(self, instance, network_info,
  2004     def finish_revert_migration(self, context, instance, network_info,
  1939                                 block_device_info=None, power_on=True):
  2005                                 block_device_info=None, power_on=True):
  1940         """
  2006         """Finish reverting a resize.
  1941         Finish reverting a resize.
  2007 
  1942 
  2008         :param context: the context for the finish_revert_migration
  1943         :param instance: the instance being migrated/resized
  2009         :param instance: nova.objects.instance.Instance being migrated/resized
  1944         :param network_info:
  2010         :param network_info:
  1945            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
  2011            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
  1946         :param block_device_info: instance volume block device info
  2012         :param block_device_info: instance volume block device info
  1947         :param power_on: True if the instance should be powered on, False
  2013         :param power_on: True if the instance should be powered on, False
  1948                          otherwise
  2014                          otherwise
  1949         """
  2015         """
       
  2016         raise NotImplementedError()
       
  2017 
       
  2018     def pause(self, instance):
       
  2019         """Pause the specified instance.
       
  2020 
       
  2021         :param instance: nova.objects.instance.Instance
       
  2022         """
  1950         # TODO(Vek): Need to pass context in for access to auth_token
  2023         # TODO(Vek): Need to pass context in for access to auth_token
  1951         raise NotImplementedError()
  2024         raise NotImplementedError()
  1952 
  2025 
  1953     def pause(self, instance):
  2026     def unpause(self, instance):
  1954         """Pause the specified instance."""
  2027         """Unpause paused VM instance.
       
  2028 
       
  2029         :param instance: nova.objects.instance.Instance
       
  2030         """
  1955         # TODO(Vek): Need to pass context in for access to auth_token
  2031         # TODO(Vek): Need to pass context in for access to auth_token
  1956         raise NotImplementedError()
  2032         raise NotImplementedError()
  1957 
  2033 
  1958     def unpause(self, instance):
  2034     def suspend(self, instance):
  1959         """Unpause paused VM instance."""
  2035         """suspend the specified instance.
       
  2036 
       
  2037         :param instance: nova.objects.instance.Instance
       
  2038         """
  1960         # TODO(Vek): Need to pass context in for access to auth_token
  2039         # TODO(Vek): Need to pass context in for access to auth_token
  1961         raise NotImplementedError()
  2040         raise NotImplementedError()
  1962 
  2041 
  1963     def suspend(self, instance):
       
  1964         """suspend the specified instance."""
       
  1965         # TODO(Vek): Need to pass context in for access to auth_token
       
  1966         raise NotImplementedError()
       
  1967 
       
  1968     def resume(self, context, instance, network_info, block_device_info=None):
  2042     def resume(self, context, instance, network_info, block_device_info=None):
  1969         """
  2043         """resume the specified instance.
  1970         resume the specified instance.
       
  1971 
  2044 
  1972         :param context: the context for the resume
  2045         :param context: the context for the resume
  1973         :param instance: the instance being resumed
  2046         :param instance: nova.objects.instance.Instance being resumed
  1974         :param network_info:
  2047         :param network_info:
  1975            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
  2048            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
  1976         :param block_device_info: instance volume block device info
  2049         :param block_device_info: instance volume block device info
  1977         """
  2050         """
  1978         raise NotImplementedError()
  2051         raise NotImplementedError()
  1979 
  2052 
  1980     def resume_state_on_host_boot(self, context, instance, network_info,
  2053     def resume_state_on_host_boot(self, context, instance, network_info,
  1981                                   block_device_info=None):
  2054                                   block_device_info=None):
  1982         """resume guest state when a host is booted."""
  2055         """resume guest state when a host is booted.
       
  2056 
       
  2057         :param instance: nova.objects.instance.Instance
       
  2058         """
  1983         name = instance['name']
  2059         name = instance['name']
  1984         zone = self._get_zone_by_name(name)
  2060         zone = self._get_zone_by_name(name)
  1985         if zone is None:
  2061         if zone is None:
  1986             raise exception.InstanceNotFound(instance_id=name)
  2062             raise exception.InstanceNotFound(instance_id=name)
  1987 
  2063 
  1993 
  2069 
  1994         self._power_on(instance)
  2070         self._power_on(instance)
  1995 
  2071 
  1996     def rescue(self, context, instance, network_info, image_meta,
  2072     def rescue(self, context, instance, network_info, image_meta,
  1997                rescue_password):
  2073                rescue_password):
  1998         """Rescue the specified instance."""
  2074         """Rescue the specified instance.
       
  2075 
       
  2076         :param instance: nova.objects.instance.Instance
       
  2077         """
       
  2078         raise NotImplementedError()
       
  2079 
       
  2080     def set_bootable(self, instance, is_bootable):
       
  2081         """Set the ability to power on/off an instance.
       
  2082 
       
  2083         :param instance: nova.objects.instance.Instance
       
  2084         """
  1999         raise NotImplementedError()
  2085         raise NotImplementedError()
  2000 
  2086 
  2001     def unrescue(self, instance, network_info):
  2087     def unrescue(self, instance, network_info):
  2002         """Unrescue the specified instance."""
  2088         """Unrescue the specified instance.
       
  2089 
       
  2090         :param instance: nova.objects.instance.Instance
       
  2091         """
  2003         # TODO(Vek): Need to pass context in for access to auth_token
  2092         # TODO(Vek): Need to pass context in for access to auth_token
  2004         raise NotImplementedError()
  2093         raise NotImplementedError()
  2005 
  2094 
  2006     def power_off(self, instance):
  2095     def power_off(self, instance, timeout=0, retry_interval=0):
  2007         """Power off the specified instance."""
  2096         """Power off the specified instance.
       
  2097 
       
  2098         :param instance: nova.objects.instance.Instance
       
  2099         :param timeout: time to wait for GuestOS to shutdown
       
  2100         :param retry_interval: How often to signal guest while
       
  2101                                waiting for it to shutdown
       
  2102         """
  2008         self._power_off(instance, 'SOFT')
  2103         self._power_off(instance, 'SOFT')
  2009 
  2104 
  2010     def power_on(self, context, instance, network_info,
  2105     def power_on(self, context, instance, network_info,
  2011                  block_device_info=None):
  2106                  block_device_info=None):
  2012         """Power on the specified instance."""
  2107         """Power on the specified instance.
       
  2108 
       
  2109         :param instance: nova.objects.instance.Instance
       
  2110         """
  2013         self._power_on(instance)
  2111         self._power_on(instance)
  2014 
  2112 
  2015     def soft_delete(self, instance):
  2113     def soft_delete(self, instance):
  2016         """Soft delete the specified instance."""
  2114         """Soft delete the specified instance.
       
  2115 
       
  2116         :param instance: nova.objects.instance.Instance
       
  2117         """
  2017         raise NotImplementedError()
  2118         raise NotImplementedError()
  2018 
  2119 
  2019     def restore(self, instance):
  2120     def restore(self, instance):
  2020         """Restore the specified instance."""
  2121         """Restore the specified instance.
       
  2122 
       
  2123         :param instance: nova.objects.instance.Instance
       
  2124         """
  2021         raise NotImplementedError()
  2125         raise NotImplementedError()
  2022 
  2126 
  2023     def _get_zpool_property(self, prop, zpool):
  2127     def _get_zpool_property(self, prop, zpool):
  2024         """Get the value of property from the zpool."""
  2128         """Get the value of property from the zpool."""
  2025         try:
  2129         try:
  2127         resources['cpu_info'] = host_stats['cpu_info']
  2231         resources['cpu_info'] = host_stats['cpu_info']
  2128         resources['disk_available_least'] = host_stats['disk_available_least']
  2232         resources['disk_available_least'] = host_stats['disk_available_least']
  2129         resources['supported_instances'] = host_stats['supported_instances']
  2233         resources['supported_instances'] = host_stats['supported_instances']
  2130         return resources
  2234         return resources
  2131 
  2235 
  2132     def pre_live_migration(self, ctxt, instance_ref, block_device_info,
  2236     def pre_live_migration(self, context, instance, block_device_info,
  2133                            network_info, disk_info, migrate_data=None):
  2237                            network_info, disk_info, migrate_data=None):
  2134         """Prepare an instance for live migration
  2238         """Prepare an instance for live migration
  2135 
  2239 
  2136         :param ctxt: security context
  2240         :param context: security context
  2137         :param instance_ref: instance object that will be migrated
  2241         :param instance: nova.objects.instance.Instance object
  2138         :param block_device_info: instance block device information
  2242         :param block_device_info: instance block device information
  2139         :param network_info: instance network information
  2243         :param network_info: instance network information
  2140         :param disk_info: instance disk information
  2244         :param disk_info: instance disk information
  2141         :param migrate_data: implementation specific data dict.
  2245         :param migrate_data: implementation specific data dict.
  2142         """
  2246         """
  2143         raise NotImplementedError()
  2247         raise NotImplementedError()
  2144 
  2248 
  2145     def live_migration(self, ctxt, instance_ref, dest,
  2249     def live_migration(self, context, instance, dest,
  2146                        post_method, recover_method, block_migration=False,
  2250                        post_method, recover_method, block_migration=False,
  2147                        migrate_data=None):
  2251                        migrate_data=None):
  2148         """Live migration of an instance to another host.
  2252         """Live migration of an instance to another host.
  2149 
  2253 
  2150         :params ctxt: security context
  2254         :param context: security context
  2151         :params instance_ref:
  2255         :param instance:
  2152             nova.db.sqlalchemy.models.Instance object
  2256             nova.db.sqlalchemy.models.Instance object
  2153             instance object that is migrated.
  2257             instance object that is migrated.
  2154         :params dest: destination host
  2258         :param dest: destination host
  2155         :params post_method:
  2259         :param post_method:
  2156             post operation method.
  2260             post operation method.
  2157             expected nova.compute.manager.post_live_migration.
  2261             expected nova.compute.manager._post_live_migration.
  2158         :params recover_method:
  2262         :param recover_method:
  2159             recovery method when any exception occurs.
  2263             recovery method when any exception occurs.
  2160             expected nova.compute.manager.recover_live_migration.
  2264             expected nova.compute.manager._rollback_live_migration.
  2161         :params block_migration: if true, migrate VM disk.
  2265         :param block_migration: if true, migrate VM disk.
  2162         :params migrate_data: implementation specific params.
  2266         :param migrate_data: implementation specific params.
  2163 
  2267 
  2164         """
  2268         """
  2165         raise NotImplementedError()
  2269         raise NotImplementedError()
  2166 
  2270 
  2167     def post_live_migration(self, ctxt, instance_ref, block_device_info):
  2271     def rollback_live_migration_at_destination(self, context, instance,
       
  2272                                                network_info,
       
  2273                                                block_device_info,
       
  2274                                                destroy_disks=True,
       
  2275                                                migrate_data=None):
       
  2276         """Clean up destination node after a failed live migration.
       
  2277 
       
  2278         :param context: security context
       
  2279         :param instance: instance object that was being migrated
       
  2280         :param network_info: instance network information
       
  2281         :param block_device_info: instance block device information
       
  2282         :param destroy_disks:
       
  2283             if true, destroy disks at destination during cleanup
       
  2284         :param migrate_data: implementation specific params
       
  2285 
       
  2286         """
       
  2287         raise NotImplementedError()
       
  2288 
       
  2289     def post_live_migration(self, context, instance, block_device_info,
       
  2290                             migrate_data=None):
  2168         """Post operation of live migration at source host.
  2291         """Post operation of live migration at source host.
  2169 
  2292 
  2170         :param ctxt: security contet
  2293         :param context: security context
  2171         :instance_ref: instance object that was migrated
  2294         :instance: instance object that was migrated
  2172         :block_device_info: instance block device information
  2295         :block_device_info: instance block device information
       
  2296         :param migrate_data: if not None, it is a dict which has data
  2173         """
  2297         """
  2174         pass
  2298         pass
  2175 
  2299 
  2176     def post_live_migration_at_destination(self, ctxt, instance_ref,
  2300     def post_live_migration_at_source(self, context, instance, network_info):
       
  2301         """Unplug VIFs from networks at source.
       
  2302 
       
  2303         :param context: security context
       
  2304         :param instance: instance object reference
       
  2305         :param network_info: instance network information
       
  2306         """
       
  2307         raise NotImplementedError(_("Hypervisor driver does not support "
       
  2308                                     "post_live_migration_at_source method"))
       
  2309 
       
  2310     def post_live_migration_at_destination(self, context, instance,
  2177                                            network_info,
  2311                                            network_info,
  2178                                            block_migration=False,
  2312                                            block_migration=False,
  2179                                            block_device_info=None):
  2313                                            block_device_info=None):
  2180         """Post operation of live migration at destination host.
  2314         """Post operation of live migration at destination host.
  2181 
  2315 
  2182         :param ctxt: security context
  2316         :param context: security context
  2183         :param instance_ref: instance object that is migrated
  2317         :param instance: instance object that is migrated
  2184         :param network_info: instance network information
  2318         :param network_info: instance network information
  2185         :param block_migration: if true, post operation of block_migration.
  2319         :param block_migration: if true, post operation of block_migration.
  2186         """
  2320         """
  2187         raise NotImplementedError()
  2321         raise NotImplementedError()
  2188 
  2322 
  2189     def check_instance_shared_storage_local(self, ctxt, instance):
  2323     def check_instance_shared_storage_local(self, context, instance):
  2190         """Check if instance files located on shared storage.
  2324         """Check if instance files located on shared storage.
  2191 
  2325 
  2192         This runs check on the destination host, and then calls
  2326         This runs check on the destination host, and then calls
  2193         back to the source host to check the results.
  2327         back to the source host to check the results.
  2194 
  2328 
  2195         :param ctxt: security context
  2329         :param context: security context
  2196         :param instance: nova.db.sqlalchemy.models.Instance
  2330         :param instance: nova.db.sqlalchemy.models.Instance
  2197         """
  2331         """
  2198         raise NotImplementedError()
  2332         raise NotImplementedError()
  2199 
  2333 
  2200     def check_instance_shared_storage_remote(self, ctxt, data):
  2334     def check_instance_shared_storage_remote(self, context, data):
  2201         """Check if instance files located on shared storage.
  2335         """Check if instance files located on shared storage.
  2202 
  2336 
  2203         :param context: security context
  2337         :param context: security context
  2204         :param data: result of check_instance_shared_storage_local
  2338         :param data: result of check_instance_shared_storage_local
  2205         """
  2339         """
  2206         raise NotImplementedError()
  2340         raise NotImplementedError()
  2207 
  2341 
  2208     def check_instance_shared_storage_cleanup(self, ctxt, data):
  2342     def check_instance_shared_storage_cleanup(self, context, data):
  2209         """Do cleanup on host after check_instance_shared_storage calls
  2343         """Do cleanup on host after check_instance_shared_storage calls
  2210 
  2344 
  2211         :param ctxt: security context
  2345         :param context: security context
  2212         :param data: result of check_instance_shared_storage_local
  2346         :param data: result of check_instance_shared_storage_local
  2213         """
  2347         """
  2214         pass
  2348         pass
  2215 
  2349 
  2216     def check_can_live_migrate_destination(self, ctxt, instance_ref,
  2350     def check_can_live_migrate_destination(self, context, instance,
  2217                                            src_compute_info, dst_compute_info,
  2351                                            src_compute_info, dst_compute_info,
  2218                                            block_migration=False,
  2352                                            block_migration=False,
  2219                                            disk_over_commit=False):
  2353                                            disk_over_commit=False):
  2220         """Check if it is possible to execute live migration.
  2354         """Check if it is possible to execute live migration.
  2221 
  2355 
  2222         This runs checks on the destination host, and then calls
  2356         This runs checks on the destination host, and then calls
  2223         back to the source host to check the results.
  2357         back to the source host to check the results.
  2224 
  2358 
  2225         :param ctxt: security context
  2359         :param context: security context
  2226         :param instance_ref: nova.db.sqlalchemy.models.Instance
  2360         :param instance: nova.db.sqlalchemy.models.Instance
  2227         :param src_compute_info: Info about the sending machine
  2361         :param src_compute_info: Info about the sending machine
  2228         :param dst_compute_info: Info about the receiving machine
  2362         :param dst_compute_info: Info about the receiving machine
  2229         :param block_migration: if true, prepare for block migration
  2363         :param block_migration: if true, prepare for block migration
  2230         :param disk_over_commit: if true, allow disk over commit
  2364         :param disk_over_commit: if true, allow disk over commit
  2231         :returns: a dict containing migration info (hypervisor-dependent)
  2365         :returns: a dict containing migration info (hypervisor-dependent)
  2232         """
  2366         """
  2233         raise NotImplementedError()
  2367         raise NotImplementedError()
  2234 
  2368 
  2235     def check_can_live_migrate_destination_cleanup(self, ctxt,
  2369     def check_can_live_migrate_destination_cleanup(self, context,
  2236                                                    dest_check_data):
  2370                                                    dest_check_data):
  2237         """Do required cleanup on dest host after check_can_live_migrate calls
  2371         """Do required cleanup on dest host after check_can_live_migrate calls
  2238 
  2372 
  2239         :param ctxt: security context
  2373         :param context: security context
  2240         :param dest_check_data: result of check_can_live_migrate_destination
  2374         :param dest_check_data: result of check_can_live_migrate_destination
  2241         """
  2375         """
  2242         raise NotImplementedError()
  2376         raise NotImplementedError()
  2243 
  2377 
  2244     def check_can_live_migrate_source(self, ctxt, instance_ref,
  2378     def check_can_live_migrate_source(self, context, instance,
  2245                                       dest_check_data):
  2379                                       dest_check_data):
  2246         """Check if it is possible to execute live migration.
  2380         """Check if it is possible to execute live migration.
  2247 
  2381 
  2248         This checks if the live migration can succeed, based on the
  2382         This checks if the live migration can succeed, based on the
  2249         results from check_can_live_migrate_destination.
  2383         results from check_can_live_migrate_destination.
  2250 
  2384 
  2251         :param context: security context
  2385         :param context: security context
  2252         :param instance_ref: nova.db.sqlalchemy.models.Instance
  2386         :param instance: nova.db.sqlalchemy.models.Instance
  2253         :param dest_check_data: result of check_can_live_migrate_destination
  2387         :param dest_check_data: result of check_can_live_migrate_destination
  2254         :returns: a dict containing migration info (hypervisor-dependent)
  2388         :returns: a dict containing migration info (hypervisor-dependent)
       
  2389         """
       
  2390         raise NotImplementedError()
       
  2391 
       
  2392     def get_instance_disk_info(self, instance_name,
       
  2393                                block_device_info=None):
       
  2394         """Retrieve information about actual disk sizes of an instance.
       
  2395 
       
  2396         :param instance_name:
       
  2397             name of a nova instance as returned by list_instances()
       
  2398         :param block_device_info:
       
  2399             Optional; Can be used to filter out devices which are
       
  2400             actually volumes.
       
  2401         :return:
       
  2402             json strings with below format::
       
  2403 
       
  2404                 "[{'path':'disk',
       
  2405                    'type':'raw',
       
  2406                    'virt_disk_size':'10737418240',
       
  2407                    'backing_file':'backing_file',
       
  2408                    'disk_size':'83886080'
       
  2409                    'over_committed_disk_size':'10737418240'},
       
  2410                    ...]"
  2255         """
  2411         """
  2256         raise NotImplementedError()
  2412         raise NotImplementedError()
  2257 
  2413 
  2258     def refresh_security_group_rules(self, security_group_id):
  2414     def refresh_security_group_rules(self, security_group_id):
  2259         """This method is called after a change to security groups.
  2415         """This method is called after a change to security groups.
  2320 
  2476 
  2321         """
  2477         """
  2322         # TODO(Vek): Need to pass context in for access to auth_token
  2478         # TODO(Vek): Need to pass context in for access to auth_token
  2323         raise NotImplementedError()
  2479         raise NotImplementedError()
  2324 
  2480 
       
  2481     def refresh_instance_security_rules(self, instance):
       
  2482         """Refresh security group rules
       
  2483 
       
  2484         Gets called when an instance gets added to or removed from
       
  2485         the security group the instance is a member of or if the
       
  2486         group gains or loses a rule.
       
  2487         """
       
  2488         raise NotImplementedError()
       
  2489 
  2325     def reset_network(self, instance):
  2490     def reset_network(self, instance):
  2326         """reset networking for specified instance."""
  2491         """reset networking for specified instance."""
  2327         # TODO(Vek): Need to pass context in for access to auth_token
  2492         # TODO(Vek): Need to pass context in for access to auth_token
  2328         pass
  2493         pass
  2329 
  2494 
  2330     def ensure_filtering_rules_for_instance(self, instance_ref, network_info):
  2495     def ensure_filtering_rules_for_instance(self, instance, network_info):
  2331         """Setting up filtering rules and waiting for its completion.
  2496         """Setting up filtering rules and waiting for its completion.
  2332 
  2497 
  2333         To migrate an instance, filtering rules to hypervisors
  2498         To migrate an instance, filtering rules to hypervisors
  2334         and firewalls are inevitable on destination host.
  2499         and firewalls are inevitable on destination host.
  2335         ( Waiting only for filtering rules to hypervisor,
  2500         ( Waiting only for filtering rules to hypervisor,
  2345 
  2510 
  2346         Don't use thread for this method since migration should
  2511         Don't use thread for this method since migration should
  2347         not be started when setting-up filtering rules operations
  2512         not be started when setting-up filtering rules operations
  2348         are not completed.
  2513         are not completed.
  2349 
  2514 
  2350         :params instance_ref: nova.db.sqlalchemy.models.Instance object
  2515         :param instance: nova.objects.instance.Instance object
  2351 
  2516 
  2352         """
  2517         """
  2353         # TODO(Vek): Need to pass context in for access to auth_token
  2518         # TODO(Vek): Need to pass context in for access to auth_token
  2354         raise NotImplementedError()
  2519         raise NotImplementedError()
  2355 
  2520 
  2364     def unfilter_instance(self, instance, network_info):
  2529     def unfilter_instance(self, instance, network_info):
  2365         """Stop filtering instance."""
  2530         """Stop filtering instance."""
  2366         # TODO(Vek): Need to pass context in for access to auth_token
  2531         # TODO(Vek): Need to pass context in for access to auth_token
  2367         raise NotImplementedError()
  2532         raise NotImplementedError()
  2368 
  2533 
  2369     def set_admin_password(self, context, instance_id, new_pass=None):
  2534     def set_admin_password(self, instance, new_pass):
  2370         """
  2535         """Set the root password on the specified instance.
  2371         Set the root password on the specified instance.
  2536 
  2372 
  2537         :param instance: nova.objects.instance.Instance
  2373         The first parameter is an instance of nova.compute.service.Instance,
  2538         :param new_password: the new password
  2374         and so the instance is being specified as instance.name. The second
       
  2375         parameter is the value of the new password.
       
  2376         """
  2539         """
  2377         raise NotImplementedError()
  2540         raise NotImplementedError()
  2378 
  2541 
  2379     def inject_file(self, instance, b64_path, b64_contents):
  2542     def inject_file(self, instance, b64_path, b64_contents):
  2380         """
  2543         """Writes a file on the specified instance.
  2381         Writes a file on the specified instance.
       
  2382 
  2544 
  2383         The first parameter is an instance of nova.compute.service.Instance,
  2545         The first parameter is an instance of nova.compute.service.Instance,
  2384         and so the instance is being specified as instance.name. The second
  2546         and so the instance is being specified as instance.name. The second
  2385         parameter is the base64-encoded path to which the file is to be
  2547         parameter is the base64-encoded path to which the file is to be
  2386         written on the instance; the third is the contents of the file, also
  2548         written on the instance; the third is the contents of the file, also
  2387         base64-encoded.
  2549         base64-encoded.
       
  2550 
       
  2551         NOTE(russellb) This method is deprecated and will be removed once it
       
  2552         can be removed from nova.compute.manager.
  2388         """
  2553         """
  2389         # TODO(Vek): Need to pass context in for access to auth_token
  2554         # TODO(Vek): Need to pass context in for access to auth_token
  2390         raise NotImplementedError()
  2555         raise NotImplementedError()
  2391 
  2556 
  2392     def change_instance_metadata(self, context, instance, diff):
  2557     def change_instance_metadata(self, context, instance, diff):
  2393         """
  2558         """Applies a diff to the instance metadata.
  2394         Applies a diff to the instance metadata.
       
  2395 
  2559 
  2396         This is an optional driver method which is used to publish
  2560         This is an optional driver method which is used to publish
  2397         changes to the instance's metadata to the hypervisor.  If the
  2561         changes to the instance's metadata to the hypervisor.  If the
  2398         hypervisor has no means of publishing the instance metadata to
  2562         hypervisor has no means of publishing the instance metadata to
  2399         the instance, then this method should not be implemented.
  2563         the instance, then this method should not be implemented.
       
  2564 
       
  2565         :param context: security context
       
  2566         :param instance: nova.objects.instance.Instance
  2400         """
  2567         """
  2401         pass
  2568         pass
  2402 
  2569 
  2403     def inject_network_info(self, instance, nw_info):
  2570     def inject_network_info(self, instance, nw_info):
  2404         """inject network info for specified instance."""
  2571         """inject network info for specified instance."""
  2435         """Returns the result of calling "uptime" on the target host."""
  2602         """Returns the result of calling "uptime" on the target host."""
  2436         # TODO(Vek): Need to pass context in for access to auth_token
  2603         # TODO(Vek): Need to pass context in for access to auth_token
  2437         return utils.execute('/usr/bin/uptime')[0]
  2604         return utils.execute('/usr/bin/uptime')[0]
  2438 
  2605 
  2439     def plug_vifs(self, instance, network_info):
  2606     def plug_vifs(self, instance, network_info):
  2440         """Plug VIFs into networks."""
  2607         """Plug VIFs into networks.
       
  2608 
       
  2609         :param instance: nova.objects.instance.Instance
       
  2610         """
  2441         # TODO(Vek): Need to pass context in for access to auth_token
  2611         # TODO(Vek): Need to pass context in for access to auth_token
  2442         pass
  2612         pass
  2443 
  2613 
  2444     def unplug_vifs(self, instance, network_info):
  2614     def unplug_vifs(self, instance, network_info):
  2445         """Unplug VIFs from networks."""
  2615         """Unplug VIFs from networks.
       
  2616 
       
  2617         :param instance: nova.objects.instance.Instance
       
  2618         """
  2446         raise NotImplementedError()
  2619         raise NotImplementedError()
  2447 
  2620 
  2448     def get_host_stats(self, refresh=False):
  2621     def get_host_stats(self, refresh=False):
  2449         """Return currently known host stats.
  2622         """Return currently known host stats.
  2450 
  2623 
  2460         """
  2633         """
  2461         if refresh or not self._host_stats:
  2634         if refresh or not self._host_stats:
  2462             self._update_host_stats()
  2635             self._update_host_stats()
  2463         return self._host_stats
  2636         return self._host_stats
  2464 
  2637 
       
  2638     def get_host_cpu_stats(self):
       
  2639         """Get the currently known host CPU stats.
       
  2640 
       
  2641         :returns: a dict containing the CPU stat info, eg:
       
  2642 
       
  2643             | {'kernel': kern,
       
  2644             |  'idle': idle,
       
  2645             |  'user': user,
       
  2646             |  'iowait': wait,
       
  2647             |   'frequency': freq},
       
  2648 
       
  2649                   where kern and user indicate the cumulative CPU time
       
  2650                   (nanoseconds) spent by kernel and user processes
       
  2651                   respectively, idle indicates the cumulative idle CPU time
       
  2652                   (nanoseconds), wait indicates the cumulative I/O wait CPU
       
  2653                   time (nanoseconds), since the host is booting up; freq
       
  2654                   indicates the current CPU frequency (MHz). All values are
       
  2655                   long integers.
       
  2656 
       
  2657         """
       
  2658         raise NotImplementedError()
       
  2659 
  2465     def block_stats(self, instance_name, disk_id):
  2660     def block_stats(self, instance_name, disk_id):
  2466         """
  2661         """Return performance counters associated with the given disk_id on the
  2467         Return performance counters associated with the given disk_id on the
       
  2468         given instance_name.  These are returned as [rd_req, rd_bytes, wr_req,
  2662         given instance_name.  These are returned as [rd_req, rd_bytes, wr_req,
  2469         wr_bytes, errs], where rd indicates read, wr indicates write, req is
  2663         wr_bytes, errs], where rd indicates read, wr indicates write, req is
  2470         the total number of I/O requests made, bytes is the total number of
  2664         the total number of I/O requests made, bytes is the total number of
  2471         bytes transferred, and errs is the number of requests held up due to a
  2665         bytes transferred, and errs is the number of requests held up due to a
  2472         full pipeline.
  2666         full pipeline.
  2481         Note that this function takes an instance ID.
  2675         Note that this function takes an instance ID.
  2482         """
  2676         """
  2483         raise NotImplementedError()
  2677         raise NotImplementedError()
  2484 
  2678 
  2485     def interface_stats(self, instance_name, iface_id):
  2679     def interface_stats(self, instance_name, iface_id):
  2486         """
  2680         """Return performance counters associated with the given iface_id
  2487         Return performance counters associated with the given iface_id on the
  2681         on the given instance_id.  These are returned as [rx_bytes, rx_packets,
  2488         given instance_id.  These are returned as [rx_bytes, rx_packets,
       
  2489         rx_errs, rx_drop, tx_bytes, tx_packets, tx_errs, tx_drop], where rx
  2682         rx_errs, rx_drop, tx_bytes, tx_packets, tx_errs, tx_drop], where rx
  2490         indicates receive, tx indicates transmit, bytes and packets indicate
  2683         indicates receive, tx indicates transmit, bytes and packets indicate
  2491         the total number of bytes or packets transferred, and errs and dropped
  2684         the total number of bytes or packets transferred, and errs and dropped
  2492         is the total number of packets failed / dropped.
  2685         is the total number of packets failed / dropped.
  2493 
  2686 
  2499         unused.
  2692         unused.
  2500 
  2693 
  2501         Note that this function takes an instance ID.
  2694         Note that this function takes an instance ID.
  2502         """
  2695         """
  2503         raise NotImplementedError()
  2696         raise NotImplementedError()
       
  2697 
       
  2698     def deallocate_networks_on_reschedule(self, instance):
       
  2699         """Does the driver want networks deallocated on reschedule?"""
       
  2700         return False
  2504 
  2701 
  2505     def macs_for_instance(self, instance):
  2702     def macs_for_instance(self, instance):
  2506         """What MAC addresses must this instance have?
  2703         """What MAC addresses must this instance have?
  2507 
  2704 
  2508         Some hypervisors (such as bare metal) cannot do freeform virtualisation
  2705         Some hypervisors (such as bare metal) cannot do freeform virtualisation
  2543 
  2740 
  2544         Note that the format of the return value is specific to Quantum
  2741         Note that the format of the return value is specific to Quantum
  2545         client API.
  2742         client API.
  2546 
  2743 
  2547         :return: None, or a set of DHCP options, eg:
  2744         :return: None, or a set of DHCP options, eg:
  2548                  [{'opt_name': 'bootfile-name',
  2745 
  2549                    'opt_value': '/tftpboot/path/to/config'},
  2746              |    [{'opt_name': 'bootfile-name',
  2550                   {'opt_name': 'server-ip-address',
  2747              |      'opt_value': '/tftpboot/path/to/config'},
  2551                    'opt_value': '1.2.3.4'},
  2748              |     {'opt_name': 'server-ip-address',
  2552                   {'opt_name': 'tftp-server',
  2749              |      'opt_value': '1.2.3.4'},
  2553                    'opt_value': '1.2.3.4'}
  2750              |     {'opt_name': 'tftp-server',
  2554                  ]
  2751              |      'opt_value': '1.2.3.4'}
       
  2752              |    ]
       
  2753 
  2555         """
  2754         """
  2556         pass
  2755         pass
  2557 
  2756 
  2558     def manage_image_cache(self, context, all_instances):
  2757     def manage_image_cache(self, context, all_instances):
  2559         """
  2758         """Manage the driver's local image cache.
  2560         Manage the driver's local image cache.
       
  2561 
  2759 
  2562         Some drivers chose to cache images for instances on disk. This method
  2760         Some drivers chose to cache images for instances on disk. This method
  2563         is an opportunity to do management of that cache which isn't directly
  2761         is an opportunity to do management of that cache which isn't directly
  2564         related to other calls into the driver. The prime example is to clean
  2762         related to other calls into the driver. The prime example is to clean
  2565         the cache and remove images which are no longer of interest.
  2763         the cache and remove images which are no longer of interest.
       
  2764 
       
  2765         :param instances: nova.objects.instance.InstanceList
  2566         """
  2766         """
  2567         pass
  2767         pass
  2568 
  2768 
  2569     def add_to_aggregate(self, context, aggregate, host, **kwargs):
  2769     def add_to_aggregate(self, context, aggregate, host, **kwargs):
  2570         """Add a compute host to an aggregate."""
  2770         """Add a compute host to an aggregate."""
  2584         """Get connector information for the instance for attaching to volumes.
  2784         """Get connector information for the instance for attaching to volumes.
  2585 
  2785 
  2586         Connector information is a dictionary representing the ip of the
  2786         Connector information is a dictionary representing the ip of the
  2587         machine that will be making the connection, the name of the iscsi
  2787         machine that will be making the connection, the name of the iscsi
  2588         initiator, the WWPN and WWNN values of the Fibre Channel initiator,
  2788         initiator, the WWPN and WWNN values of the Fibre Channel initiator,
  2589         and the hostname of the machine as follows:
  2789         and the hostname of the machine as follows::
  2590 
  2790 
  2591             {
  2791             {
  2592                 'ip': ip,
  2792                 'ip': ip,
  2593                 'initiator': initiator,
  2793                 'initiator': initiator,
  2594                 'wwnns': wwnns,
  2794                 'wwnns': wwnns,
  2595                 'wwpns': wwpns,
  2795                 'wwpns': wwpns,
  2596                 'host': hostname
  2796                 'host': hostname
  2597             }
  2797             }
       
  2798 
  2598         """
  2799         """
  2599         connector = {'ip': self.get_host_ip_addr(),
  2800         connector = {'ip': self.get_host_ip_addr(),
  2600                      'host': CONF.host}
  2801                      'host': CONF.host}
  2601         if not self._initiator:
  2802         if not self._initiator:
  2602             self._initiator = self._get_iscsi_initiator()
  2803             self._initiator = self._get_iscsi_initiator()
  2654         return {}
  2855         return {}
  2655 
  2856 
  2656     def instance_on_disk(self, instance):
  2857     def instance_on_disk(self, instance):
  2657         """Checks access of instance files on the host.
  2858         """Checks access of instance files on the host.
  2658 
  2859 
  2659         :param instance: instance to lookup
  2860         :param instance: nova.objects.instance.Instance to lookup
  2660 
  2861 
  2661         Returns True if files of an instance with the supplied ID accessible on
  2862         Returns True if files of an instance with the supplied ID accessible on
  2662         the host, False otherwise.
  2863         the host, False otherwise.
  2663 
  2864 
  2664         .. note::
  2865         .. note::
  2685         compute manager to dispatch the event. This
  2886         compute manager to dispatch the event. This
  2686         must only be invoked from a green thread.
  2887         must only be invoked from a green thread.
  2687         """
  2888         """
  2688 
  2889 
  2689         if not self._compute_event_callback:
  2890         if not self._compute_event_callback:
  2690             LOG.debug(_("Discarding event %s") % str(event))
  2891             LOG.debug("Discarding event %s", str(event))
  2691             return
  2892             return
  2692 
  2893 
  2693         if not isinstance(event, virtevent.Event):
  2894         if not isinstance(event, virtevent.Event):
  2694             raise ValueError(
  2895             raise ValueError(
  2695                 _("Event must be an instance of nova.virt.event.Event"))
  2896                 _("Event must be an instance of nova.virt.event.Event"))
  2696 
  2897 
  2697         try:
  2898         try:
  2698             LOG.debug(_("Emitting event %s") % str(event))
  2899             LOG.debug("Emitting event %s", str(event))
  2699             self._compute_event_callback(event)
  2900             self._compute_event_callback(event)
  2700         except Exception as ex:
  2901         except Exception as ex:
  2701             LOG.error(_("Exception dispatching event %(event)s: %(ex)s"),
  2902             LOG.error(_("Exception dispatching event %(event)s: %(ex)s"),
  2702                       {'event': event, 'ex': ex})
  2903                       {'event': event, 'ex': ex})
  2703 
  2904 
  2704     def delete_instance_files(self, instance):
  2905     def delete_instance_files(self, instance):
  2705         """Delete any lingering instance files for an instance.
  2906         """Delete any lingering instance files for an instance.
  2706 
  2907 
       
  2908         :param instance: nova.objects.instance.Instance
  2707         :returns: True if the instance was deleted from disk, False otherwise.
  2909         :returns: True if the instance was deleted from disk, False otherwise.
  2708         """
  2910         """
  2709         return True
  2911         return True
  2710 
  2912 
  2711     @property
  2913     @property
  2712     def need_legacy_block_device_info(self):
  2914     def need_legacy_block_device_info(self):
  2713         """Tell the caller if the driver requires legacy block device info.
  2915         """Tell the caller if the driver requires legacy block device info.
  2714 
  2916 
  2715         Tell the caller weather we expect the legacy format of block
  2917         Tell the caller whether we expect the legacy format of block
  2716         device info to be passed in to methods that expect it.
  2918         device info to be passed in to methods that expect it.
  2717         """
  2919         """
  2718         return True
  2920         return True
  2719 
  2921 
  2720     def volume_snapshot_create(self, context, instance, volume_id,
  2922     def volume_snapshot_create(self, context, instance, volume_id,
  2721                                create_info):
  2923                                create_info):
  2722         """
  2924         """Snapshots volumes attached to a specified instance.
  2723         Snapshots volumes attached to a specified instance.
       
  2724 
  2925 
  2725         :param context: request context
  2926         :param context: request context
  2726         :param instance: Instance object that has the volume attached
  2927         :param instance: nova.objects.instance.Instance that has the volume
       
  2928                attached
  2727         :param volume_id: Volume to be snapshotted
  2929         :param volume_id: Volume to be snapshotted
  2728         :param create_info: The data needed for nova to be able to attach
  2930         :param create_info: The data needed for nova to be able to attach
  2729                to the volume.  This is the same data format returned by
  2931                to the volume.  This is the same data format returned by
  2730                Cinder's initialize_connection() API call.  In the case of
  2932                Cinder's initialize_connection() API call.  In the case of
  2731                doing a snapshot, it is the image file Cinder expects to be
  2933                doing a snapshot, it is the image file Cinder expects to be
  2735         """
  2937         """
  2736         raise NotImplementedError()
  2938         raise NotImplementedError()
  2737 
  2939 
  2738     def volume_snapshot_delete(self, context, instance, volume_id,
  2940     def volume_snapshot_delete(self, context, instance, volume_id,
  2739                                snapshot_id, delete_info):
  2941                                snapshot_id, delete_info):
  2740         """
  2942         """Snapshots volumes attached to a specified instance.
  2741         Snapshots volumes attached to a specified instance.
       
  2742 
  2943 
  2743         :param context: request context
  2944         :param context: request context
  2744         :param instance: Instance object that has the volume attached
  2945         :param instance: nova.objects.instance.Instance that has the volume
       
  2946                attached
  2745         :param volume_id: Attached volume associated with the snapshot
  2947         :param volume_id: Attached volume associated with the snapshot
  2746         :param snapshot_id: The snapshot to delete.
  2948         :param snapshot_id: The snapshot to delete.
  2747         :param delete_info: Volume backend technology specific data needed to
  2949         :param delete_info: Volume backend technology specific data needed to
  2748                be able to complete the snapshot.  For example, in the case of
  2950                be able to complete the snapshot.  For example, in the case of
  2749                qcow2 backed snapshots, this would include the file being
  2951                qcow2 backed snapshots, this would include the file being
  2757 
  2959 
  2758     def default_device_names_for_instance(self, instance, root_device_name,
  2960     def default_device_names_for_instance(self, instance, root_device_name,
  2759                                           *block_device_lists):
  2961                                           *block_device_lists):
  2760         """Default the missing device names in the block device mapping."""
  2962         """Default the missing device names in the block device mapping."""
  2761         raise NotImplementedError()
  2963         raise NotImplementedError()
       
  2964 
       
  2965     def is_supported_fs_format(self, fs_type):
       
  2966         """Check whether the file format is supported by this driver
       
  2967 
       
  2968         :param fs_type: the file system type to be checked,
       
  2969                         the validate values are defined at disk API module.
       
  2970         """
       
  2971         # NOTE(jichenjc): Return False here so that every hypervisor
       
  2972         #                 need to define their supported file system
       
  2973         #                 type and implement this function at their
       
  2974         #                 virt layer.
       
  2975         return False