summaryrefslogtreecommitdiff
path: root/ironic/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'ironic/drivers')
-rw-r--r--ironic/drivers/agent.py28
-rw-r--r--ironic/drivers/fake.py47
-rw-r--r--ironic/drivers/modules/msftocs/__init__.py0
-rw-r--r--ironic/drivers/modules/msftocs/common.py110
-rw-r--r--ironic/drivers/modules/msftocs/management.py121
-rw-r--r--ironic/drivers/modules/msftocs/msftocsclient.py176
-rw-r--r--ironic/drivers/modules/msftocs/power.py105
-rw-r--r--ironic/drivers/modules/seamicro.py672
-rw-r--r--ironic/drivers/modules/virtualbox.py393
-rw-r--r--ironic/drivers/pxe.py76
10 files changed, 0 insertions, 1728 deletions
diff --git a/ironic/drivers/agent.py b/ironic/drivers/agent.py
index 44065a971..c4c36f02c 100644
--- a/ironic/drivers/agent.py
+++ b/ironic/drivers/agent.py
@@ -27,7 +27,6 @@ from ironic.drivers.modules import pxe
from ironic.drivers.modules import ssh
from ironic.drivers.modules.ucs import management as ucs_mgmt
from ironic.drivers.modules.ucs import power as ucs_power
-from ironic.drivers.modules import virtualbox
# For backward compatibility
@@ -87,33 +86,6 @@ class AgentAndSSHDriver(base.BaseDriver):
self.console = ssh.ShellinaboxConsole()
-class AgentAndVirtualBoxDriver(base.BaseDriver):
- """Agent + VirtualBox driver.
-
- NOTE: This driver is meant only for testing environments.
-
- This driver implements the `core` functionality, combining
- :class:`ironic.drivers.modules.virtualbox.VirtualBoxPower` (for power
- on/off and reboot of VirtualBox virtual machines), with
- :class:`ironic.drivers.modules.agent.AgentDeploy` (for image
- deployment). Implementations are in those respective classes; this class
- is merely the glue between them.
- """
-
- supported = False
-
- def __init__(self):
- if not importutils.try_import('pyremotevbox'):
- raise exception.DriverLoadError(
- driver=self.__class__.__name__,
- reason=_("Unable to import pyremotevbox library"))
- self.power = virtualbox.VirtualBoxPower()
- self.boot = pxe.PXEBoot()
- self.deploy = agent.AgentDeploy()
- self.management = virtualbox.VirtualBoxManagement()
- self.raid = agent.AgentRAID()
-
-
class AgentAndUcsDriver(base.BaseDriver):
"""Agent + Cisco UCSM driver.
diff --git a/ironic/drivers/fake.py b/ironic/drivers/fake.py
index be838e975..e926aaa8f 100644
--- a/ironic/drivers/fake.py
+++ b/ironic/drivers/fake.py
@@ -42,18 +42,14 @@ from ironic.drivers.modules.irmc import inspect as irmc_inspect
from ironic.drivers.modules.irmc import management as irmc_management
from ironic.drivers.modules.irmc import power as irmc_power
from ironic.drivers.modules import iscsi_deploy
-from ironic.drivers.modules.msftocs import management as msftocs_management
-from ironic.drivers.modules.msftocs import power as msftocs_power
from ironic.drivers.modules.oneview import common as oneview_common
from ironic.drivers.modules.oneview import management as oneview_management
from ironic.drivers.modules.oneview import power as oneview_power
from ironic.drivers.modules import pxe
-from ironic.drivers.modules import seamicro
from ironic.drivers.modules import snmp
from ironic.drivers.modules import ssh
from ironic.drivers.modules.ucs import management as ucs_mgmt
from ironic.drivers.modules.ucs import power as ucs_power
-from ironic.drivers.modules import virtualbox
from ironic.drivers import utils
@@ -146,23 +142,6 @@ class FakeIPMINativeDriver(base.BaseDriver):
self.management = ipminative.NativeIPMIManagement()
-class FakeSeaMicroDriver(base.BaseDriver):
- """Fake SeaMicro driver."""
-
- supported = False
-
- def __init__(self):
- if not importutils.try_import('seamicroclient'):
- raise exception.DriverLoadError(
- driver=self.__class__.__name__,
- reason=_("Unable to import seamicroclient library"))
- self.power = seamicro.Power()
- self.deploy = fake.FakeDeploy()
- self.management = seamicro.Management()
- self.vendor = seamicro.VendorPassthru()
- self.console = seamicro.ShellinaboxConsole()
-
-
class FakeAgentDriver(base.BaseDriver):
"""Example implementation of an AgentDriver."""
@@ -230,21 +209,6 @@ class FakeIRMCDriver(base.BaseDriver):
self.inspect = irmc_inspect.IRMCInspect()
-class FakeVirtualBoxDriver(base.BaseDriver):
- """Fake VirtualBox driver."""
-
- supported = False
-
- def __init__(self):
- if not importutils.try_import('pyremotevbox'):
- raise exception.DriverLoadError(
- driver=self.__class__.__name__,
- reason=_("Unable to import pyremotevbox library"))
- self.power = virtualbox.VirtualBoxPower()
- self.deploy = fake.FakeDeploy()
- self.management = virtualbox.VirtualBoxManagement()
-
-
class FakeIPMIToolInspectorDriver(base.BaseDriver):
"""Fake Inspector driver."""
@@ -260,17 +224,6 @@ class FakeIPMIToolInspectorDriver(base.BaseDriver):
self.inspect = inspector.Inspector()
-class FakeMSFTOCSDriver(base.BaseDriver):
- """Fake MSFT OCS driver."""
-
- supported = False
-
- def __init__(self):
- self.power = msftocs_power.MSFTOCSPower()
- self.deploy = fake.FakeDeploy()
- self.management = msftocs_management.MSFTOCSManagement()
-
-
class FakeUcsDriver(base.BaseDriver):
"""Fake UCS driver."""
diff --git a/ironic/drivers/modules/msftocs/__init__.py b/ironic/drivers/modules/msftocs/__init__.py
deleted file mode 100644
index e69de29bb..000000000
--- a/ironic/drivers/modules/msftocs/__init__.py
+++ /dev/null
diff --git a/ironic/drivers/modules/msftocs/common.py b/ironic/drivers/modules/msftocs/common.py
deleted file mode 100644
index 97d069967..000000000
--- a/ironic/drivers/modules/msftocs/common.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# Copyright 2015 Cloudbase Solutions Srl
-# 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.
-
-import copy
-import re
-
-import six
-
-from ironic.common import exception
-from ironic.common.i18n import _
-from ironic.drivers.modules.msftocs import msftocsclient
-
-REQUIRED_PROPERTIES = {
- 'msftocs_base_url': _('Base url of the OCS chassis manager REST API, '
- 'e.g.: http://10.0.0.1:8000. Required.'),
- 'msftocs_blade_id': _('Blade id, must be a number between 1 and the '
- 'maximum number of blades available in the chassis. '
- 'Required.'),
- 'msftocs_username': _('Username to access the chassis manager REST API. '
- 'Required.'),
- 'msftocs_password': _('Password to access the chassis manager REST API. '
- 'Required.'),
-}
-
-
-def get_client_info(driver_info):
- """Returns an instance of the REST API client and the blade id.
-
- :param driver_info: the node's driver_info dict.
- """
- client = msftocsclient.MSFTOCSClientApi(driver_info['msftocs_base_url'],
- driver_info['msftocs_username'],
- driver_info['msftocs_password'])
- return client, driver_info['msftocs_blade_id']
-
-
-def get_properties():
- """Returns the driver's properties."""
- return copy.deepcopy(REQUIRED_PROPERTIES)
-
-
-def _is_valid_url(url):
- """Checks whether a URL is valid.
-
- :param url: a url string.
- :returns: True if the url is valid or None, False otherwise.
- """
- r = re.compile(
- r'^https?://'
- r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)*[A-Z]{2,6}\.?|'
- r'localhost|'
- r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
- r'(?::\d+)?'
- r'(?:/?|[/?]\S+)$', re.IGNORECASE)
-
- return bool(isinstance(url, six.string_types) and r.search(url))
-
-
-def _check_required_properties(driver_info):
- """Checks if all required properties are present.
-
- :param driver_info: the node's driver_info dict.
- :raises: MissingParameterValue if one or more required properties are
- missing.
- """
- missing_properties = set(REQUIRED_PROPERTIES) - set(driver_info)
- if missing_properties:
- raise exception.MissingParameterValue(
- _('The following parameters were missing: %s') %
- ' '.join(missing_properties))
-
-
-def parse_driver_info(node):
- """Checks for the required properties and values validity.
-
- :param node: the target node.
- :raises: MissingParameterValue if one or more required properties are
- missing.
- :raises: InvalidParameterValue if a parameter value is invalid.
- """
- driver_info = node.driver_info
- _check_required_properties(driver_info)
-
- base_url = driver_info.get('msftocs_base_url')
- if not _is_valid_url(base_url):
- raise exception.InvalidParameterValue(
- _('"%s" is not a valid "msftocs_base_url"') % base_url)
-
- blade_id = driver_info.get('msftocs_blade_id')
- try:
- blade_id = int(blade_id)
- except ValueError:
- raise exception.InvalidParameterValue(
- _('"%s" is not a valid "msftocs_blade_id"') % blade_id)
- if blade_id < 1:
- raise exception.InvalidParameterValue(
- _('"msftocs_blade_id" must be greater than 0. The provided value '
- 'is: %s') % blade_id)
diff --git a/ironic/drivers/modules/msftocs/management.py b/ironic/drivers/modules/msftocs/management.py
deleted file mode 100644
index f148c4394..000000000
--- a/ironic/drivers/modules/msftocs/management.py
+++ /dev/null
@@ -1,121 +0,0 @@
-# Copyright 2015 Cloudbase Solutions Srl
-# 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 ironic.common import boot_devices
-from ironic.common import exception
-from ironic.common.i18n import _
-from ironic.conductor import task_manager
-from ironic.drivers import base
-from ironic.drivers.modules.msftocs import common as msftocs_common
-from ironic.drivers.modules.msftocs import msftocsclient
-from ironic.drivers import utils as drivers_utils
-
-BOOT_TYPE_TO_DEVICE_MAP = {
- msftocsclient.BOOT_TYPE_FORCE_PXE: boot_devices.PXE,
- msftocsclient.BOOT_TYPE_FORCE_DEFAULT_HDD: boot_devices.DISK,
- msftocsclient.BOOT_TYPE_FORCE_INTO_BIOS_SETUP: boot_devices.BIOS,
-}
-DEVICE_TO_BOOT_TYPE_MAP = {v: k for k, v in BOOT_TYPE_TO_DEVICE_MAP.items()}
-
-DEFAULT_BOOT_DEVICE = boot_devices.DISK
-
-
-class MSFTOCSManagement(base.ManagementInterface):
- def get_properties(self):
- """Returns the driver's properties."""
- return msftocs_common.get_properties()
-
- def validate(self, task):
- """Validate the driver_info in the node.
-
- Check if the driver_info contains correct required fields.
-
- :param task: a TaskManager instance containing the target node.
- :raises: MissingParameterValue if any required parameters are missing.
- :raises: InvalidParameterValue if any parameters have invalid values.
- """
- msftocs_common.parse_driver_info(task.node)
-
- def get_supported_boot_devices(self, task):
- """Get a list of the supported boot devices.
-
- :param task: a task from TaskManager.
- :returns: A list with the supported boot devices.
- """
- return list(BOOT_TYPE_TO_DEVICE_MAP.values())
-
- def _check_valid_device(self, device, node):
- """Checks if the desired boot device is valid for this driver.
-
- :param device: a boot device.
- :param node: the target node.
- :raises: InvalidParameterValue if the boot device is not valid.
- """
- if device not in DEVICE_TO_BOOT_TYPE_MAP:
- raise exception.InvalidParameterValue(
- _("set_boot_device called with invalid device %(device)s for "
- "node %(node_id)s.") %
- {'device': device, 'node_id': node.uuid})
-
- @task_manager.require_exclusive_lock
- def set_boot_device(self, task, device, persistent=False):
- """Set the boot device for the task's node.
-
- Set the boot device to use on next boot of the node.
-
- :param task: a task from TaskManager.
- :param device: the boot device.
- :param persistent: Boolean value. True if the boot device will
- persist to all future boots, False if not.
- Default: False.
- :raises: InvalidParameterValue if an invalid boot device is specified.
- """
- self._check_valid_device(device, task.node)
- client, blade_id = msftocs_common.get_client_info(
- task.node.driver_info)
-
- boot_mode = drivers_utils.get_node_capability(task.node, 'boot_mode')
- uefi = (boot_mode == 'uefi')
-
- boot_type = DEVICE_TO_BOOT_TYPE_MAP[device]
- client.set_next_boot(blade_id, boot_type, persistent, uefi)
-
- def get_boot_device(self, task):
- """Get the current boot device for the task's node.
-
- Returns the current boot device of the node.
-
- :param task: a task from TaskManager.
- :returns: a dictionary containing:
-
- :boot_device: the boot device
- :persistent: Whether the boot device will persist to all
- future boots or not, None if it is unknown.
-
- """
- client, blade_id = msftocs_common.get_client_info(
- task.node.driver_info)
- device = BOOT_TYPE_TO_DEVICE_MAP.get(
- client.get_next_boot(blade_id), DEFAULT_BOOT_DEVICE)
-
- # Note(alexpilotti): Although the ChasssisManager REST API allows to
- # specify the persistent boot status in SetNextBoot, currently it does
- # not provide a way to retrieve the value with GetNextBoot.
- # This is being addressed in the ChassisManager API.
- return {'boot_device': device,
- 'persistent': None}
-
- def get_sensors_data(self, task):
- raise NotImplementedError()
diff --git a/ironic/drivers/modules/msftocs/msftocsclient.py b/ironic/drivers/modules/msftocs/msftocsclient.py
deleted file mode 100644
index d511c68ad..000000000
--- a/ironic/drivers/modules/msftocs/msftocsclient.py
+++ /dev/null
@@ -1,176 +0,0 @@
-# Copyright 2015 Cloudbase Solutions Srl
-# 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.
-
-"""
-MSFT OCS ChassisManager v2.0 REST API client
-https://github.com/MSOpenTech/ChassisManager
-"""
-
-import posixpath
-from xml import etree
-
-from oslo_log import log
-import requests
-from requests import auth
-from requests import exceptions as requests_exceptions
-
-from ironic.common import exception
-from ironic.common.i18n import _, _LE
-
-LOG = log.getLogger(__name__)
-
-WCSNS = 'http://schemas.datacontract.org/2004/07/Microsoft.GFS.WCS.Contracts'
-COMPLETION_CODE_SUCCESS = "Success"
-
-BOOT_TYPE_UNKNOWN = 0
-BOOT_TYPE_NO_OVERRIDE = 1
-BOOT_TYPE_FORCE_PXE = 2
-BOOT_TYPE_FORCE_DEFAULT_HDD = 3
-BOOT_TYPE_FORCE_INTO_BIOS_SETUP = 4
-BOOT_TYPE_FORCE_FLOPPY_OR_REMOVABLE = 5
-
-BOOT_TYPE_MAP = {
- 'Unknown': BOOT_TYPE_UNKNOWN,
- 'NoOverride': BOOT_TYPE_NO_OVERRIDE,
- 'ForcePxe': BOOT_TYPE_FORCE_PXE,
- 'ForceDefaultHdd': BOOT_TYPE_FORCE_DEFAULT_HDD,
- 'ForceIntoBiosSetup': BOOT_TYPE_FORCE_INTO_BIOS_SETUP,
- 'ForceFloppyOrRemovable': BOOT_TYPE_FORCE_FLOPPY_OR_REMOVABLE,
-}
-
-POWER_STATUS_ON = "ON"
-POWER_STATUS_OFF = "OFF"
-
-
-class MSFTOCSClientApi(object):
- def __init__(self, base_url, username, password):
- self._base_url = base_url
- self._username = username
- self._password = password
-
- def _exec_cmd(self, rel_url):
- """Executes a command by calling the chassis manager API."""
- url = posixpath.join(self._base_url, rel_url)
- try:
- response = requests.get(
- url, auth=auth.HTTPBasicAuth(self._username, self._password))
- response.raise_for_status()
- except requests_exceptions.RequestException as ex:
- msg = _("HTTP call failed: %s") % ex
- LOG.exception(msg)
- raise exception.MSFTOCSClientApiException(msg)
-
- xml_response = response.text
- LOG.debug("Call to %(url)s got response: %(xml_response)s",
- {"url": url, "xml_response": xml_response})
- return xml_response
-
- def _check_completion_code(self, xml_response):
- try:
- et = etree.ElementTree.fromstring(xml_response)
- except etree.ElementTree.ParseError as ex:
- LOG.exception(_LE("XML parsing failed: %s"), ex)
- raise exception.MSFTOCSClientApiException(
- _("Invalid XML: %s") % xml_response)
- item = et.find("./n:completionCode", namespaces={'n': WCSNS})
- if item is None or item.text != COMPLETION_CODE_SUCCESS:
- raise exception.MSFTOCSClientApiException(
- _("Operation failed: %s") % xml_response)
- return et
-
- def get_blade_state(self, blade_id):
- """Returns whether a blade's chipset is receiving power (soft-power).
-
- :param blade_id: the blade id
- :returns: one of:
- POWER_STATUS_ON,
- POWER_STATUS_OFF
- :raises: MSFTOCSClientApiException
- """
- et = self._check_completion_code(
- self._exec_cmd("GetBladeState?bladeId=%d" % blade_id))
- return et.find('./n:bladeState', namespaces={'n': WCSNS}).text
-
- def set_blade_on(self, blade_id):
- """Supplies power to a blade chipset (soft-power state).
-
- :param blade_id: the blade id
- :raises: MSFTOCSClientApiException
- """
- self._check_completion_code(
- self._exec_cmd("SetBladeOn?bladeId=%d" % blade_id))
-
- def set_blade_off(self, blade_id):
- """Shuts down a given blade (soft-power state).
-
- :param blade_id: the blade id
- :raises: MSFTOCSClientApiException
- """
- self._check_completion_code(
- self._exec_cmd("SetBladeOff?bladeId=%d" % blade_id))
-
- def set_blade_power_cycle(self, blade_id, off_time=0):
- """Performs a soft reboot of a given blade.
-
- :param blade_id: the blade id
- :param off_time: seconds to wait between shutdown and boot
- :raises: MSFTOCSClientApiException
- """
- self._check_completion_code(
- self._exec_cmd("SetBladeActivePowerCycle?bladeId=%(blade_id)d&"
- "offTime=%(off_time)d" %
- {"blade_id": blade_id, "off_time": off_time}))
-
- def get_next_boot(self, blade_id):
- """Returns the next boot device configured for a given blade.
-
- :param blade_id: the blade id
- :returns: one of:
- BOOT_TYPE_UNKNOWN,
- BOOT_TYPE_NO_OVERRIDE,
- BOOT_TYPE_FORCE_PXE, BOOT_TYPE_FORCE_DEFAULT_HDD,
- BOOT_TYPE_FORCE_INTO_BIOS_SETUP,
- BOOT_TYPE_FORCE_FLOPPY_OR_REMOVABLE
- :raises: MSFTOCSClientApiException
- """
- et = self._check_completion_code(
- self._exec_cmd("GetNextBoot?bladeId=%d" % blade_id))
- return BOOT_TYPE_MAP[
- et.find('./n:nextBoot', namespaces={'n': WCSNS}).text]
-
- def set_next_boot(self, blade_id, boot_type, persistent=True, uefi=True):
- """Sets the next boot device for a given blade.
-
- :param blade_id: the blade id
- :param boot_type: possible values:
- BOOT_TYPE_UNKNOWN,
- BOOT_TYPE_NO_OVERRIDE,
- BOOT_TYPE_FORCE_PXE,
- BOOT_TYPE_FORCE_DEFAULT_HDD,
- BOOT_TYPE_FORCE_INTO_BIOS_SETUP,
- BOOT_TYPE_FORCE_FLOPPY_OR_REMOVABLE
- :param persistent: whether this setting affects the next boot only or
- every subsequent boot
- :param uefi: True if UEFI, False otherwise
- :raises: MSFTOCSClientApiException
- """
- self._check_completion_code(
- self._exec_cmd(
- "SetNextBoot?bladeId=%(blade_id)d&bootType=%(boot_type)d&"
- "uefi=%(uefi)s&persistent=%(persistent)s" %
- {"blade_id": blade_id,
- "boot_type": boot_type,
- "uefi": str(uefi).lower(),
- "persistent": str(persistent).lower()}))
diff --git a/ironic/drivers/modules/msftocs/power.py b/ironic/drivers/modules/msftocs/power.py
deleted file mode 100644
index e5ce62066..000000000
--- a/ironic/drivers/modules/msftocs/power.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# Copyright 2015 Cloudbase Solutions Srl
-# 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.
-
-"""
-MSFT OCS Power Driver
-"""
-from oslo_log import log
-
-from ironic.common import exception
-from ironic.common.i18n import _, _LE
-from ironic.common import states
-from ironic.conductor import task_manager
-from ironic.drivers import base
-from ironic.drivers.modules.msftocs import common as msftocs_common
-from ironic.drivers.modules.msftocs import msftocsclient
-
-LOG = log.getLogger(__name__)
-
-POWER_STATES_MAP = {
- msftocsclient.POWER_STATUS_ON: states.POWER_ON,
- msftocsclient.POWER_STATUS_OFF: states.POWER_OFF,
-}
-
-
-class MSFTOCSPower(base.PowerInterface):
- def get_properties(self):
- """Returns the driver's properties."""
- return msftocs_common.get_properties()
-
- def validate(self, task):
- """Validate the driver_info in the node.
-
- Check if the driver_info contains correct required fields.
-
- :param task: a TaskManager instance containing the target node.
- :raises: MissingParameterValue if any required parameters are missing.
- :raises: InvalidParameterValue if any parameters have invalid values.
- """
- msftocs_common.parse_driver_info(task.node)
-
- def get_power_state(self, task):
- """Get the power state from the node.
-
- :param task: a TaskManager instance containing the target node.
- :raises: MSFTOCSClientApiException.
- """
- client, blade_id = msftocs_common.get_client_info(
- task.node.driver_info)
- return POWER_STATES_MAP[client.get_blade_state(blade_id)]
-
- @task_manager.require_exclusive_lock
- def set_power_state(self, task, pstate):
- """Set the power state of the node.
-
- Turn the node power on or off.
-
- :param task: a TaskManager instance contains the target node.
- :param pstate: The desired power state of the node.
- :raises: PowerStateFailure if the power cannot set to pstate.
- :raises: InvalidParameterValue
- """
- client, blade_id = msftocs_common.get_client_info(
- task.node.driver_info)
-
- try:
- if pstate == states.POWER_ON:
- client.set_blade_on(blade_id)
- elif pstate == states.POWER_OFF:
- client.set_blade_off(blade_id)
- else:
- raise exception.InvalidParameterValue(
- _('Unsupported target_state: %s') % pstate)
- except exception.MSFTOCSClientApiException as ex:
- LOG.exception(_LE("Changing the power state to %(pstate)s failed. "
- "Error: %(err_msg)s"),
- {"pstate": pstate, "err_msg": ex})
- raise exception.PowerStateFailure(pstate=pstate)
-
- @task_manager.require_exclusive_lock
- def reboot(self, task):
- """Cycle the power of the node
-
- :param task: a TaskManager instance contains the target node.
- :raises: PowerStateFailure if failed to reboot.
- """
- client, blade_id = msftocs_common.get_client_info(
- task.node.driver_info)
- try:
- client.set_blade_power_cycle(blade_id)
- except exception.MSFTOCSClientApiException as ex:
- LOG.exception(_LE("Reboot failed. Error: %(err_msg)s"),
- {"err_msg": ex})
- raise exception.PowerStateFailure(pstate=states.REBOOT)
diff --git a/ironic/drivers/modules/seamicro.py b/ironic/drivers/modules/seamicro.py
deleted file mode 100644
index cf45bb6d0..000000000
--- a/ironic/drivers/modules/seamicro.py
+++ /dev/null
@@ -1,672 +0,0 @@
-# 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 SeaMicro interfaces.
-
-Provides basic power control of servers in SeaMicro chassis via
-python-seamicroclient.
-
-Provides vendor passthru methods for SeaMicro specific functionality.
-"""
-import os
-import re
-
-from oslo_log import log as logging
-from oslo_service import loopingcall
-from oslo_utils import importutils
-from six.moves.urllib import parse as urlparse
-
-from ironic.common import boot_devices
-from ironic.common import exception
-from ironic.common.i18n import _, _LE, _LW
-from ironic.common import states
-from ironic.common import utils
-from ironic.conductor import task_manager
-from ironic.conf import CONF
-from ironic.drivers import base
-from ironic.drivers.modules import console_utils
-
-seamicroclient = importutils.try_import('seamicroclient')
-if seamicroclient:
- from seamicroclient import client as seamicro_client
- from seamicroclient import exceptions as seamicro_client_exception
-
-LOG = logging.getLogger(__name__)
-
-_BOOT_DEVICES_MAP = {
- boot_devices.DISK: 'hd0',
- boot_devices.PXE: 'pxe',
-}
-
-REQUIRED_PROPERTIES = {
- 'seamicro_api_endpoint': _("API endpoint. Required."),
- 'seamicro_password': _("password. Required."),
- 'seamicro_server_id': _("server ID. Required."),
- 'seamicro_username': _("username. Required."),
-}
-OPTIONAL_PROPERTIES = {
- 'seamicro_api_version': _("version of SeaMicro API client; default is 2. "
- "Optional.")
-}
-COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy()
-COMMON_PROPERTIES.update(OPTIONAL_PROPERTIES)
-CONSOLE_PROPERTIES = {
- 'seamicro_terminal_port': _("node's UDP port to connect to. "
- "Only required for console access.")
-}
-PORT_BASE = 2000
-
-
-def _get_client(*args, **kwargs):
- """Creates the python-seamicro_client
-
- :param kwargs: A dict of keyword arguments to be passed to the method,
- which should contain: 'username', 'password',
- 'auth_url', 'api_version' parameters.
- :returns: SeaMicro API client.
- """
-
- cl_kwargs = {'username': kwargs['username'],
- 'password': kwargs['password'],
- 'auth_url': kwargs['api_endpoint']}
- try:
- return seamicro_client.Client(kwargs['api_version'], **cl_kwargs)
- except seamicro_client_exception.UnsupportedVersion as e:
- raise exception.InvalidParameterValue(_(
- "Invalid 'seamicro_api_version' parameter. Reason: %s.") % e)
-
-
-def _parse_driver_info(node):
- """Parses and creates seamicro driver info
-
- :param node: An Ironic node object.
- :returns: SeaMicro driver info.
- :raises: MissingParameterValue if any required parameters are missing.
- :raises: InvalidParameterValue if required parameter are invalid.
- """
-
- info = node.driver_info or {}
- missing_info = [key for key in REQUIRED_PROPERTIES if not info.get(key)]
- if missing_info:
- raise exception.MissingParameterValue(_(
- "SeaMicro driver requires the following parameters to be set in"
- " node's driver_info: %s.") % missing_info)
-
- api_endpoint = info.get('seamicro_api_endpoint')
- username = info.get('seamicro_username')
- password = info.get('seamicro_password')
- server_id = info.get('seamicro_server_id')
- api_version = info.get('seamicro_api_version', "2")
- port = info.get('seamicro_terminal_port')
-
- if port is not None:
- port = utils.validate_network_port(port, 'seamicro_terminal_port')
-
- r = re.compile(r"(^[0-9]+)/([0-9]+$)")
- if not r.match(server_id):
- raise exception.InvalidParameterValue(_(
- "Invalid 'seamicro_server_id' parameter in node's "
- "driver_info. Expected format of 'seamicro_server_id' "
- "is <int>/<int>"))
-
- url = urlparse.urlparse(api_endpoint)
- if (not (url.scheme == "http") or not url.netloc):
- raise exception.InvalidParameterValue(_(
- "Invalid 'seamicro_api_endpoint' parameter in node's "
- "driver_info."))
-
- res = {'username': username,
- 'password': password,
- 'api_endpoint': api_endpoint,
- 'server_id': server_id,
- 'api_version': api_version,
- 'uuid': node.uuid,
- 'port': port}
-
- return res
-
-
-def _get_server(driver_info):
- """Get server from server_id."""
-
- s_client = _get_client(**driver_info)
- return s_client.servers.get(driver_info['server_id'])
-
-
-def _get_volume(driver_info, volume_id):
- """Get volume from volume_id."""
-
- s_client = _get_client(**driver_info)
- return s_client.volumes.get(volume_id)
-
-
-def _get_power_status(node):
- """Get current power state of this node
-
- :param node: Ironic node one of :class:`ironic.db.models.Node`
- :raises: InvalidParameterValue if a seamicro parameter is invalid.
- :raises: MissingParameterValue if required seamicro parameters are
- missing.
- :raises: ServiceUnavailable on an error from SeaMicro Client.
- :returns: Power state of the given node
- """
-
- seamicro_info = _parse_driver_info(node)
- try:
- server = _get_server(seamicro_info)
- if not hasattr(server, 'active') or server.active is None:
- return states.ERROR
- if not server.active:
- return states.POWER_OFF
- elif server.active:
- return states.POWER_ON
-
- except seamicro_client_exception.NotFound:
- raise exception.NodeNotFound(node=node.uuid)
- except seamicro_client_exception.ClientException as ex:
- LOG.error(_LE("SeaMicro client exception %(msg)s for node %(uuid)s"),
- {'msg': ex.message, 'uuid': node.uuid})
- raise exception.ServiceUnavailable(message=ex.message)
-
-
-def _power_on(node, timeout=None):
- """Power ON this node
-
- :param node: An Ironic node object.
- :param timeout: Time in seconds to wait till power on is complete.
- :raises: InvalidParameterValue if a seamicro parameter is invalid.
- :raises: MissingParameterValue if required seamicro parameters are
- missing.
- :returns: Power state of the given node.
- """
- if timeout is None:
- timeout = CONF.seamicro.action_timeout
- state = [None]
- retries = [0]
- seamicro_info = _parse_driver_info(node)
- server = _get_server(seamicro_info)
-
- def _wait_for_power_on(state, retries):
- """Called at an interval until the node is powered on."""
-
- state[0] = _get_power_status(node)
- if state[0] == states.POWER_ON:
- raise loopingcall.LoopingCallDone()
-
- if retries[0] > CONF.seamicro.max_retry:
- state[0] = states.ERROR
- raise loopingcall.LoopingCallDone()
- try:
- retries[0] += 1
- server.power_on()
- except seamicro_client_exception.ClientException:
- LOG.warning(_LW("Power-on failed for node %s."),
- node.uuid)
-
- timer = loopingcall.FixedIntervalLoopingCall(_wait_for_power_on,
- state, retries)
- timer.start(interval=timeout).wait()
- return state[0]
-
-
-def _power_off(node, timeout=None):
- """Power OFF this node
-
- :param node: Ironic node one of :class:`ironic.db.models.Node`
- :param timeout: Time in seconds to wait till power off is compelete
- :raises: InvalidParameterValue if a seamicro parameter is invalid.
- :raises: MissingParameterValue if required seamicro parameters are
- missing.
- :returns: Power state of the given node
- """
- if timeout is None:
- timeout = CONF.seamicro.action_timeout
- state = [None]
- retries = [0]
- seamicro_info = _parse_driver_info(node)
- server = _get_server(seamicro_info)
-
- def _wait_for_power_off(state, retries):
- """Called at an interval until the node is powered off."""
-
- state[0] = _get_power_status(node)
- if state[0] == states.POWER_OFF:
- raise loopingcall.LoopingCallDone()
-
- if retries[0] > CONF.seamicro.max_retry:
- state[0] = states.ERROR
- raise loopingcall.LoopingCallDone()
- try:
- retries[0] += 1
- server.power_off()
- except seamicro_client_exception.ClientException:
- LOG.warning(_LW("Power-off failed for node %s."),
- node.uuid)
-
- timer = loopingcall.FixedIntervalLoopingCall(_wait_for_power_off,
- state, retries)
- timer.start(interval=timeout).wait()
- return state[0]
-
-
-def _reboot(node, timeout=None):
- """Reboot this node.
-
- :param node: Ironic node one of :class:`ironic.db.models.Node`
- :param timeout: Time in seconds to wait till reboot is compelete
- :raises: InvalidParameterValue if a seamicro parameter is invalid.
- :raises: MissingParameterValue if required seamicro parameters are
- missing.
- :returns: Power state of the given node
- """
- if timeout is None:
- timeout = CONF.seamicro.action_timeout
- state = [None]
- retries = [0]
- seamicro_info = _parse_driver_info(node)
- server = _get_server(seamicro_info)
-
- def _wait_for_reboot(state, retries):
- """Called at an interval until the node is rebooted successfully."""
-
- state[0] = _get_power_status(node)
- if state[0] == states.POWER_ON:
- raise loopingcall.LoopingCallDone()
-
- if retries[0] > CONF.seamicro.max_retry:
- state[0] = states.ERROR
- raise loopingcall.LoopingCallDone()
-
- try:
- retries[0] += 1
- server.reset()
- except seamicro_client_exception.ClientException:
- LOG.warning(_LW("Reboot failed for node %s."),
- node.uuid)
-
- timer = loopingcall.FixedIntervalLoopingCall(_wait_for_reboot,
- state, retries)
- server.reset()
- timer.start(interval=timeout).wait()
- return state[0]
-
-
-def _validate_volume(driver_info, volume_id):
- """Validates if volume is in Storage pools designated for ironic."""
-
- volume = _get_volume(driver_info, volume_id)
-
- # Check if the ironic <scard>/ironic-<pool_id>/<volume_id> naming scheme
- # is present in volume id
- try:
- pool_id = volume.id.split('/')[1].lower()
- except IndexError:
- pool_id = ""
-
- if "ironic-" in pool_id:
- return True
- else:
- raise exception.InvalidParameterValue(_(
- "Invalid volume id specified"))
-
-
-def _get_pools(driver_info, filters=None):
- """Get SeaMicro storage pools matching given filters."""
-
- s_client = _get_client(**driver_info)
- return s_client.pools.list(filters=filters)
-
-
-def _create_volume(driver_info, volume_size):
- """Create volume in the SeaMicro storage pools designated for ironic."""
-
- ironic_pools = _get_pools(driver_info, filters={'id': 'ironic-'})
- if ironic_pools is None:
- raise exception.VendorPassthruException(_(
- "No storage pools found for ironic"))
-
- least_used_pool = sorted(ironic_pools,
- key=lambda x: x.freeSize)[0]
- return _get_client(**driver_info).volumes.create(volume_size,
- least_used_pool)
-
-
-def get_telnet_port(driver_info):
- """Get SeaMicro telnet port to listen."""
- server_id = int(driver_info['server_id'].split("/")[0])
- return PORT_BASE + (10 * server_id)
-
-
-class Power(base.PowerInterface):
- """SeaMicro Power Interface.
-
- This PowerInterface class provides a mechanism for controlling the power
- state of servers in a seamicro chassis.
- """
-
- def get_properties(self):
- return COMMON_PROPERTIES
-
- def validate(self, task):
- """Check that node 'driver_info' is valid.
-
- Check that node 'driver_info' contains the required fields.
-
- :param task: a TaskManager instance containing the node to act on.
- :raises: MissingParameterValue if required seamicro parameters are
- missing.
- """
- _parse_driver_info(task.node)
-
- def get_power_state(self, task):
- """Get the current power state of the task's node.
-
- Poll the host for the current power state of the node.
-
- :param task: a TaskManager instance containing the node to act on.
- :raises: ServiceUnavailable on an error from SeaMicro Client.
- :raises: InvalidParameterValue if a seamicro parameter is invalid.
- :raises: MissingParameterValue when a required parameter is missing
- :returns: power state. One of :class:`ironic.common.states`.
-
- """
- return _get_power_status(task.node)
-
- @task_manager.require_exclusive_lock
- def set_power_state(self, task, pstate):
- """Turn the power on or off.
-
- Set the power state of a node.
-
- :param task: a TaskManager instance containing the node to act on.
- :param pstate: Either POWER_ON or POWER_OFF from :class:
- `ironic.common.states`.
- :raises: InvalidParameterValue if an invalid power state was specified
- or a seamicro parameter is invalid.
- :raises: MissingParameterValue when a required parameter is missing
- :raises: PowerStateFailure if the desired power state couldn't be set.
- """
-
- if pstate == states.POWER_ON:
- state = _power_on(task.node)
- elif pstate == states.POWER_OFF:
- state = _power_off(task.node)
- else:
- raise exception.InvalidParameterValue(_(
- "set_power_state called with invalid power state."))
-
- if state != pstate:
- raise exception.PowerStateFailure(pstate=pstate)
-
- @task_manager.require_exclusive_lock
- def reboot(self, task):
- """Cycles the power to the task's node.
-
- :param task: a TaskManager instance containing the node to act on.
- :raises: InvalidParameterValue if a seamicro parameter is invalid.
- :raises: MissingParameterValue if required seamicro parameters are
- missing.
- :raises: PowerStateFailure if the final state of the node is not
- POWER_ON.
- """
- state = _reboot(task.node)
-
- if state != states.POWER_ON:
- raise exception.PowerStateFailure(pstate=states.POWER_ON)
-
-
-class VendorPassthru(base.VendorInterface):
- """SeaMicro vendor-specific methods."""
-
- def get_properties(self):
- return COMMON_PROPERTIES
-
- def validate(self, task, method, **kwargs):
- _parse_driver_info(task.node)
-
- @base.passthru(['POST'],
- description=_("Set an untagged VLAN ID for NIC 0 of node. "
- "Required argument: 'vlan_id' - ID of "
- "untagged VLAN."))
- def set_node_vlan_id(self, task, **kwargs):
- """Sets an untagged vlan id for NIC 0 of node.
-
- @kwargs vlan_id: id of untagged vlan for NIC 0 of node
- """
- node = task.node
- vlan_id = kwargs.get('vlan_id')
- if not vlan_id:
- raise exception.MissingParameterValue(_("No vlan id provided"))
-
- seamicro_info = _parse_driver_info(node)
- try:
- server = _get_server(seamicro_info)
-
- # remove current vlan for server
- if len(server.nic['0']['untaggedVlan']) > 0:
- server.unset_untagged_vlan(server.nic['0']['untaggedVlan'])
- server = server.refresh(5)
- server.set_untagged_vlan(vlan_id)
- except seamicro_client_exception.ClientException as ex:
- LOG.error(_LE("SeaMicro client exception: %s"), ex.message)
- raise exception.VendorPassthruException(message=ex.message)
-
- properties = node.properties
- properties['seamicro_vlan_id'] = vlan_id
- node.properties = properties
- node.save()
-
- @base.passthru(['POST'],
- description=_("Attach volume to node. Arguments: "
- "1. 'volume_id' - ID of pre-provisioned "
- "volume. This is optional. If not specified, "
- "a volume is created in SeaMicro storage "
- "pool. 2. 'volume_size' - size of new volume "
- "(if volume_id is not specified)."))
- def attach_volume(self, task, **kwargs):
- """Attach a volume to a node.
-
- Attach volume from SeaMicro storage pools for ironic to node.
- If kwargs['volume_id'] not given, Create volume in SeaMicro
- storage pool and attach to node.
-
- @kwargs volume_id: id of pre-provisioned volume that is to be attached
- as root volume of node
- @kwargs volume_size: size of new volume to be created and attached
- as root volume of node
- """
- node = task.node
- seamicro_info = _parse_driver_info(node)
- volume_id = kwargs.get('volume_id')
-
- if volume_id is None:
- volume_size = kwargs.get('volume_size')
- if volume_size is None:
- raise exception.MissingParameterValue(
- _("No volume size provided for creating volume"))
- volume_id = _create_volume(seamicro_info, volume_size)
-
- if _validate_volume(seamicro_info, volume_id):
- try:
- server = _get_server(seamicro_info)
- server.detach_volume()
- server = server.refresh(5)
- server.attach_volume(volume_id)
- except seamicro_client_exception.ClientException as ex:
- LOG.error(_LE("SeaMicro client exception: %s"), ex.message)
- raise exception.VendorPassthruException(message=ex.message)
-
- properties = node.properties
- properties['seamicro_volume_id'] = volume_id
- node.properties = properties
- node.save()
-
-
-class Management(base.ManagementInterface):
-
- def get_properties(self):
- return COMMON_PROPERTIES
-
- def validate(self, task):
- """Check that 'driver_info' contains SeaMicro credentials.
-
- 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 when a required parameter is missing
-
- """
- _parse_driver_info(task.node)
-
- def get_supported_boot_devices(self, task):
- """Get a list of the supported boot devices.
-
- :param task: a task from TaskManager.
- :returns: A list with the supported boot devices defined
- in :mod:`ironic.common.boot_devices`.
-
- """
- return list(_BOOT_DEVICES_MAP.keys())
-
- @task_manager.require_exclusive_lock
- def set_boot_device(self, task, device, persistent=False):
- """Set the boot device for the task's node.
-
- Set the boot device to use on next reboot of the node.
-
- :param task: a task from TaskManager.
- :param device: the boot device, one of
- :mod:`ironic.common.boot_devices`.
- :param persistent: Boolean value. True if the boot device will
- persist to all future boots, False if not.
- Default: False. Ignored by this driver.
- :raises: InvalidParameterValue if an invalid boot device is
- specified or if a seamicro parameter is invalid.
- :raises: IronicException on an error from seamicro-client.
- :raises: MissingParameterValue when a required parameter is missing
-
- """
- if device not in self.get_supported_boot_devices(task):
- raise exception.InvalidParameterValue(_(
- "Invalid boot device %s specified.") % device)
-
- seamicro_info = _parse_driver_info(task.node)
- try:
- server = _get_server(seamicro_info)
- boot_device = _BOOT_DEVICES_MAP[device]
- server.set_boot_order(boot_device)
- except seamicro_client_exception.ClientException as ex:
- LOG.error(_LE("Seamicro set boot device failed for node "
- "%(node)s with the following error: %(error)s"),
- {'node': task.node.uuid, 'error': ex})
- raise exception.IronicException(ex)
-
- def get_boot_device(self, task):
- """Get the current boot device for the task's node.
-
- Returns the current boot device of the node. Be aware that not
- all drivers support this.
-
- :param task: a task from TaskManager.
- :returns: a dictionary containing:
-
- :boot_device: the boot device, one of
- :mod:`ironic.common.boot_devices` or None if it is unknown.
- :persistent: Whether the boot device will persist to all
- future boots or not, None if it is unknown.
-
- """
- # TODO(lucasagomes): The python-seamicroclient library currently
- # doesn't expose a method to get the boot device, update it once
- # it's implemented.
- return {'boot_device': None, 'persistent': None}
-
- def get_sensors_data(self, task):
- """Get sensors data method.
-
- Not implemented by this driver.
- :param task: a TaskManager instance.
-
- """
- raise NotImplementedError()
-
-
-class ShellinaboxConsole(base.ConsoleInterface):
- """A ConsoleInterface that uses telnet and shellinabox."""
-
- def get_properties(self):
- d = COMMON_PROPERTIES.copy()
- d.update(CONSOLE_PROPERTIES)
- return d
-
- def validate(self, task):
- """Validate the Node console info.
-
- :param task: a task from TaskManager.
- :raises: MissingParameterValue if required seamicro parameters are
- missing
- :raises: InvalidParameterValue if required parameter are invalid.
- """
- driver_info = _parse_driver_info(task.node)
- if not driver_info['port']:
- raise exception.MissingParameterValue(_(
- "Missing 'seamicro_terminal_port' parameter in node's "
- "driver_info"))
-
- def start_console(self, task):
- """Start a remote console for the node.
-
- :param task: a task from TaskManager
- :raises: MissingParameterValue if required seamicro parameters are
- missing
- :raises: ConsoleError if the directory for the PID file cannot be
- created
- :raises: ConsoleSubprocessFailed when invoking the subprocess failed
- :raises: InvalidParameterValue if required parameter are invalid.
- """
-
- driver_info = _parse_driver_info(task.node)
- telnet_port = get_telnet_port(driver_info)
- chassis_ip = urlparse.urlparse(driver_info['api_endpoint']).netloc
-
- seamicro_cmd = ("/:%(uid)s:%(gid)s:HOME:telnet %(chassis)s %(port)s"
- % {'uid': os.getuid(),
- 'gid': os.getgid(),
- 'chassis': chassis_ip,
- 'port': telnet_port})
-
- console_utils.start_shellinabox_console(driver_info['uuid'],
- driver_info['port'],
- seamicro_cmd)
-
- def stop_console(self, task):
- """Stop the remote console session for the node.
-
- :param task: a task from TaskManager
- :raises: ConsoleError if unable to stop the console
- """
-
- console_utils.stop_shellinabox_console(task.node.uuid)
-
- def get_console(self, task):
- """Get the type and connection information about the console.
-
- :raises: MissingParameterValue if required seamicro parameters are
- missing
- :raises: InvalidParameterValue if required parameter are invalid.
- """
-
- driver_info = _parse_driver_info(task.node)
- url = console_utils.get_shellinabox_console_url(driver_info['port'])
- return {'type': 'shellinabox', 'url': url}
diff --git a/ironic/drivers/modules/virtualbox.py b/ironic/drivers/modules/virtualbox.py
deleted file mode 100644
index c3eda6a4c..000000000
--- a/ironic/drivers/modules/virtualbox.py
+++ /dev/null
@@ -1,393 +0,0 @@
-# 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.
-
-"""
-VirtualBox Driver Modules
-"""
-
-from oslo_log import log as logging
-from oslo_utils import importutils
-
-from ironic.common import boot_devices
-from ironic.common import exception
-from ironic.common.i18n import _, _LE, _LW
-from ironic.common import states
-from ironic.common import utils
-from ironic.conductor import task_manager
-from ironic.conf import CONF
-from ironic.drivers import base
-
-pyremotevbox = importutils.try_import('pyremotevbox')
-if pyremotevbox:
- from pyremotevbox import exception as virtualbox_exc
- from pyremotevbox import vbox as virtualbox
-
-IRONIC_TO_VIRTUALBOX_DEVICE_MAPPING = {
- boot_devices.PXE: 'Network',
- boot_devices.DISK: 'HardDisk',
- boot_devices.CDROM: 'DVD',
-}
-VIRTUALBOX_TO_IRONIC_DEVICE_MAPPING = {
- v: k for k, v in IRONIC_TO_VIRTUALBOX_DEVICE_MAPPING.items()}
-
-VIRTUALBOX_TO_IRONIC_POWER_MAPPING = {
- 'PoweredOff': states.POWER_OFF,
- 'Running': states.POWER_ON,
- 'Error': states.ERROR
-}
-
-LOG = logging.getLogger(__name__)
-
-REQUIRED_PROPERTIES = {
- 'virtualbox_vmname': _("Name of the VM in VirtualBox. Required."),
- 'virtualbox_host': _("IP address or hostname of the VirtualBox host. "
- "Required.")
-}
-
-OPTIONAL_PROPERTIES = {
- 'virtualbox_username': _("Username for the VirtualBox host. "
- "Default value is ''. Optional."),
- 'virtualbox_password': _("Password for 'virtualbox_username'. "
- "Default value is ''. Optional."),
- 'virtualbox_port': _("Port on which VirtualBox web service is listening. "
- "Optional."),
-}
-
-COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy()
-COMMON_PROPERTIES.update(OPTIONAL_PROPERTIES)
-
-
-def _strip_virtualbox_from_param_name(param_name):
- if param_name.startswith('virtualbox_'):
- return param_name[11:]
- else:
- return param_name
-
-
-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.
- """
- info = node.driver_info
- d_info = {}
-
- missing_params = []
- for param in REQUIRED_PROPERTIES:
- try:
- d_info_param_name = _strip_virtualbox_from_param_name(param)
- d_info[d_info_param_name] = info[param]
- except KeyError:
- missing_params.append(param)
-
- if missing_params:
- msg = (_("The following parameters are missing in driver_info: %s") %
- ', '.join(missing_params))
- raise exception.MissingParameterValue(msg)
-
- for param in OPTIONAL_PROPERTIES:
- if param in info:
- d_info_param_name = _strip_virtualbox_from_param_name(param)
- d_info[d_info_param_name] = info[param]
-
- port = d_info.get('port', CONF.virtualbox.port)
- d_info['port'] = utils.validate_network_port(port, 'virtualbox_port')
-
- return d_info
-
-
-def _run_virtualbox_method(node, ironic_method, vm_object_method,
- *call_args, **call_kwargs):
- """Runs a method of pyremotevbox.vbox.VirtualMachine
-
- This runs a method from pyremotevbox.vbox.VirtualMachine.
- The VirtualMachine method to be invoked and the argument(s) to be
- passed to it are to be provided.
-
- :param node: an Ironic Node object.
- :param ironic_method: the Ironic method which called
- '_run_virtualbox_method'. This is used for logging only.
- :param vm_object_method: The method on the VirtualMachine object
- to be called.
- :param call_args: The args to be passed to 'vm_object_method'.
- :param call_kwargs: The kwargs to be passed to the 'vm_object_method'.
- :returns: The value returned by 'vm_object_method'
- :raises: VirtualBoxOperationFailed, if execution of 'vm_object_method'
- failed.
- :raises: InvalidParameterValue,
- - if 'vm_object_method' is not a valid 'VirtualMachine' method.
- - if some parameter(s) have invalid value(s) in the node's driver_info.
- :raises: MissingParameterValue, if some required parameter(s) are missing
- in the node's driver_info.
- :raises: pyremotevbox.exception.VmInWrongPowerState, if operation cannot
- be performed when vm is in the current power state.
- """
- driver_info = _parse_driver_info(node)
- try:
- host = virtualbox.VirtualBoxHost(**driver_info)
- vm_object = host.find_vm(driver_info['vmname'])
- except virtualbox_exc.PyRemoteVBoxException as exc:
- LOG.error(_LE("Failed while creating a VirtualMachine object for "
- "node %(node_id)s. Error: %(error)s."),
- {'node_id': node.uuid, 'error': exc})
- raise exception.VirtualBoxOperationFailed(operation=vm_object_method,
- error=exc)
-
- try:
- func = getattr(vm_object, vm_object_method)
- except AttributeError:
- error_msg = _("Invalid VirtualMachine method '%s' passed "
- "to '_run_virtualbox_method'.")
- raise exception.InvalidParameterValue(error_msg % vm_object_method)
-
- try:
- return func(*call_args, **call_kwargs)
- except virtualbox_exc.PyRemoteVBoxException as exc:
- error_msg = _LE("'%(ironic_method)s' failed for node %(node_id)s with "
- "error: %(error)s.")
- LOG.error(error_msg, {'ironic_method': ironic_method,
- 'node_id': node.uuid,
- 'error': exc})
- raise exception.VirtualBoxOperationFailed(operation=vm_object_method,
- error=exc)
-
-
-class VirtualBoxPower(base.PowerInterface):
- def get_properties(self):
- return COMMON_PROPERTIES
-
- def validate(self, task):
- """Check if node.driver_info contains the required credentials.
-
- :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.
- """
- _parse_driver_info(task.node)
-
- def _apply_boot_device(self, task):
- """Get the target boot device and apply on the baremetal machine .
-
- :param task: a TaskManager instance.
- """
- driver_internal_info = task.node.driver_internal_info
- device = driver_internal_info.pop('vbox_target_boot_device', None)
- if device is not None:
- task.driver.management.set_boot_device(task, device)
- task.node.driver_internal_info = driver_internal_info
- task.node.save()
-
- 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.
- :raises: VirtualBoxOperationFailed, if error encountered from
- VirtualBox operation.
- """
- power_status = _run_virtualbox_method(task.node, 'get_power_state',
- 'get_power_status')
- try:
- return VIRTUALBOX_TO_IRONIC_POWER_MAPPING[power_status]
- except KeyError:
- msg = _LE("VirtualBox returned unknown state '%(state)s' for "
- "node %(node)s")
- LOG.error(msg, {'state': power_status, 'node': task.node.uuid})
- return states.ERROR
-
- @task_manager.require_exclusive_lock
- def set_power_state(self, task, target_state):
- """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.
- :raises: VirtualBoxOperationFailed, if error encountered from
- VirtualBox operation.
- """
-
- # We set boot device before power on to avoid the case that user
- # shuts down the machine without calling power off method here. For
- # instance, soft power off the machine from OS.
- if target_state == states.POWER_OFF:
- _run_virtualbox_method(task.node, 'set_power_state', 'stop')
- self._apply_boot_device(task)
- elif target_state == states.POWER_ON:
- self._apply_boot_device(task)
- _run_virtualbox_method(task.node, 'set_power_state', 'start')
- elif target_state == states.REBOOT:
- self.reboot(task)
- else:
- msg = _("'set_power_state' called with invalid power "
- "state '%s'") % target_state
- raise exception.InvalidParameterValue(msg)
-
- @task_manager.require_exclusive_lock
- def reboot(self, task):
- """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: VirtualBoxOperationFailed, if error encountered from
- VirtualBox operation.
- """
- _run_virtualbox_method(task.node, 'reboot', 'stop')
- self._apply_boot_device(task)
- _run_virtualbox_method(task.node, 'reboot', 'start')
-
-
-class VirtualBoxManagement(base.ManagementInterface):
- def get_properties(self):
- return COMMON_PROPERTIES
-
- def validate(self, task):
- """Check that 'driver_info' contains required credentials.
-
- 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.
-
- :param task: a task from TaskManager.
- :returns: A list with the supported boot devices defined
- in :mod:`ironic.common.boot_devices`.
- """
- return list(IRONIC_TO_VIRTUALBOX_DEVICE_MAPPING.keys())
-
- def _get_boot_device_from_hardware(self, task):
- boot_dev = _run_virtualbox_method(task.node,
- 'get_boot_device', 'get_boot_device')
- ironic_boot_dev = VIRTUALBOX_TO_IRONIC_DEVICE_MAPPING.get(boot_dev)
- persistent = True
- if not ironic_boot_dev:
- persistent = None
- msg = _LW("VirtualBox returned unknown boot "
- "device '%(device)s' for node %(node)s")
- LOG.warning(msg, {'device': boot_dev, 'node': task.node.uuid})
- return (ironic_boot_dev, persistent)
-
- 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: VirtualBoxOperationFailed, if error encountered from
- VirtualBox operation.
- """
- if task.driver.power.get_power_state(task) == states.POWER_OFF:
- ironic_boot_dev, persistent = \
- self._get_boot_device_from_hardware(task)
- else:
- ironic_boot_dev = task.node. \
- driver_internal_info.get('vbox_target_boot_device')
- if ironic_boot_dev is not None:
- msg = _LW("As ironic node %(node)s is"
- " powered on, we will set to boot"
- " from %(device)s before next boot.")
- LOG.warning(msg, {'node': task.node.uuid,
- 'device': ironic_boot_dev})
- persistent = True
- else:
- # Maybe the vbox_target_boot_device is cleaned
- ironic_boot_dev, persistent = \
- self._get_boot_device_from_hardware(task)
- 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 as VirtualBox support only
- persistent boot devices.
- :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: VirtualBoxOperationFailed, if error encountered from
- VirtualBox operation.
- """
- # NOTE(rameshg87): VirtualBox has only persistent boot devices.
- try:
- boot_dev = IRONIC_TO_VIRTUALBOX_DEVICE_MAPPING[device]
- except KeyError:
- raise exception.InvalidParameterValue(
- _("Invalid boot device %s specified.") % device)
-
- if task.driver.power.get_power_state(task) == states.POWER_OFF:
-
- _run_virtualbox_method(task.node, 'set_boot_device',
- 'set_boot_device', boot_dev)
- else:
- LOG.warning(_LW('Node %(node_uuid)s: As VirtualBox do not support '
- 'setting boot device when VM is powered on, we '
- 'will set booting from %(device)s when reboot '
- 'next time.'),
- {'node_uuid': task.node.uuid, 'device': device})
- # We should store target boot device in case the
- # end user shutoff the baremetal machine from NOVA API.
- boot_device_now = self.get_boot_device(task)['boot_device']
- if device != boot_device_now:
- driver_internal_info = task.node.driver_internal_info
- driver_internal_info['vbox_target_boot_device'] = device
- task.node.driver_internal_info = driver_internal_info
- task.node.save()
-
- 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()
diff --git a/ironic/drivers/pxe.py b/ironic/drivers/pxe.py
index 8f890f974..8f93170c0 100644
--- a/ironic/drivers/pxe.py
+++ b/ironic/drivers/pxe.py
@@ -39,15 +39,11 @@ from ironic.drivers.modules.irmc import inspect as irmc_inspect
from ironic.drivers.modules.irmc import management as irmc_management
from ironic.drivers.modules.irmc import power as irmc_power
from ironic.drivers.modules import iscsi_deploy
-from ironic.drivers.modules.msftocs import management as msftocs_management
-from ironic.drivers.modules.msftocs import power as msftocs_power
from ironic.drivers.modules import pxe
-from ironic.drivers.modules import seamicro
from ironic.drivers.modules import snmp
from ironic.drivers.modules import ssh
from ironic.drivers.modules.ucs import management as ucs_mgmt
from ironic.drivers.modules.ucs import power as ucs_power
-from ironic.drivers.modules import virtualbox
# For backward compatibility
@@ -110,32 +106,6 @@ class PXEAndIPMINativeDriver(base.BaseDriver):
self.raid = agent.AgentRAID()
-class PXEAndSeaMicroDriver(base.BaseDriver):
- """PXE + SeaMicro driver.
-
- This driver implements the `core` functionality, combining
- :class:`ironic.drivers.modules.seamicro.Power` for power
- on/off and reboot with
- :class:`ironic.drivers.modules.iscsi_deploy.ISCSIDeploy`
- for image deployment. Implementations are in those respective
- classes; this class is merely the glue between them.
- """
-
- supported = False
-
- def __init__(self):
- if not importutils.try_import('seamicroclient'):
- raise exception.DriverLoadError(
- driver=self.__class__.__name__,
- reason=_("Unable to import seamicroclient library"))
- self.power = seamicro.Power()
- self.boot = pxe.PXEBoot()
- self.deploy = iscsi_deploy.ISCSIDeploy()
- self.management = seamicro.Management()
- self.vendor = seamicro.VendorPassthru()
- self.console = seamicro.ShellinaboxConsole()
-
-
class PXEAndIloDriver(base.BaseDriver):
"""PXE + Ilo Driver using IloClient interface.
@@ -206,52 +176,6 @@ class PXEAndIRMCDriver(base.BaseDriver):
self.inspect = irmc_inspect.IRMCInspect()
-class PXEAndVirtualBoxDriver(base.BaseDriver):
- """PXE + VirtualBox driver.
-
- NOTE: This driver is meant only for testing environments.
-
- This driver implements the `core` functionality, combining
- :class:`ironic.drivers.virtualbox.VirtualBoxPower` for power on/off and
- reboot of VirtualBox virtual machines, with
- :class:`ironic.drivers.modules.iscsi_deploy.ISCSIDeploy` for image
- deployment. Implementations are in those respective classes;
- this class is merely the glue between them.
- """
-
- supported = False
-
- def __init__(self):
- if not importutils.try_import('pyremotevbox'):
- raise exception.DriverLoadError(
- driver=self.__class__.__name__,
- reason=_("Unable to import pyremotevbox library"))
- self.power = virtualbox.VirtualBoxPower()
- self.boot = pxe.PXEBoot()
- self.deploy = iscsi_deploy.ISCSIDeploy()
- self.management = virtualbox.VirtualBoxManagement()
- self.raid = agent.AgentRAID()
-
-
-class PXEAndMSFTOCSDriver(base.BaseDriver):
- """PXE + MSFT OCS driver.
-
- This driver implements the `core` functionality, combining
- :class:`ironic.drivers.modules.msftocs.power.MSFTOCSPower` for power on/off
- and reboot with :class:`ironic.drivers.modules.iscsi_deploy.ISCSIDeploy`
- for image deployment. Implementations are in those respective classes;
- this class is merely the glue between them.
- """
-
- supported = False
-
- def __init__(self):
- self.power = msftocs_power.MSFTOCSPower()
- self.boot = pxe.PXEBoot()
- self.deploy = iscsi_deploy.ISCSIDeploy()
- self.management = msftocs_management.MSFTOCSManagement()
-
-
class PXEAndUcsDriver(base.BaseDriver):
"""PXE + Cisco UCSM driver.