Initial scaffold of PowerVM virt driver

Initial driver that wraps the 'fake' implementation for PowerVM.

Also updates the tox.ini to match more of the pep8 rules that Nova
utilizes.

Provides an initial test case to validate that the driver can be
initialized.  This requires updates to the test framework to pull
in further dependencies of Nova.

Change-Id: I59407d14531635be567d2eea5d7e26ea895b5093
This commit is contained in:
Drew Thorstensen 2014-10-28 15:43:13 -05:00
parent b078b89f49
commit 4be982bf3c
5 changed files with 332 additions and 1 deletions

View File

@ -13,3 +13,23 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# TODO(mikal): move eventlet imports to nova.__init__ once we move to PBR
import os
import sys
# NOTE(mikal): All of this is because if dnspython is present in your
# environment then eventlet monkeypatches socket.getaddrinfo() with an
# implementation which doesn't work for IPv6. What we're checking here is
# that the magic environment variable was set when the import happened.
if ('eventlet' in sys.modules and
os.environ.get('EVENTLET_NO_GREENDNS', '').lower() != 'yes'):
raise ImportError('eventlet imported before nova/cmd/__init__ '
'(env var set to %s)'
% os.environ.get('EVENTLET_NO_GREENDNS'))
os.environ['EVENTLET_NO_GREENDNS'] = 'yes'
import eventlet
eventlet.monkey_patch(os=False)

View File

@ -0,0 +1,35 @@
# Copyright 2014 IBM Corp.
#
# 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
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# @author: Drew Thorstensen, IBM Corp.
from nova import test
from nova.virt import fake
from nova_powervm.virt.powervm import driver
class TestPowerVMDriver(test.TestCase):
def setUp(self):
super(TestPowerVMDriver, self).setUp()
def test_driver_create(self):
"""Validates that a driver of the PowerVM type can just be
initialized.
"""
test_drv = driver.PowerVMDriver(fake.FakeVirtAPI())
self.assertIsNotNone(test_drv)

View File

