components/openstack/nova/files/solariszones/driver.py
changeset 3998 5bd484384122
parent 3652 7e731a1b0b39
child 4099 306bbc1c18bb
--- a/components/openstack/nova/files/solariszones/driver.py	Fri Mar 20 03:13:26 2015 -0700
+++ b/components/openstack/nova/files/solariszones/driver.py	Thu Mar 19 14:41:20 2015 -0700
@@ -1,9 +1,7 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
 # Copyright 2011 Justin Santa Barbara
 # All Rights Reserved.
 #
-# Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
@@ -45,13 +43,15 @@
 from nova.compute import power_state
 from nova.compute import task_states
 from nova.compute import vm_states
+from nova.console import type as ctype
 from nova import conductor
 from nova import context as nova_context
 from nova import exception
+from nova.i18n import _
 from nova.image import glance
 from nova.network import neutronv2
+from nova.objects import flavor as flavor_obj
 from nova.openstack.common import fileutils
-from nova.openstack.common.gettextutils import _
 from nova.openstack.common import jsonutils
 from nova.openstack.common import log as logging
 from nova.openstack.common import loopingcall
@@ -282,7 +282,7 @@
     capabilities = {
         "has_imagecache": False,
         "supports_recreate": False,
-    }
+        }
 
     def __init__(self, virtapi):
         self.virtapi = virtapi
@@ -295,10 +295,24 @@
         self._initiator = None
         self._install_engine = None
         self._pagesize = os.sysconf('SC_PAGESIZE')
+        self._rad_connection = None
         self._uname = os.uname()
         self._validated_archives = list()
         self._volume_api = volume.API()
 
+    @property
+    def rad_connection(self):
+        if self._rad_connection is None:
+            self._rad_connection = rad.connect.connect_unix()
+        else:
+            # taken from rad.connect.RadConnection.__repr__ to look for a
+            # closed connection
+            if self._rad_connection._closed is not None:
+                # the RAD connection has been lost.  Reconnect to RAD
+                self._rad_connection = rad.connect.connect_unix()
+
+        return self._rad_connection
+
     def _init_rad(self):
         """Connect to RAD providers for kernel statistics and Solaris
         Zones. By connecting to the local rad(1M) service through a
@@ -307,11 +321,8 @@
         via zonemgr(3RAD).
         """
 
-        # TODO(dcomay): Arrange to call this in the event of losing the
-        # connection to RAD.
         try:
