Merge "Ovirt support"
This commit is contained in:
commit
5c3dc1dded
@ -37,3 +37,7 @@ class LibvirtError(exception.IronicException):
|
||||
|
||||
class InvalidIPMITimestamp(exception.IronicException):
|
||||
pass
|
||||
|
||||
|
||||
class oVirtError(exception.IronicException):
|
||||
message = _("oVirt call failed: %(err)s.")
|
||||
|
37
ironic_staging_drivers/ovirt/__init__.py
Normal file
37
ironic_staging_drivers/ovirt/__init__.py
Normal file
@ -0,0 +1,37 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
#
|
||||
# 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.
|
||||
"""
|
||||
PXE Driver and supporting meta-classes.
|
||||
"""
|
||||
|
||||
from ironic.drivers import generic
|
||||
|
||||
from ironic_staging_drivers.ovirt import ovirt
|
||||
|
||||
|
||||
class oVirtHardware(generic.GenericHardware):
|
||||
"""oVirt hardware type.
|
||||
|
||||
Uses oVirt for power and management.
|
||||
"""
|
||||
|
||||
@property
|
||||
def supported_management_interfaces(self):
|
||||
"""List of supported management interfaces."""
|
||||
return [ovirt.oVirtManagement]
|
||||
|
||||
@property
|
||||
def supported_power_interfaces(self):
|
||||
"""List of supported power interfaces."""
|
||||
return [ovirt.oVirtPower]
|
3
ironic_staging_drivers/ovirt/other-requirements.sh
Normal file
3
ironic_staging_drivers/ovirt/other-requirements.sh
Normal file
@ -0,0 +1,3 @@
|
||||
OVIRT_DEB_PACKAGES="libcurl4-openssl-dev libssl-dev libxml2-dev"
|
||||
|
||||
install_package $OVIRT_DEB_PACKAGES
|
339
ironic_staging_drivers/ovirt/ovirt.py
Normal file
339
ironic_staging_drivers/ovirt/ovirt.py
Normal file
@ -0,0 +1,339 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Ironic oVirt power manager and management interface.
|
||||
|
||||
Provides basic power control and management of virtual machines
|
||||
via oVirt sdk API.
|
||||
|
||||
For use in dev and test environments.
|
||||
"""
|
||||
|
||||
from ironic.common import boot_devices
|
||||
from ironic.common import exception
|
||||
from ironic.common.i18n import _
|
||||
from ironic.common import states
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.drivers import base
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import importutils
|
||||
|
||||
from ironic_staging_drivers.common import exception as staging_exception
|
||||
|
||||
ovirtsdk = importutils.try_import('ovirtsdk4')
|
||||
if ovirtsdk:
|
||||
import ovirtsdk4 as sdk
|
||||
import ovirtsdk4.types as otypes
|
||||
|
||||
IRONIC_TO_OVIRT_DEVICE_MAPPING = {
|
||||
boot_devices.PXE: 'network',
|
||||
boot_devices.DISK: 'hd',
|
||||
boot_devices.CDROM: 'cdrom',
|
||||
}
|
||||
OVIRT_TO_IRONIC_DEVICE_MAPPING = {v: k for k, v in
|
||||
IRONIC_TO_OVIRT_DEVICE_MAPPING.items()}
|
||||
|
||||
OVIRT_TO_IRONIC_POWER_MAPPING = {
|
||||
'down': states.POWER_OFF,
|
||||
'error': states.ERROR,
|
||||
'image_locked': states.POWER_OFF,
|
||||
'migrating': states.POWER_ON,
|
||||
'not_responding': states.ERROR,
|
||||
'paused': states.ERROR,
|
||||
'powering_down': states.POWER_OFF,
|
||||
'powering_up': states.POWER_ON,
|
||||
'reboot_in_progress': states.POWER_ON,
|
||||
'wait_for_launch': states.POWER_ON,
|
||||
'up': states.POWER_ON
|
||||
}
|
||||
|
||||
opts = [
|
||||
cfg.StrOpt('address',
|
||||
default='127.0.0.1',
|
||||
help='oVirt address'),
|
||||
cfg.StrOpt('username',
|
||||
default='admin@internal',
|
||||
help='oVirt username'),
|
||||
cfg.StrOpt('password',
|
||||
help='oVirt password'),
|
||||
cfg.StrOpt('insecure',
|
||||
default=False,
|
||||
help='Skips verification of the oVirt host certificate'),
|
||||
cfg.StrOpt('ca_file',
|
||||
help='oVirt path to a CA file'),
|
||||
]
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(opts, group='ovirt')
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
PROPERTIES = {
|
||||
'ovirt_address': _("Address of the oVirt Manager"),
|
||||
'ovirt_username': _("oVirt username"),
|
||||
'ovirt_password': _("oVirt password"),
|
||||
'ovirt_insecure': _("Skips oVirt host certificate's verification"),
|
||||
'ovirt_ca_file': _("oVirt path to a CA file"),
|
||||
'ovirt_vm_name': _("Name of the VM in oVirt. Required."),
|
||||
}
|
||||
|
||||
|
||||
def _parse_driver_info(node):
|
||||
"""Gets the driver specific node driver info.
|
||||
|
||||
This method validates whether the 'driver_info' property of the
|
||||
supplied node contains the required information for this driver.
|
||||
|
||||
:param node: an Ironic Node object.
|
||||
:returns: a dict containing information from driver_info (or where
|
||||
applicable, config values).
|
||||
:raises: MissingParameterValue, if some required parameter(s) are missing
|
||||
in the node's driver_info.
|
||||
:raises: InvalidParameterValue, if some parameter(s) have invalid value(s)
|
||||
in the node's driver_info.
|
||||
"""
|
||||
conf_info = {attr: getattr(CONF.ovirt, attr) for attr in CONF.ovirt}
|
||||
node_info = node.driver_info or {}
|
||||
driver_info = {}
|
||||
for prop in PROPERTIES:
|
||||
node_value = node_info.get(prop)
|
||||
conf_value = conf_info.get(prop.replace('ovirt_', ''))
|
||||
value = node_value if node_value is not None else conf_value
|
||||
if value is None and prop not in ['ovirt_ca_file', 'ovirt_insecure']:
|
||||
raise exception.MissingParameterValue(
|
||||
_("%(prop)s is not set either in the configuration or"
|
||||
"in the node's driver_info"))
|
||||
else:
|
||||
driver_info[prop] = value
|
||||
insecure = driver_info['ovirt_insecure']
|
||||
ovirt_ca_file = driver_info['ovirt_ca_file']
|
||||
if not insecure and ovirt_ca_file is None:
|
||||
msg = _("Missing ovirt_ca_file in the node's driver_info")
|
||||
raise exception.MissingParameterValue(msg)
|
||||
return driver_info
|
||||
|
||||
|
||||
def _getvm(driver_info):
|
||||
address = driver_info['ovirt_address']
|
||||
username = driver_info['ovirt_username']
|
||||
password = driver_info['ovirt_password']
|
||||
insecure = driver_info['ovirt_insecure']
|
||||
ca_file = driver_info['ovirt_ca_file']
|
||||
name = driver_info['ovirt_vm_name'].encode('ascii', 'ignore')
|
||||
url = "https://%s/ovirt-engine/api" % address
|
||||
try:
|
||||
connection = sdk.Connection(url=url, username=username,
|
||||
password=password, insecure=insecure,
|
||||
ca_file=ca_file)
|
||||
vms_service = connection.system_service().vms_service()
|
||||
vmsearch = vms_service.list(search='name=%s' % name)
|
||||
except sdk.Error as e:
|
||||
LOG.error("Could not fetch information about VM vm %(name)s, "
|
||||
"got error: %(error)s", {'name': name, 'error': e})
|
||||
raise staging_exception.oVirtError(err=e)
|
||||
if vmsearch:
|
||||
return vms_service.vm_service(vmsearch[0].id)
|
||||
else:
|
||||
raise staging_exception.oVirtError(_("VM with name "
|
||||
"%s was not found") % name)
|
||||
|
||||
|
||||
class oVirtPower(base.PowerInterface):
|
||||
|
||||
def get_properties(self):
|
||||
return PROPERTIES
|
||||
|
||||
def validate(self, task):
|
||||
"""Check if node.driver_info contains ovirt_vm_name.
|
||||
|
||||
:param task: a TaskManager instance.
|
||||
:raises: MissingParameterValue, if some of the required parameters are
|
||||
missing in the node's driver_info.
|
||||
:raises: InvalidParameterValue, if some of the parameters have invalid
|
||||
values in the node's driver_info.
|
||||
"""
|
||||
_parse_driver_info(task.node)
|
||||
|
||||
def get_power_state(self, task):
|
||||
"""Gets the current power state.
|
||||
|
||||
:param task: a TaskManager instance.
|
||||
:returns: one of :mod:`ironic.common.states`
|
||||
:raises: MissingParameterValue, if some required parameter(s) are
|
||||
missing in the node's driver_info.
|
||||
:raises: InvalidParameterValue, if some parameter(s) have invalid
|
||||
value(s) in the node's driver_info.
|
||||
"""
|
||||
driver_info = _parse_driver_info(task.node)
|
||||
vm_name = driver_info['ovirt_vm_name']
|
||||
vm = _getvm(driver_info)
|
||||
status = vm.get().status.value
|
||||
if status not in OVIRT_TO_IRONIC_POWER_MAPPING:
|
||||
msg = ("oVirt returned unknown state for node %(node)s "
|
||||
"and vm %(vm)s")
|
||||
LOG.error(msg, {'node': task.node.uuid, 'vm': vm_name})
|
||||
return states.ERROR
|
||||
else:
|
||||
return OVIRT_TO_IRONIC_POWER_MAPPING[status]
|
||||
|
||||
@task_manager.require_exclusive_lock
|
||||
def set_power_state(self, task, target_state, timeout=None):
|
||||
"""Turn the current power state on or off.
|
||||
|
||||
:param task: a TaskManager instance.
|
||||
:param target_state: The desired power state POWER_ON, POWER_OFF or
|
||||
REBOOT from :mod:`ironic.common.states`.
|
||||
:raises: MissingParameterValue, if some required parameter(s) are
|
||||
missing in the node's driver_info.
|
||||
:raises: InvalidParameterValue, if some parameter(s) have invalid
|
||||
value(s) in the node's driver_info OR if an invalid power state
|
||||
was specified.
|
||||
"""
|
||||
driver_info = _parse_driver_info(task.node)
|
||||
vm_name = driver_info['ovirt_vm_name']
|
||||
vm = _getvm(driver_info)
|
||||
try:
|
||||
if target_state == states.POWER_OFF:
|
||||
vm.stop()
|
||||
elif target_state == states.POWER_ON:
|
||||
vm.start()
|
||||
elif target_state == states.REBOOT:
|
||||
vm.reboot()
|
||||
else:
|
||||
msg = _("'set_power_state' called with invalid power "
|
||||
"state '%s'") % target_state
|
||||
raise exception.InvalidParameterValue(msg)
|
||||
except sdk.Error as e:
|
||||
LOG.error("Could not change status of VM vm %(name)s "
|
||||
"got error: %(error)s", {'name': vm_name, 'error': e})
|
||||
raise staging_exception.oVirtError(err=e)
|
||||
|
||||
@task_manager.require_exclusive_lock
|
||||
def reboot(self, task, timeout=None):
|
||||
"""Reboot the node.
|
||||
|
||||
:param task: a TaskManager instance.
|
||||
:raises: MissingParameterValue, if some required parameter(s) are
|
||||
missing in the node's driver_info.
|
||||
:raises: InvalidParameterValue, if some parameter(s) have invalid
|
||||
value(s) in the node's driver_info.
|
||||
:raises: ovirtsdk4.Error, if error encountered from
|
||||
oVirt operation.
|
||||
"""
|
||||
driver_info = _parse_driver_info(task.node)
|
||||
vm_name = driver_info['ovirt_vm_name']
|
||||
vm = _getvm(driver_info)
|
||||
try:
|
||||
vm.reboot()
|
||||
except sdk.Error as e:
|
||||
LOG.error("Could not restart VM vm %(name)s "
|
||||
"got error: %(error)s", {'name': vm_name, 'error': e})
|
||||
raise staging_exception.oVirtError(err=e)
|
||||
|
||||
|
||||
class oVirtManagement(base.ManagementInterface):
|
||||
|
||||
def get_properties(self):
|
||||
return PROPERTIES
|
||||
|
||||
def validate(self, task):
|
||||
"""Check that 'driver_info' contains ovirt_vm_name.
|
||||
|
||||
Validates whether the 'driver_info' property of the supplied
|
||||
task's node contains the required credentials information.
|
||||
|
||||
:param task: a task from TaskManager.
|
||||
:raises: MissingParameterValue, if some required parameter(s) are
|
||||
missing in the node's driver_info.
|
||||
:raises: InvalidParameterValue, if some parameter(s) have invalid
|
||||
value(s) in the node's driver_info.
|
||||
"""
|
||||
_parse_driver_info(task.node)
|
||||
|
||||
def get_supported_boot_devices(self, task):
|
||||
"""Get a list of the supported boot devices.
|
||||
|
||||
:returns: A list with the supported boot devices defined
|
||||
in :mod:`ironic.common.boot_devices`.
|
||||
"""
|
||||
return sorted(list(IRONIC_TO_OVIRT_DEVICE_MAPPING))
|
||||
|
||||
def get_boot_device(self, task):
|
||||
"""Get the current boot device for a node.
|
||||
|
||||
:param task: a task from TaskManager.
|
||||
:returns: a dictionary containing:
|
||||
'boot_device': one of the ironic.common.boot_devices or None
|
||||
'persistent': True if boot device is persistent, False otherwise
|
||||
:raises: MissingParameterValue, if some required parameter(s) are
|
||||
missing in the node's driver_info.
|
||||
:raises: InvalidParameterValue, if some parameter(s) have invalid
|
||||
value(s) in the node's driver_info.
|
||||
:raises: oVirtError, if error encountered from
|
||||
oVirt operation.
|
||||
"""
|
||||
driver_info = _parse_driver_info(task.node)
|
||||
vm = _getvm(driver_info)
|
||||
boot_dev = vm.os.boot[0].get_dev()
|
||||
persistent = True
|
||||
ironic_boot_dev = OVIRT_TO_IRONIC_DEVICE_MAPPING.get(boot_dev)
|
||||
if not ironic_boot_dev:
|
||||
persistent = False
|
||||
msg = _("oVirt returned unknown boot device '%(device)s' "
|
||||
"for node %(node)s")
|
||||
LOG.error(msg, {'device': boot_dev, 'node': task.node.uuid})
|
||||
raise staging_exception.oVirtError(msg.format(device=boot_dev,
|
||||
node=task.node.uuid))
|
||||
|
||||
return {'boot_device': ironic_boot_dev, 'persistent': persistent}
|
||||
|
||||
@task_manager.require_exclusive_lock
|
||||
def set_boot_device(self, task, device, persistent=False):
|
||||
"""Set the boot device for a node.
|
||||
|
||||
:param task: a task from TaskManager.
|
||||
:param device: ironic.common.boot_devices
|
||||
:param persistent: This argument is ignored.
|
||||
:raises: MissingParameterValue, if some required parameter(s) are
|
||||
missing in the node's driver_info.
|
||||
:raises: InvalidParameterValue, if some parameter(s) have invalid
|
||||
value(s) in the node's driver_info.
|
||||
"""
|
||||
try:
|
||||
boot_dev = IRONIC_TO_OVIRT_DEVICE_MAPPING[device]
|
||||
except KeyError:
|
||||
raise exception.InvalidParameterValue(_(
|
||||
"Invalid boot device %s specified.") % device)
|
||||
|
||||
driver_info = _parse_driver_info(task.node)
|
||||
vm = _getvm(driver_info)
|
||||
try:
|
||||
boot = otypes.Boot(devices=[otypes.BootDevice(boot_dev)])
|
||||
bootos = otypes.OperatingSystem(boot=boot)
|
||||
vm.update(otypes.Vm(os=bootos))
|
||||
except sdk.Error as e:
|
||||
LOG.error("Setting boot device failed for node %(node_id)s "
|
||||
"with error: %(error)s",
|
||||
{'node_id': task.node.uuid, 'error': e})
|
||||
raise staging_exception.oVirtError(err=e)
|
||||
|
||||
def get_sensors_data(self, task):
|
||||
"""Get sensors data.
|
||||
|
||||
:param task: a TaskManager instance.
|
||||
:raises: FailedToGetSensorData when getting the sensor data fails.
|
||||
:raises: FailedToParseSensorData when parsing sensor data fails.
|
||||
:returns: returns a consistent format dict of sensor data grouped by
|
||||
sensor type, which can be processed by Ceilometer.
|
||||
"""
|
||||
raise NotImplementedError()
|
1
ironic_staging_drivers/ovirt/python-requirements.txt
Normal file
1
ironic_staging_drivers/ovirt/python-requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
ovirt-engine-sdk-python>=4.0.0 # Apache-2.0
|
0
ironic_staging_drivers/tests/unit/ovirt/__init__.py
Normal file
0
ironic_staging_drivers/tests/unit/ovirt/__init__.py
Normal file
112
ironic_staging_drivers/tests/unit/ovirt/test_ovirt.py
Normal file
112
ironic_staging_drivers/tests/unit/ovirt/test_ovirt.py
Normal file
@ -0,0 +1,112 @@
|
||||
# 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.
|
||||
|
||||
"""Test class for oVirt driver module."""
|
||||
|
||||
import time
|
||||
|
||||
from ironic.common import boot_devices
|
||||
from ironic.common import states
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.tests.unit.conductor import mgr_utils
|
||||
from ironic.tests.unit.db import base as db_base
|
||||
from ironic.tests.unit.objects import utils as obj_utils
|
||||
import mock
|
||||
|
||||
from ironic_staging_drivers.ovirt import ovirt as ovirt_power
|
||||
|
||||
|
||||
def _ovirt_info():
|
||||
driver_info = {'ovirt_address': '127.0.0.1',
|
||||
'ovirt_username': 'jhendrix@internal',
|
||||
'ovirt_password': 'changeme',
|
||||
'ovirt__insecure': True,
|
||||
'ovirt_ca_file': None,
|
||||
'ovirt_vm_name': 'jimi'}
|
||||
return driver_info
|
||||
|
||||
|
||||
@mock.patch.object(time, 'sleep', lambda *_: None)
|
||||
class oVirtDriverTestCase(db_base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(oVirtDriverTestCase, self).setUp()
|
||||
self.config(enabled_power_interfaces='staging-ovirt',
|
||||
enabled_management_interfaces='staging-ovirt')
|
||||
namespace = 'ironic.hardware.types'
|
||||
mgr_utils.mock_the_extension_manager(driver='staging-ovirt',
|
||||
namespace=namespace)
|
||||
self.node = obj_utils.create_test_node(self.context,
|
||||
driver='staging-ovirt',
|
||||
driver_info=_ovirt_info())
|
||||
self.port = obj_utils.create_test_port(self.context,
|
||||
node_id=self.node.id)
|
||||
|
||||
def test__parse_parameters(self):
|
||||
params = ovirt_power._parse_driver_info(self.node)
|
||||
self.assertEqual('127.0.0.1', params['ovirt_address'])
|
||||
self.assertEqual('jhendrix@internal', params['ovirt_username'])
|
||||
self.assertEqual('changeme', params['ovirt_password'])
|
||||
self.assertEqual('jimi', params['ovirt_vm_name'])
|
||||
|
||||
def test_get_properties(self):
|
||||
expected = list(ovirt_power.PROPERTIES.keys())
|
||||
with task_manager.acquire(
|
||||
self.context, self.node.uuid, shared=False) as task:
|
||||
driver_properties = [prop for prop in task.driver.get_properties()
|
||||
if prop in expected]
|
||||
self.assertEqual(sorted(expected), sorted(driver_properties))
|
||||
|
||||
@mock.patch.object(ovirt_power.oVirtPower, 'set_power_state',
|
||||
autospec=True, spec_set=True)
|
||||
def test_set_power_state_power_on(self, mock_power):
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
task.driver.power.set_power_state(task, states.POWER_ON)
|
||||
mock_power.assert_called_once_with(task.driver.power, task,
|
||||
states.POWER_ON)
|
||||
|
||||
@mock.patch.object(ovirt_power.oVirtPower, 'set_power_state',
|
||||
autospec=True, spec_set=True)
|
||||
def test_set_power_state_power_off(self, mock_power):
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
task.driver.power.set_power_state(task, states.POWER_OFF)
|
||||
mock_power.assert_called_once_with(task.driver.power, task,
|
||||
states.POWER_OFF)
|
||||
|
||||
def test_get_supported_power_states(self):
|
||||
with task_manager.acquire(
|
||||
self.context, self.node.uuid, shared=True) as task:
|
||||
pstates = task.driver.power.get_supported_power_states(task)
|
||||
self.assertEqual([states.POWER_ON, states.POWER_OFF,
|
||||
states.REBOOT], pstates)
|
||||
|
||||
def test_get_supported_boot_devices(self):
|
||||
with task_manager.acquire(
|
||||
self.context, self.node.uuid, shared=True) as task:
|
||||
bdevices = task.driver.management.get_supported_boot_devices(task)
|
||||
self.assertEqual([boot_devices.CDROM, boot_devices.DISK,
|
||||
boot_devices.PXE], bdevices)
|
||||
|
||||
@mock.patch.object(ovirt_power.oVirtManagement, 'get_boot_device',
|
||||
return_value='hd')
|
||||
def test_get_boot_device(self, mock_management):
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
boot_dev = task.driver.management.get_boot_device(task)
|
||||
self.assertEqual('hd', boot_dev)
|
||||
|
||||
@mock.patch.object(ovirt_power.oVirtManagement, 'set_boot_device',
|
||||
autospec=True, spec_set=True)
|
||||
def test_set_boot_device(self, mock_power):
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
task.driver.management.set_boot_device(task, boot_devices.DISK)
|
||||
mock_power.assert_called_once_with(task.driver.management, task,
|
||||
boot_devices.DISK)
|
@ -49,11 +49,13 @@ ironic.hardware.interfaces.deploy =
|
||||
ironic.hardware.interfaces.management =
|
||||
staging-amt = ironic_staging_drivers.amt.management:AMTManagement
|
||||
staging-libvirt = ironic_staging_drivers.libvirt.power:LibvirtManagement
|
||||
staging-ovirt = ironic_staging_drivers.ovirt.ovirt:oVirtManagement
|
||||
|
||||
ironic.hardware.interfaces.power =
|
||||
staging-amt = ironic_staging_drivers.amt.power:AMTPower
|
||||
staging-iboot = ironic_staging_drivers.iboot.power:IBootPower
|
||||
staging-libvirt = ironic_staging_drivers.libvirt.power:LibvirtPower
|
||||
staging-ovirt = ironic_staging_drivers.ovirt.ovirt:oVirtPower
|
||||
staging-wol = ironic_staging_drivers.wol.power:WakeOnLanPower
|
||||
|
||||
ironic.hardware.interfaces.vendor =
|
||||
@ -65,6 +67,7 @@ ironic.hardware.types =
|
||||
staging-iboot = ironic_staging_drivers.iboot:IBootHardware
|
||||
staging-nm = ironic_staging_drivers.intel_nm:IntelNMHardware
|
||||
staging-libvirt = ironic_staging_drivers.libvirt:LibvirtHardware
|
||||
staging-ovirt = ironic_staging_drivers.ovirt:oVirtHardware
|
||||
staging-wol = ironic_staging_drivers.wol:WOLHardware
|
||||
|
||||
[build_sphinx]
|
||||
|
Loading…
Reference in New Issue
Block a user