@ -0,0 +1,275 @@
# Copyright 2014 IBM Corp.
#
# 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
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from nova.openstack.common import log as logging
from nova.virt import driver
from nova.virt import fake # TODO(IBM): Remove this in the future
LOG = logging.getLogger(__name__)
class PowerVMDriver(driver.ComputeDriver):
"""PowerVM Implementation of Compute Driver."""
def __init__(self, virtapi):
super(PowerVMDriver, self).__init__(virtapi)
# Use the fake driver for scaffolding for now
fake.set_nodes(['fake-PowerVM'])
self._fake = fake.FakeDriver(virtapi)
def init_host(self, host):
"""Initialize anything that is necessary for the driver to function,
including catching up with currently running VM's on the given host.
"""
pass
def get_info(self, instance):
"""Get the current status of an instance, by name (not ID!)
Returns a dict containing:
:state: the running state, one of the power_state codes
:max_mem: (int) the maximum memory in KBytes allowed
:mem: (int) the memory in KBytes used by the domain
:num_cpu: (int) the number of virtual CPUs for the domain
:cpu_time: (int) the CPU time used in nanoseconds
"""
info = self._fake.get_info(instance)
return info
def list_instances(self):
"""Return the names of all the instances known to the virtualization
layer, as a list.
"""
return self._fake.list_instances()
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.
Once this successfully completes, the instance should be
running (power_state.RUNNING).
If this fails, any partial instance should be completely
cleaned up, and the virtualization platform should be in the state
that it was before this call began.
:param context: security context
:param instance: Instance object as returned by DB layer.
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 network_info:
:py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
:param block_device_info: Information about block devices to be
attached to the instance.
"""
return self._fake.spawn(context, instance, image_meta, injected_files,
admin_password, network_info,
block_device_info)
def destroy(self, instance, network_info, block_device_info=None,
destroy_disks=True):
"""Destroy (shutdown and delete) the specified instance.
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 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
"""
return self._fake.destroy(instance, network_info, block_device_info,
destroy_disks)
def attach_volume(self, connection_info, instance, mountpoint):
"""Attach the disk to the instance at mountpoint using info."""
return self._fake.attach_volume(connection_info, instance, mountpoint)
def detach_volume(self, connection_info, instance, mountpoint):
"""Detach the disk attached to the instance."""
return self._fake.detach_volume(connection_info, instance, mountpoint)
def snapshot(self, context, instance, image_id, update_task_state):
"""Snapshots the specified instance.
: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.
"""
raise self._fake.snapshot(context, instance, image_id,
update_task_state)
def power_off(self, instance):
"""Power off the specified instance."""
raise NotImplementedError()
def power_on(self, instance):
"""Power on the specified instance."""
raise NotImplementedError()
def get_available_resource(self, nodename):
"""Retrieve resource information.
This method is called when nova-compute launches, and
as part of a periodic task
:param nodename:
node which the caller want to get resources from
a driver that manages only one node can safely ignore this
:returns: Dictionary describing resources
"""
data = self._fake.get_available_resource(nodename)
return data
def get_host_uptime(self, host):
"""Returns the result of calling "uptime" on the target host."""
raise NotImplementedError()
def plug_vifs(self, instance, network_info):
"""Plug VIFs into networks."""
pass
def unplug_vifs(self, instance, network_info):
"""Unplug VIFs from networks."""
pass
def get_host_stats(self, refresh=False):
"""Return currently known host stats."""
data = self._fake.get_host_stats(refresh)
return data
def get_available_nodes(self):
"""Returns nodenames of all nodes managed by the compute service.
This method is for multi compute-nodes support. If a driver supports
multi compute-nodes, this method returns a list of nodenames managed
by the service. Otherwise, this method should return
[hypervisor_hostname].
"""
return self._fake.get_available_nodes()
def legacy_nwinfo(self):
"""Indicate if the driver requires the legacy network_info format.
"""
return False
def check_can_live_migrate_destination(self, ctxt, instance_ref,
src_compute_info, dst_compute_info,
block_migration=False,
disk_over_commit=False):
"""Validate the destination host is capable of live partition
migration.
:param ctxt: security context
:param instance_ref: instance to be migrated
:param src_compute_info: source host information
:param dst_compute_info: destination host information
:param block_migration: if true, prepare for block migration
:param disk_over_commit: if true, allow disk over commit
:returns dest_check_data: dictionary containing destination data
"""
dest_check_data = \
self._fake.check_can_live_migrate_destination(
ctxt, instance_ref, src_compute_info, dst_compute_info,
block_migration=False, disk_over_commit=False)
return dest_check_data
def check_can_live_migrate_source(self, ctxt, instance_ref,
dest_check_data):
"""Validate the source host is capable of live partition
migration.
:param context: security context
:param instance_ref: instance to be migrated
:param dest_check_data: results from check_can_live_migrate_destination
:returns migrate_data: dictionary containing source and
destination data for migration
"""
migrate_data = \
self._fake.check_can_live_migrate_source(ctxt,
instance_ref,
dest_check_data)
return migrate_data
def pre_live_migration(self, context, instance,
block_device_info, network_info,
migrate_data=None):
"""Perfoms any required prerequisites on the destination
host prior to live partition migration.
:param context: security context
:param instance: instance to be migrated
:param block_device_info: instance block device information
:param network_info: instance network information
:param migrate_data: implementation specific data dictionary
"""
self._fake.pre_live_migration(context, instance,
block_device_info,
network_info,
migrate_data)
def live_migration(self, ctxt, instance_ref, dest,
post_method, recover_method,
block_migration=False, migrate_data=None):
"""Live migrates a partition from one host to another.
:param ctxt: security context
:params instance_ref: instance to be migrated.
:params dest: destination host
:params post_method: post operation method.
nova.compute.manager.post_live_migration.
:params recover_method: recovery method when any exception occurs.
nova.compute.manager.recover_live_migration.
:params block_migration: if true, migrate VM disk.
:params migrate_data: implementation specific data dictionary.
"""
self._fake.live_migration(ctxt, instance_ref, dest,
post_method, recover_method,
migrate_data, block_migration=False)
def post_live_migration_at_destination(self, ctxt, instance_ref,
network_info,
block_migration=False,
block_device_info=None):
"""Performs post operations on the destination host
following a successful live migration.
:param ctxt: security context
:param instance_ref: migrated instance
:param network_info: dictionary of network info for instance
:param block_migration: boolean for block migration
"""
self._fake.post_live_migration_at_destination(
ctxt, instance_ref, network_info,
block_migration=False, block_device_info=None)

View File

@ -10,3 +10,4 @@ testrepository>=0.0.17
testscenarios>=0.4,<0.5
testtools>=0.9.32
mock>=1.0
mox>=0.5.3

View File

@ -23,7 +23,7 @@ commands = {posargs}
commands = python setup.py testr --coverage --testr-args='{posargs}'
[flake8]
ignore = E125,E712,H104
ignore = E125,E712,H104,H405,H904
exclude = .venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build,tools
[hacking]