-            self._rad_instance = rad.connect.connect_unix()
-            self._kstat_control = self._rad_instance.get_object(
+            self._kstat_control = self.rad_connection.get_object(
                 kstat.Control())
         except Exception as reason:
             msg = (_('Unable to connect to svc:/system/rad:local: %s')
@@ -325,6 +336,12 @@
         # TODO(Vek): Need to pass context in for access to auth_token
         self._init_rad()
 
+    def cleanup_host(self, host):
+        """Clean up anything that is necessary for the driver gracefully stop,
+        including ending remote sessions. This is optional.
+        """
+        pass
+
     def _get_fc_hbas(self):
         """Get Fibre Channel HBA information."""
         if self._fc_hbas:
@@ -420,7 +437,7 @@
     def _get_zone_by_name(self, name):
         """Return a Solaris Zones object via RAD by name."""
         try:
-            zone = self._rad_instance.get_object(
+            zone = self.rad_connection.get_object(
                 zonemgr.Zone(), rad.client.ADRGlobPattern({'name': name}))
         except rad.client.NotFoundError:
             return None
@@ -440,7 +457,7 @@
         """Return the maximum memory in KBytes allowed."""
         max_mem = lookup_resource_property(zone, 'capped-memory', 'physical')
         if max_mem is not None:
-            return strutils.to_bytes(max_mem) / 1024
+            return strutils.string_to_bytes("%sB" % max_mem) / 1024
 
         # If physical property in capped-memory doesn't exist, this may
         # represent a non-global zone so just return the system's total
@@ -499,7 +516,7 @@
         }
         try:
             self._kstat_control.update()
-            kstat_object = self._rad_instance.get_object(
+            kstat_object = self.rad_connection.get_object(
                 kstat.Kstat(), rad.client.ADRGlobPattern(pattern))
         except Exception as reason:
             LOG.info(_("Unable to retrieve kstat object '%s:%s:%s' of class "
@@ -528,6 +545,8 @@
     def get_info(self, instance):
         """Get the current status of an instance, by name (not ID!)
 
+        :param instance: nova.objects.instance.Instance object
+
         Returns a dict containing:
 
         :state:           the running state, one of the power_state codes
@@ -566,10 +585,10 @@
         """
         return len(self.list_instances())
 
-    def instance_exists(self, instance_id):
+    def instance_exists(self, instance):
         """Checks existence of an instance on the host.
 
-        :param instance_id: The ID / name of the instance to lookup
+        :param instance: The instance to lookup
 
         Returns True if an instance with the supplied ID exists on
         the host, False otherwise.
@@ -581,7 +600,10 @@
             encouraged to override this method with something more
             efficient.
         """
-        return instance_id in self.list_instances()
+        try:
+            return instance.uuid in self.list_instance_uuids()
+        except NotImplementedError:
+            return instance.name in self.list_instances()
 
     def estimate_instance_overhead(self, instance_info):
         """Estimate the virtualization overhead required to build an instance
@@ -597,24 +619,63 @@
 
     def _get_list_zone_object(self):
         """Return a list of all Solaris Zones objects via RAD."""
-        return self._rad_instance.list_objects(zonemgr.Zone())
+        return self.rad_connection.list_objects(zonemgr.Zone())
 
     def list_instances(self):
-        """
-        Return the names of all the instances known to the virtualization
+        """Return the names of all the instances known to the virtualization
         layer, as a list.
         """
         # TODO(Vek): Need to pass context in for access to auth_token
         instances_list = []
         for zone in self._get_list_zone_object():
-            instances_list.append(self._rad_instance.get_object(zone).name)
-
+            instances_list.append(self.rad_connection.get_object(zone).name)
         return instances_list
 
     def list_instance_uuids(self):
+        """Return the UUIDS of all the instances known to the virtualization
+        layer, as a list.
         """
-        Return the UUIDS of all the instances known to the virtualization
-        layer, as a list.
+        raise NotImplementedError()
+
+    def rebuild(self, context, instance, image_meta, injected_files,
+                admin_password, bdms, detach_block_devices,
+                attach_block_devices, network_info=None,
+                recreate=False, block_device_info=None,
+                preserve_ephemeral=False):
+        """Destroy and re-make this instance.
+
+        A 'rebuild' effectively purges all existing data from the system and
+        remakes the VM with given 'metadata' and 'personalities'.
+
+        This base class method shuts down the VM, detaches all block devices,
+        then spins up the new VM afterwards. It may be overridden by
+        hypervisors that need to - e.g. for optimisations, or when the 'VM'
+        is actually proxied and needs to be held across the shutdown + spin
+        up steps.
+
+        :param context: security context
+        :param instance: nova.objects.instance.Instance
+                         This function should use the data there to guide
+                         the creation of the new instance.
+        :param image_meta: image object returned by nova.image.glance that
+                           defines the image from which to boot this instance
+        :param injected_files: User files to inject into instance.
+        :param admin_password: Administrator password to set in instance.
+        :param bdms: block-device-mappings to use for rebuild
+        :param detach_block_devices: function to detach block devices. See
+            nova.compute.manager.ComputeManager:_rebuild_default_impl for
+            usage.
+        :param attach_block_devices: function to attach block devices. See
+            nova.compute.manager.ComputeManager:_rebuild_default_impl for
+            usage.
+        :param network_info:
+           :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
+        :param recreate: True if the instance is being recreated on a new
+            hypervisor - all the cleanup of old state is skipped.
+        :param block_device_info: Information about block devices to be
+                                  attached to the instance.
+        :param preserve_ephemeral: True if the default ephemeral storage
+                                   partition must be preserved on rebuild
         """
         raise NotImplementedError()
 
@@ -962,11 +1023,14 @@
             raise exception.InstanceNotFound(instance_id=name)
 
         tenant_id = None
+        network_plugin = neutronv2.get_client(context)
         for netid, network in enumerate(network_info):
             if tenant_id is None:
                 tenant_id = network['network']['meta']['tenant_id']
-            network_uuid = network['network']['id']
             port_uuid = network['id']
+            port = network_plugin.show_port(port_uuid)['port']
+            evs_uuid = port['network_id']
+            vport_uuid = port['id']
             ip = network['network']['subnets'][0]['ips'][0]['address']
             ip_version = network['network']['subnets'][0]['version']
             route = network['network']['subnets'][0]['gateway']['address']
@@ -979,17 +1043,17 @@
             with ZoneConfig(zone) as zc:
                 if netid == 0:
                     zc.setprop('anet', 'configure-allowed-address', 'false')
-                    zc.setprop('anet', 'evs', network_uuid)
-                    zc.setprop('anet', 'vport', port_uuid)
+                    zc.setprop('anet', 'evs', evs_uuid)
+                    zc.setprop('anet', 'vport', vport_uuid)
                 else:
                     zc.addresource(
                         'anet',
                         [zonemgr.Property('configure-allowed-address',
                                           'false'),
-                         zonemgr.Property('evs', network_uuid),
-                         zonemgr.Property('vport', port_uuid)])
-
-                filter = [zonemgr.Property('vport', port_uuid)]
+                         zonemgr.Property('evs', evs_uuid),
+                         zonemgr.Property('vport', vport_uuid)])
+
+                filter = [zonemgr.Property('vport', vport_uuid)]
                 if brand == ZONE_BRAND_SOLARIS:
                     linkname = lookup_resource_property(zc.zone, 'anet',
                                                         'linkname', filter)
@@ -999,8 +1063,6 @@
                     linkname = 'net%s' % id
 
             # create the required sysconfig file
-            network_plugin = neutronv2.get_client(context)
-            port = network_plugin.show_port(port_uuid)['port']
             subnet_uuid = port['fixed_ips'][0]['subnet_id']
             subnet = network_plugin.show_subnet(subnet_uuid)['subnet']
 
@@ -1103,7 +1165,7 @@
 
         self._verify_sysconfig(sc_dir, instance)
 
-        zonemanager = self._rad_instance.get_object(zonemgr.ZoneManager())
+        zonemanager = self.rad_connection.get_object(zonemgr.ZoneManager())
         try:
             zonemanager.create(name, None, template)
             self._set_global_properties(name, extra_specs, brand)
@@ -1335,7 +1397,7 @@
         if self._get_zone_by_name(name) is None:
             raise exception.InstanceNotFound(instance_id=name)
 
-        zonemanager = self._rad_instance.get_object(zonemgr.ZoneManager())
+        zonemanager = self.rad_connection.get_object(zonemgr.ZoneManager())
         try:
             zonemanager.delete(name)
         except Exception as reason:
@@ -1345,8 +1407,7 @@
 
     def spawn(self, context, instance, image_meta, injected_files,
               admin_password, network_info=None, block_device_info=None):
-        """
-        Create a new instance/VM/domain on the virtualization platform.
+        """Create a new instance/VM/domain on the virtualization platform.
 
         Once this successfully completes, the instance should be
         running (power_state.RUNNING).
@@ -1356,7 +1417,7 @@
         that it was before this call began.
 
         :param context: security context
-        :param instance: Instance object as returned by DB layer.
+        :param instance: nova.objects.instance.Instance
                          This function should use the data there to guide
                          the creation of the new instance.
         :param image_meta: image object returned by nova.image.glance that
@@ -1368,7 +1429,7 @@
         :param block_device_info: Information about block devices to be
                                   attached to the instance.
         """
-        inst_type = self.virtapi.instance_type_get(
+        inst_type = flavor_obj.Flavor.get_by_id(
             nova_context.get_admin_context(read_deleted='yes'),
             instance['instance_type_id'])
         extra_specs = inst_type['extra_specs'].copy()
@@ -1425,23 +1486,23 @@
                         "%s") % (name, reason))
             raise exception.InstancePowerOffFailure(reason=reason)
 
-    def destroy(self, instance, network_info, block_device_info=None,
-                destroy_disks=True, context=None):
-        """Destroy (shutdown and delete) the specified instance.
+    def destroy(self, context, instance, network_info, block_device_info=None,
+                destroy_disks=True, migrate_data=None):
+        """Destroy the specified instance from the Hypervisor.
 
         If the instance is not found (for example if networking failed), this
         function should still succeed.  It's probably a good idea to log a
         warning in that case.
 
+        :param context: security context
         :param instance: Instance object as returned by DB layer.
         :param network_info:
            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
         :param block_device_info: Information about block devices that should
                                   be detached from the instance.
         :param destroy_disks: Indicates if disks should be destroyed
-
+        :param migrate_data: implementation specific params
         """
-        # TODO(Vek): Need to pass context in for access to auth_token
         try:
             # These methods log if problems occur so no need to double log
             # here. Just catch any stray exceptions and allow destroy to
@@ -1471,6 +1532,24 @@
             LOG.warning(_("Unable to destroy instance '%s' via zonemgr(3RAD): "
                           "%s") % (name, reason))
 
+    def cleanup(self, context, instance, network_info, block_device_info=None,
+                destroy_disks=True, migrate_data=None, destroy_vifs=True):
+        """Cleanup the instance resources .
+
+        Instance should have been destroyed from the Hypervisor before calling
+        this method.
+
+        :param context: security context
+        :param instance: Instance object as returned by DB layer.
+        :param network_info:
+           :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
+        :param block_device_info: Information about block devices that should
+                                  be detached from the instance.
+        :param destroy_disks: Indicates if disks should be destroyed
+        :param migrate_data: implementation specific params
+        """
+        raise NotImplementedError()
+
     def reboot(self, context, instance, network_info, reboot_type,
                block_device_info=None, bad_volumes_callback=None):
         """Reboot the specified instance.
@@ -1481,7 +1560,7 @@
         successfully even in cases in which the underlying domain/vm
         is paused or halted/stopped.
 
-        :param instance: Instance object as returned by DB layer.
+        :param instance: nova.objects.instance.Instance
         :param network_info:
            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
         :param reboot_type: Either a HARD or SOFT reboot
@@ -1551,13 +1630,22 @@
                 console_str = fragment + console_str
         return console_str
 
-    def get_console_output(self, instance):
-        # TODO(Vek): Need to pass context in for access to auth_token
+    def get_console_output(self, context, instance):
+        """Get console output for an instance
+
+        :param context: security context
+        :param instance: nova.objects.instance.Instance
+        """
         return self._get_console_output(instance)
 
-    def get_vnc_console(self, instance):
-        # TODO(Vek): Need to pass context in for access to auth_token
-
+    def get_vnc_console(self, context, instance):
+        """Get connection info for a vnc console.
+
+        :param context: security context
+        :param instance: nova.objects.instance.Instance
+
+        :returns an instance of console.type.ConsoleVNC
+        """
         # Do not provide console access prematurely. Zone console access is
         # exclusive and zones that are still installing require their console.
         # Grabbing the zone console will break installation.
@@ -1590,16 +1678,43 @@
         try:
             out, err = utils.execute('/usr/bin/svcprop', '-p', 'vnc/port',
                                      console_fmri)
-            port = out.strip()
-            return {'host': '127.0.0.1', 'port': port,
-                    'internal_access_path': None}
+            port = int(out.strip())
+            return ctype.ConsoleVNC(host='127.0.0.1',
+                                    port=port,
+                                    internal_access_path=None)
         except processutils.ProcessExecutionError as err:
             LOG.error(_("Unable to read VNC console port from zone VNC "
                         "console SMF service '%s': %s"
                       % (console_fmri, err)))
 
-    def get_spice_console(self, instance):
-        # TODO(Vek): Need to pass context in for access to auth_token
+    def get_spice_console(self, context, instance):
+        """Get connection info for a spice console.
+
+        :param context: security context
+        :param instance: nova.objects.instance.Instance
+
+        :returns an instance of console.type.ConsoleSpice
+        """
+        raise NotImplementedError()
+
+    def get_rdp_console(self, context, instance):
+        """Get connection info for a rdp console.
+
+        :param context: security context
+        :param instance: nova.objects.instance.Instance
+
+        :returns an instance of console.type.ConsoleRDP
+        """
+        raise NotImplementedError()
+
+    def get_serial_console(self, context, instance):
+        """Get connection info for a serial console.
+
+        :param context: security context
+        :param instance: nova.objects.instance.Instance
+
+        :returns an instance of console.type.ConsoleSerial
+        """
         raise NotImplementedError()
 
     def _get_zone_diagnostics(self, zone):
@@ -1634,7 +1749,10 @@
         return diagnostics
 
     def get_diagnostics(self, instance):
-        """Return data about VM diagnostics."""
+        """Return data about VM diagnostics.
+
+        :param instance: nova.objects.instance.Instance
+        """
         # TODO(Vek): Need to pass context in for access to auth_token
         name = instance['name']
         zone = self._get_zone_by_name(name)
@@ -1644,9 +1762,18 @@
             raise exception.InstanceNotFound(instance_id=name)
         return self._get_zone_diagnostics(zone)
 
+    def get_instance_diagnostics(self, instance):
+        """Return data about VM diagnostics.
+
+        :param instance: nova.objects.instance.Instance
+        """
+        raise NotImplementedError()
+
     def get_all_bw_counters(self, instances):
         """Return bandwidth usage counters for each interface on each
            running VM.
+
+        :param instances: nova.objects.instance.InstanceList
         """
         raise NotImplementedError()
 
@@ -1657,14 +1784,13 @@
         raise NotImplementedError()
 
     def get_host_ip_addr(self):
-        """
-        Retrieves the IP address of the dom0
+        """Retrieves the IP address of the dom0
         """
         # TODO(Vek): Need to pass context in for access to auth_token
         return CONF.my_ip
 
     def attach_volume(self, context, connection_info, instance, mountpoint,
-                      encryption=None):
+                      disk_bus=None, device_type=None, encryption=None):
         """Attach the disk to the instance at mountpoint using info."""
         # TODO(npower): Apply mountpoint in a meaningful way to the zone
         # (I don't think this is even possible for Solaris brand zones)
@@ -1711,44 +1837,49 @@
             zc.removeresources("device", [zonemgr.Property("storage", suri)])
 
     def swap_volume(self, old_connection_info, new_connection_info,
-                    instance, mountpoint):
-        """Replace the disk attached to the instance."""
+                    instance, mountpoint, resize_to):
+        """Replace the disk attached to the instance.
+
+        :param instance: nova.objects.instance.Instance
+        :param resize_to: This parameter is used to indicate the new volume
+                          size when the new volume lager than old volume.
+                          And the units is Gigabyte.
+        """
         raise NotImplementedError()
 
     def attach_interface(self, instance, image_meta, vif):
-        """Attach an interface to the instance."""
+        """Attach an interface to the instance.
+
+        :param instance: nova.objects.instance.Instance
+        """
         raise NotImplementedError()
 
     def detach_interface(self, instance, vif):
-        """Detach an interface from the instance."""
+        """Detach an interface from the instance.
+
+        :param instance: nova.objects.instance.Instance
+        """
         raise NotImplementedError()
 
     def migrate_disk_and_power_off(self, context, instance, dest,
-                                   instance_type, network_info,
-                                   block_device_info=None):
-        """
-        Transfers the disk of a running instance in multiple phases, turning
+                                   flavor, network_info,
+                                   block_device_info=None,
+                                   timeout=0, retry_interval=0):
+        """Transfers the disk of a running instance in multiple phases, turning
         off the instance before the end.
-        """
-        raise NotImplementedError()
-
-    def live_snapshot(self, context, instance, image_id, update_task_state):
-        """
-        Live-snapshots the specified instance (includes ram and proc state).
-
-        :param context: security context
-        :param instance: Instance object as returned by DB layer.
-        :param image_id: Reference to a pre-created image that will
-                         hold the snapshot.
+
+        :param instance: nova.objects.instance.Instance
+        :param timeout: time to wait for GuestOS to shutdown
+        :param retry_interval: How often to signal guest while
+                               waiting for it to shutdown
         """
         raise NotImplementedError()
 
     def snapshot(self, context, instance, image_id, update_task_state):
-        """
-        Snapshots the specified instance.
+        """Snapshots the specified instance.
 
         :param context: security context
-        :param instance: Instance object as returned by DB layer.
+        :param instance: nova.objects.instance.Instance
         :param image_id: Reference to a pre-created image that will
                          hold the snapshot.
         """
@@ -1773,6 +1904,7 @@
                 'image_location': 'snapshot',
                 'image_state': 'available',
                 'owner_id': instance['project_id'],
+                'instance_uuid': instance['uuid'],
             }
         }
         # Match architecture, hypervisor_type and vm_mode properties to base
@@ -1794,10 +1926,6 @@
 
         with utils.tempdir(dir=snapshot_directory) as tmpdir:
             out_path = os.path.join(tmpdir, snapshot_name)
-
-            # TODO(npower): archiveadm invocation needs --root-only arg
-            # passed once it is available. Assume the instance contains
-            # root pool only for now.
             zone_name = instance['name']
             utils.execute('/usr/sbin/archiveadm', 'create', '--root-only',
                           '-z', zone_name, out_path)
@@ -1806,9 +1934,9 @@
                      instance=instance)
             try:
                 # Upload the archive image to the image service
-                update_task_state(task_state=task_states.IMAGE_UPLOADING,
-                                  expected_state=
-                                  task_states.IMAGE_PENDING_UPLOAD)
+                update_task_state(
+                    task_state=task_states.IMAGE_UPLOADING,
+                    expected_state=task_states.IMAGE_PENDING_UPLOAD)
                 with open(out_path, 'r') as image_file:
                     snapshot_service.update(context,
                                             image_id,
@@ -1835,6 +1963,14 @@
                 # Delete the snapshot image file source
                 os.unlink(out_path)
 
+    def post_interrupted_snapshot_cleanup(self, context, instance):
+        """Cleans up any resources left after an interrupted snapshot.
+
+        :param context: security context
+        :param instance: nova.objects.instance.Instance
+        """
+        pass
+
     def finish_migration(self, context, migration, instance, disk_info,
                          network_info, image_meta, resize_instance,
                          block_device_info=None, power_on=True):
@@ -1842,7 +1978,7 @@
 
         :param context: the context for the migration/resize
         :param migration: the migrate/resize information
-        :param instance: the instance being migrated/resized
+        :param instance: nova.objects.instance.Instance being migrated/resized
         :param disk_info: the newly transferred disk information
         :param network_info:
            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
@@ -1858,46 +1994,56 @@
         raise NotImplementedError()
 
     def confirm_migration(self, migration, instance, network_info):
-        """Confirms a resize, destroying the source VM."""
+        """Confirms a resize, destroying the source VM.
+
+        :param instance: nova.objects.instance.Instance
+        """
         # TODO(Vek): Need to pass context in for access to auth_token
         raise NotImplementedError()
 
-    def finish_revert_migration(self, instance, network_info,
+    def finish_revert_migration(self, context, instance, network_info,
                                 block_device_info=None, power_on=True):
-        """
-        Finish reverting a resize.
-
-        :param instance: the instance being migrated/resized
+        """Finish reverting a resize.
+
+        :param context: the context for the finish_revert_migration
+        :param instance: nova.objects.instance.Instance being migrated/resized
         :param network_info:
            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
         :param block_device_info: instance volume block device info
         :param power_on: True if the instance should be powered on, False
                          otherwise
         """
-        # TODO(Vek): Need to pass context in for access to auth_token
         raise NotImplementedError()
 
     def pause(self, instance):
-        """Pause the specified instance."""
+        """Pause the specified instance.
+
+        :param instance: nova.objects.instance.Instance
+        """
         # TODO(Vek): Need to pass context in for access to auth_token
         raise NotImplementedError()
 
     def unpause(self, instance):
-        """Unpause paused VM instance."""
+        """Unpause paused VM instance.
+
+        :param instance: nova.objects.instance.Instance
+        """
         # TODO(Vek): Need to pass context in for access to auth_token
         raise NotImplementedError()
 
     def suspend(self, instance):
-        """suspend the specified instance."""
+        """suspend the specified instance.
+
+        :param instance: nova.objects.instance.Instance
+        """
         # TODO(Vek): Need to pass context in for access to auth_token
         raise NotImplementedError()
 
     def resume(self, context, instance, network_info, block_device_info=None):
-        """
-        resume the specified instance.
+        """resume the specified instance.
 
         :param context: the context for the resume
-        :param instance: the instance being resumed
+        :param instance: nova.objects.instance.Instance being resumed
         :param network_info:
            :py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
         :param block_device_info: instance volume block device info
@@ -1906,7 +2052,10 @@
 
     def resume_state_on_host_boot(self, context, instance, network_info,
                                   block_device_info=None):
-        """resume guest state when a host is booted."""
+        """resume guest state when a host is booted.
+
+        :param instance: nova.objects.instance.Instance
+        """
         name = instance['name']
         zone = self._get_zone_by_name(name)
         if zone is None:
@@ -1922,29 +2071,57 @@
 
     def rescue(self, context, instance, network_info, image_meta,
                rescue_password):
-        """Rescue the specified instance."""
+        """Rescue the specified instance.
+
+        :param instance: nova.objects.instance.Instance
+        """
+        raise NotImplementedError()
+
+    def set_bootable(self, instance, is_bootable):
+        """Set the ability to power on/off an instance.
+
+        :param instance: nova.objects.instance.Instance
+        """
         raise NotImplementedError()
 
     def unrescue(self, instance, network_info):
-        """Unrescue the specified instance."""
+        """Unrescue the specified instance.
+
+        :param instance: nova.objects.instance.Instance
+        """
         # TODO(Vek): Need to pass context in for access to auth_token
         raise NotImplementedError()
 
-    def power_off(self, instance):
-        """Power off the specified instance."""
+    def power_off(self, instance, timeout=0, retry_interval=0):
+        """Power off the specified instance.
+
+        :param instance: nova.objects.instance.Instance
+        :param timeout: time to wait for GuestOS to shutdown
+        :param retry_interval: How often to signal guest while
+                               waiting for it to shutdown
+        """
         self._power_off(instance, 'SOFT')
 
     def power_on(self, context, instance, network_info,
                  block_device_info=None):
-        """Power on the specified instance."""
+        """Power on the specified instance.
+
+        :param instance: nova.objects.instance.Instance
+        """
         self._power_on(instance)
 
     def soft_delete(self, instance):
-        """Soft delete the specified instance."""
+        """Soft delete the specified instance.
+
+        :param instance: nova.objects.instance.Instance
+        """
         raise NotImplementedError()
 
     def restore(self, instance):
-        """Restore the specified instance."""
+        """Restore the specified instance.
+
+        :param instance: nova.objects.instance.Instance
+        """
         raise NotImplementedError()
 
     def _get_zpool_property(self, prop, zpool):
@@ -2056,12 +2233,12 @@
         resources['supported_instances'] = host_stats['supported_instances']
         return resources
 
-    def pre_live_migration(self, ctxt, instance_ref, block_device_info,
+    def pre_live_migration(self, context, instance, block_device_info,
                            network_info, disk_info, migrate_data=None):
         """Prepare an instance for live migration
 
-        :param ctxt: security context
-        :param instance_ref: instance object that will be migrated
+        :param context: security context
+        :param instance: nova.objects.instance.Instance object
         :param block_device_info: instance block device information
         :param network_info: instance network information
         :param disk_info: instance disk information
@@ -2069,62 +2246,92 @@
         """
         raise NotImplementedError()
 
-    def live_migration(self, ctxt, instance_ref, dest,
+    def live_migration(self, context, instance, dest,
                        post_method, recover_method, block_migration=False,
                        migrate_data=None):
         """Live migration of an instance to another host.
 
-        :params ctxt: security context
-        :params instance_ref:
+        :param context: security context
+        :param instance:
             nova.db.sqlalchemy.models.Instance object
             instance object that is migrated.
-        :params dest: destination host
-        :params post_method:
+        :param dest: destination host
+        :param post_method:
             post operation method.
-            expected nova.compute.manager.post_live_migration.
-        :params recover_method:
+            expected nova.compute.manager._post_live_migration.
+        :param recover_method:
             recovery method when any exception occurs.
-            expected nova.compute.manager.recover_live_migration.
-        :params block_migration: if true, migrate VM disk.
-        :params migrate_data: implementation specific params.
+            expected nova.compute.manager._rollback_live_migration.
+        :param block_migration: if true, migrate VM disk.
+        :param migrate_data: implementation specific params.
 
         """
         raise NotImplementedError()
 
-    def post_live_migration(self, ctxt, instance_ref, block_device_info):
+    def rollback_live_migration_at_destination(self, context, instance,
+                                               network_info,
+                                               block_device_info,
+                                               destroy_disks=True,
+                                               migrate_data=None):
+        """Clean up destination node after a failed live migration.
+
+        :param context: security context
+        :param instance: instance object that was being migrated
+        :param network_info: instance network information
+        :param block_device_info: instance block device information
+        :param destroy_disks:
+            if true, destroy disks at destination during cleanup
+        :param migrate_data: implementation specific params
+
+        """
+        raise NotImplementedError()
+
+    def post_live_migration(self, context, instance, block_device_info,
+                            migrate_data=None):
         """Post operation of live migration at source host.
 
-        :param ctxt: security contet
-        :instance_ref: instance object that was migrated
+        :param context: security context
+        :instance: instance object that was migrated
         :block_device_info: instance block device information
+        :param migrate_data: if not None, it is a dict which has data
         """
         pass
 
-    def post_live_migration_at_destination(self, ctxt, instance_ref,
+    def post_live_migration_at_source(self, context, instance, network_info):
+        """Unplug VIFs from networks at source.
+
+        :param context: security context
+        :param instance: instance object reference
+        :param network_info: instance network information
+        """
+        raise NotImplementedError(_("Hypervisor driver does not support "
+                                    "post_live_migration_at_source method"))
+
+    def post_live_migration_at_destination(self, context, instance,
                                            network_info,
                                            block_migration=False,
                                            block_device_info=None):
         """Post operation of live migration at destination host.
 
-        :param ctxt: security context
-        :param instance_ref: instance object that is migrated
+        :param context: security context
+        :param instance: instance object that is migrated
         :param network_info: instance network information
         :param block_migration: if true, post operation of block_migration.
         """
         raise NotImplementedError()
 
-    def check_instance_shared_storage_local(self, ctxt, instance):
+    def check_instance_shared_storage_local(self, context, instance):
         """Check if instance files located on shared storage.
 
         This runs check on the destination host, and then calls
         back to the source host to check the results.
 
-        :param ctxt: security context
+        :param context: security context
         :param instance: nova.db.sqlalchemy.models.Instance
         """
         raise NotImplementedError()
 
-    def check_instance_shared_storage_remote(self, ctxt, data):
+    def check_instance_shared_storage_remote(self, context, data):
         """Check if instance files located on shared storage.
 
         :param context: security context
@@ -2132,15 +2339,15 @@
         """
         raise NotImplementedError()
 
-    def check_instance_shared_storage_cleanup(self, ctxt, data):
+    def check_instance_shared_storage_cleanup(self, context, data):
         """Do cleanup on host after check_instance_shared_storage calls
 
-        :param ctxt: security context
+        :param context: security context
         :param data: result of check_instance_shared_storage_local
         """
         pass
 
-    def check_can_live_migrate_destination(self, ctxt, instance_ref,
+    def check_can_live_migrate_destination(self, context, instance,
                                            src_compute_info, dst_compute_info,
                                            block_migration=False,
                                            disk_over_commit=False):
@@ -2149,8 +2356,8 @@
         This runs checks on the destination host, and then calls
         back to the source host to check the results.
 
-        :param ctxt: security context
-        :param instance_ref: nova.db.sqlalchemy.models.Instance
+        :param context: security context
+        :param instance: nova.db.sqlalchemy.models.Instance
         :param src_compute_info: Info about the sending machine
         :param dst_compute_info: Info about the receiving machine
         :param block_migration: if true, prepare for block migration
@@ -2159,16 +2366,16 @@
         """
         raise NotImplementedError()
 
-    def check_can_live_migrate_destination_cleanup(self, ctxt,
+    def check_can_live_migrate_destination_cleanup(self, context,
                                                    dest_check_data):
         """Do required cleanup on dest host after check_can_live_migrate calls
 
-        :param ctxt: security context
+        :param context: security context
         :param dest_check_data: result of check_can_live_migrate_destination
         """
         raise NotImplementedError()
 
-    def check_can_live_migrate_source(self, ctxt, instance_ref,
+    def check_can_live_migrate_source(self, context, instance,
                                       dest_check_data):
         """Check if it is possible to execute live migration.
 
@@ -2176,12 +2383,34 @@
         results from check_can_live_migrate_destination.
 
         :param context: security context
-        :param instance_ref: nova.db.sqlalchemy.models.Instance
+        :param instance: nova.db.sqlalchemy.models.Instance
         :param dest_check_data: result of check_can_live_migrate_destination
         :returns: a dict containing migration info (hypervisor-dependent)
         """
         raise NotImplementedError()
 
+    def get_instance_disk_info(self, instance_name,
+                               block_device_info=None):
+        """Retrieve information about actual disk sizes of an instance.
+
+        :param instance_name:
+            name of a nova instance as returned by list_instances()
+        :param block_device_info:
+            Optional; Can be used to filter out devices which are
+            actually volumes.
+        :return:
+            json strings with below format::
+
+                "[{'path':'disk',
+                   'type':'raw',
+                   'virt_disk_size':'10737418240',
+                   'backing_file':'backing_file',
+                   'disk_size':'83886080'
+                   'over_committed_disk_size':'10737418240'},
+                   ...]"
+        """
+        raise NotImplementedError()
+
     def refresh_security_group_rules(self, security_group_id):
         """This method is called after a change to security groups.
 
@@ -2249,12 +2478,21 @@
         # TODO(Vek): Need to pass context in for access to auth_token
         raise NotImplementedError()
 
+    def refresh_instance_security_rules(self, instance):
+        """Refresh security group rules
+
+        Gets called when an instance gets added to or removed from
+        the security group the instance is a member of or if the
+        group gains or loses a rule.
+        """
+        raise NotImplementedError()
+
     def reset_network(self, instance):
         """reset networking for specified instance."""
         # TODO(Vek): Need to pass context in for access to auth_token
         pass
 
-    def ensure_filtering_rules_for_instance(self, instance_ref, network_info):
+    def ensure_filtering_rules_for_instance(self, instance, network_info):
         """Setting up filtering rules and waiting for its completion.
 
         To migrate an instance, filtering rules to hypervisors
@@ -2274,7 +2512,7 @@
         not be started when setting-up filtering rules operations
         are not completed.
 
-        :params instance_ref: nova.db.sqlalchemy.models.Instance object
+        :param instance: nova.objects.instance.Instance object
 
         """
         # TODO(Vek): Need to pass context in for access to auth_token
@@ -2293,37 +2531,39 @@
         # TODO(Vek): Need to pass context in for access to auth_token
         raise NotImplementedError()
 
-    def set_admin_password(self, context, instance_id, new_pass=None):
-        """
-        Set the root password on the specified instance.
-
-        The first parameter is an instance of nova.compute.service.Instance,
-        and so the instance is being specified as instance.name. The second
-        parameter is the value of the new password.
+    def set_admin_password(self, instance, new_pass):
+        """Set the root password on the specified instance.
+
+        :param instance: nova.objects.instance.Instance
+        :param new_password: the new password
         """
         raise NotImplementedError()
 
     def inject_file(self, instance, b64_path, b64_contents):
-        """
-        Writes a file on the specified instance.
+        """Writes a file on the specified instance.
 
         The first parameter is an instance of nova.compute.service.Instance,
         and so the instance is being specified as instance.name. The second
         parameter is the base64-encoded path to which the file is to be
         written on the instance; the third is the contents of the file, also
         base64-encoded.
+
+        NOTE(russellb) This method is deprecated and will be removed once it
+        can be removed from nova.compute.manager.
         """
         # TODO(Vek): Need to pass context in for access to auth_token
         raise NotImplementedError()
 
     def change_instance_metadata(self, context, instance, diff):
-        """
-        Applies a diff to the instance metadata.
+        """Applies a diff to the instance metadata.
 
         This is an optional driver method which is used to publish
         changes to the instance's metadata to the hypervisor.  If the
         hypervisor has no means of publishing the instance metadata to
         the instance, then this method should not be implemented.
+
+        :param context: security context
+        :param instance: nova.objects.instance.Instance
         """
         pass
 
@@ -2364,12 +2604,18 @@
         return utils.execute('/usr/bin/uptime')[0]
 
     def plug_vifs(self, instance, network_info):
-        """Plug VIFs into networks."""
+        """Plug VIFs into networks.
+
+        :param instance: nova.objects.instance.Instance
+        """
         # TODO(Vek): Need to pass context in for access to auth_token
         pass
 
     def unplug_vifs(self, instance, network_info):
-        """Unplug VIFs from networks."""
+        """Unplug VIFs from networks.
+
+        :param instance: nova.objects.instance.Instance
+        """
         raise NotImplementedError()
 
     def get_host_stats(self, refresh=False):
@@ -2389,9 +2635,30 @@
             self._update_host_stats()
         return self._host_stats
 
-    def block_stats(self, instance_name, disk_id):
+    def get_host_cpu_stats(self):
+        """Get the currently known host CPU stats.
+
+        :returns: a dict containing the CPU stat info, eg:
+
+            | {'kernel': kern,
+            |  'idle': idle,
+            |  'user': user,
+            |  'iowait': wait,
+            |   'frequency': freq},
+
+                  where kern and user indicate the cumulative CPU time
+                  (nanoseconds) spent by kernel and user processes
+                  respectively, idle indicates the cumulative idle CPU time
+                  (nanoseconds), wait indicates the cumulative I/O wait CPU
+                  time (nanoseconds), since the host is booting up; freq
+                  indicates the current CPU frequency (MHz). All values are
+                  long integers.
+
         """
-        Return performance counters associated with the given disk_id on the
+        raise NotImplementedError()
+
+    def block_stats(self, instance_name, disk_id):
+        """Return performance counters associated with the given disk_id on the
         given instance_name.  These are returned as [rd_req, rd_bytes, wr_req,
         wr_bytes, errs], where rd indicates read, wr indicates write, req is
         the total number of I/O requests made, bytes is the total number of
@@ -2410,9 +2677,8 @@
         raise NotImplementedError()
 
     def interface_stats(self, instance_name, iface_id):
-        """
-        Return performance counters associated with the given iface_id on the
-        given instance_id.  These are returned as [rx_bytes, rx_packets,
+        """Return performance counters associated with the given iface_id
+        on the given instance_id.  These are returned as [rx_bytes, rx_packets,
         rx_errs, rx_drop, tx_bytes, tx_packets, tx_errs, tx_drop], where rx
         indicates receive, tx indicates transmit, bytes and packets indicate
         the total number of bytes or packets transferred, and errs and dropped
@@ -2429,6 +2695,10 @@
         """
         raise NotImplementedError()
 
+    def deallocate_networks_on_reschedule(self, instance):
+        """Does the driver want networks deallocated on reschedule?"""
+        return False
+
     def macs_for_instance(self, instance):
         """What MAC addresses must this instance have?
 
@@ -2472,24 +2742,27 @@
         client API.
 
         :return: None, or a set of DHCP options, eg:
-                 [{'opt_name': 'bootfile-name',
-                   'opt_value': '/tftpboot/path/to/config'},
-                  {'opt_name': 'server-ip-address',
-                   'opt_value': '1.2.3.4'},
-                  {'opt_name': 'tftp-server',
-                   'opt_value': '1.2.3.4'}
-                 ]
+
+             |    [{'opt_name': 'bootfile-name',
+             |      'opt_value': '/tftpboot/path/to/config'},
+             |     {'opt_name': 'server-ip-address',
+             |      'opt_value': '1.2.3.4'},
+             |     {'opt_name': 'tftp-server',
+             |      'opt_value': '1.2.3.4'}
+             |    ]
+
         """
         pass
 
     def manage_image_cache(self, context, all_instances):
-        """
-        Manage the driver's local image cache.
+        """Manage the driver's local image cache.
 
         Some drivers chose to cache images for instances on disk. This method
         is an opportunity to do management of that cache which isn't directly
         related to other calls into the driver. The prime example is to clean
         the cache and remove images which are no longer of interest.
+
+        :param instances: nova.objects.instance.InstanceList
         """
         pass
 
@@ -2513,7 +2786,7 @@
         Connector information is a dictionary representing the ip of the
         machine that will be making the connection, the name of the iscsi
         initiator, the WWPN and WWNN values of the Fibre Channel initiator,
-        and the hostname of the machine as follows:
+        and the hostname of the machine as follows::
 
             {
                 'ip': ip,
@@ -2522,6 +2795,7 @@
                 'wwpns': wwpns,
                 'host': hostname
             }
+
         """
         connector = {'ip': self.get_host_ip_addr(),
                      'host': CONF.host}
@@ -2583,7 +2857,7 @@
     def instance_on_disk(self, instance):
         """Checks access of instance files on the host.
 
-        :param instance: instance to lookup
+        :param instance: nova.objects.instance.Instance to lookup
 
         Returns True if files of an instance with the supplied ID accessible on
         the host, False otherwise.
@@ -2614,7 +2888,7 @@
         """
 
         if not self._compute_event_callback:
-            LOG.debug(_("Discarding event %s") % str(event))
+            LOG.debug("Discarding event %s", str(event))
             return
 
         if not isinstance(event, virtevent.Event):
@@ -2622,7 +2896,7 @@
                 _("Event must be an instance of nova.virt.event.Event"))
 
         try:
-            LOG.debug(_("Emitting event %s") % str(event))
+            LOG.debug("Emitting event %s", str(event))
             self._compute_event_callback(event)
         except Exception as ex:
             LOG.error(_("Exception dispatching event %(event)s: %(ex)s"),
@@ -2631,6 +2905,7 @@
     def delete_instance_files(self, instance):
         """Delete any lingering instance files for an instance.
 
+        :param instance: nova.objects.instance.Instance
         :returns: True if the instance was deleted from disk, False otherwise.
         """
         return True
@@ -2639,18 +2914,18 @@
     def need_legacy_block_device_info(self):
         """Tell the caller if the driver requires legacy block device info.
 
-        Tell the caller weather we expect the legacy format of block
+        Tell the caller whether we expect the legacy format of block
         device info to be passed in to methods that expect it.
         """
         return True
 
     def volume_snapshot_create(self, context, instance, volume_id,
                                create_info):
-        """
-        Snapshots volumes attached to a specified instance.
+        """Snapshots volumes attached to a specified instance.
 
         :param context: request context
-        :param instance: Instance object that has the volume attached
+        :param instance: nova.objects.instance.Instance that has the volume
+               attached
         :param volume_id: Volume to be snapshotted
         :param create_info: The data needed for nova to be able to attach
                to the volume.  This is the same data format returned by
@@ -2664,11 +2939,11 @@
 
     def volume_snapshot_delete(self, context, instance, volume_id,
                                snapshot_id, delete_info):
-        """
-        Snapshots volumes attached to a specified instance.
+        """Snapshots volumes attached to a specified instance.
 
         :param context: request context
-        :param instance: Instance object that has the volume attached
+        :param instance: nova.objects.instance.Instance that has the volume
+               attached
         :param volume_id: Attached volume associated with the snapshot
         :param snapshot_id: The snapshot to delete.
         :param delete_info: Volume backend technology specific data needed to
@@ -2686,3 +2961,15 @@
                                           *block_device_lists):
         """Default the missing device names in the block device mapping."""
         raise NotImplementedError()
+
+    def is_supported_fs_format(self, fs_type):
+        """Check whether the file format is supported by this driver
+
+        :param fs_type: the file system type to be checked,
+                        the validate values are defined at disk API module.
+        """
+        # NOTE(jichenjc): Return False here so that every hypervisor
+        #                 need to define their supported file system
+        #                 type and implement this function at their
+        #                 virt layer.
+        return False