diff --git a/devstack/enabled-drivers.txt b/devstack/enabled-drivers.txt deleted file mode 100644 index a86824e..0000000 --- a/devstack/enabled-drivers.txt +++ /dev/null @@ -1,13 +0,0 @@ -fake_wol_fake -pxe_wol_iscsi -pxe_wol_agent -agent_ipmitool_nm -fake_nm -pxe_libvirt_agent -pxe_libvirt_iscsi -fake_libvirt_fake -fake_amt_fake -pxe_amt_iscsi -pxe_amt_agent -pxe_libvirt_ansible -pxe_ipmitool_ansible diff --git a/devstack/plugin.sh b/devstack/plugin.sh index e2451f9..83870b4 100755 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -4,26 +4,74 @@ IRONIC_STAGING_DRIVERS_DIR=$DEST/ironic-staging-drivers IRONIC_DRIVERS_EXCLUDED_DIRS='tests common' IRONIC_STAGING_DRIVER=${IRONIC_STAGING_DRIVER:-} +# NOTE(pas-ha) skip iboot drivers by default as they require package not available on PyPI +IRONIC_STAGING_DRIVERS_SKIPS=${IRONIC_STAGING_DRIVERS_SKIPS:-"iboot"} +IRONIC_STAGING_DRIVERS_FILTERS=${IRONIC_STAGING_DRIVERS_FILTERS:-} +IRONIC_STAGING_LIST_EP_CMD="$PYTHON $IRONIC_STAGING_DRIVERS_DIR/tools/list-package-entrypoints.py ironic-staging-drivers" +if [[ -n "$IRONIC_STAGING_DRIVERS_SKIPS" ]]; then + IRONIC_STAGING_LIST_EP_CMD+=" -s $IRONIC_STAGING_DRIVERS_SKIPS" +fi +if [[ -n "$IRONIC_STAGING_DRIVERS_FILTERS" ]]; then + IRONIC_STAGING_LIST_EP_CMD+=" -f $IRONIC_STAGING_DRIVERS_FILTERS" +fi + +function setup_ironic_enabled_interfaces_for { + + local iface=$1 + local iface_var + local ironic_iface_var + local staging_ifs + iface_var=$(echo $iface | tr '[:lower:]' '[:upper:]') + ironic_iface_var="IRONIC_ENABLED_${iface_var}_INTERFACES" + staging_ifs=$($IRONIC_STAGING_LIST_EP_CMD -t ironic.hardware.interfaces.${iface}) + + # NOTE(pas-ha) need fake management interface enabled for staging-wol hw type, + # and even if WoL is disabled by skips or filters, no harm in enabling it any way + if [[ $iface == 'management' ]]; then + if [[ -n ${staging_ifs} ]]; then + staging_ifs+=",fake" + else + staging_ifs='fake' + fi + fi + + if [[ -n ${staging_ifs} ]]; then + iniset $IRONIC_CONF_FILE DEFAULT "enabled_${iface}_interfaces" "${!ironic_iface_var},$staging_ifs" + fi +} function update_ironic_enabled_drivers { - local saveIFS - saveIFS=$IFS - IFS="," - while read driver; do - if [[ ! $IRONIC_ENABLED_DRIVERS =~ $(echo "\<$driver\>") ]]; then - if [[ -z "$IRONIC_ENABLED_DRIVERS" ]]; then - IRONIC_ENABLED_DRIVERS="$driver" - else - IRONIC_ENABLED_DRIVERS+=",$driver" - fi - fi - done < $IRONIC_STAGING_DRIVERS_DIR/devstack/enabled-drivers.txt - IFS=$saveIFS + # NOTE(pas-ha) not carying about possible duplicates any more, + # as it was fixed in ironic already # NOTE(vsaienko) if ironic-staging-drivers are called after ironic - # setting IRONIC_ENABLED_DRIVERS will not take affect. Update ironic - # configuration explicitly. + # setting IRONIC_ENABLED_* will not take affect. Update ironic + # configuration explicitly for each option. + local staging_drivers + local staging_hw_types + + staging_drivers=$($IRONIC_STAGING_LIST_EP_CMD -t ironic.drivers) + if [[ -z "$IRONIC_ENABLED_DRIVERS" ]]; then + IRONIC_ENABLED_DRIVERS="$staging_drivers" + else + IRONIC_ENABLED_DRIVERS+=",$staging_drivers" + fi iniset $IRONIC_CONF_FILE DEFAULT enabled_drivers "$IRONIC_ENABLED_DRIVERS" + # hardware types + staging_hw_types=$($IRONIC_STAGING_LIST_EP_CMD -t ironic.hardware.types) + if [[ -z "$IRONIC_ENABLED_HARDWARE_TYPES" ]]; then + IRONIC_ENABLED_HARDWARE_TYPES="$staging_hw_types" + else + IRONIC_ENABLED_HARDWARE_TYPES+=",$staging_hw_types" + fi + iniset $IRONIC_CONF_FILE DEFAULT enabled_hardware_types "$IRONIC_ENABLED_HARDWARE_TYPES" + + # NOTE(pas-ha) find and enable any type of ironic hardware interface + # registered by ironic-staging-drivers package (minding skips and filters) + for i in $IRONIC_DRIVER_INTERFACE_TYPES; do + setup_ironic_enabled_interfaces_for $i + done + # set logging for ansible-deploy # NOTE(pas-ha) w/o systemd or syslog, there will be no output of single # ansible tasks to ironic log, only in the stdout returned by processutils diff --git a/ironic_staging_drivers/amt/drivers.py b/ironic_staging_drivers/amt/drivers.py index d14d6a2..57e3202 100644 --- a/ironic_staging_drivers/amt/drivers.py +++ b/ironic_staging_drivers/amt/drivers.py @@ -15,6 +15,7 @@ from ironic.common import exception as ironic_exception from ironic.drivers import base +from ironic.drivers import generic from ironic.drivers.modules import agent from ironic.drivers.modules import fake from ironic.drivers.modules import pxe @@ -79,3 +80,25 @@ class PXEAndAMTAgentDriver(base.BaseDriver): self.boot = pxe.PXEBoot() self.deploy = agent.AgentDeploy() self.management = amt_management.AMTManagement() + + +class AMTHardware(generic.GenericHardware): + """AMT hardware type. + + Hardware type for Intel AMT. + """ + + @property + def supported_deploy_interfaces(self): + """List of supported deploy interfaces.""" + return [amt_deploy.AMTISCSIDeploy, agent.AgentDeploy] + + @property + def supported_management_interfaces(self): + """List of supported management interfaces.""" + return [amt_management.AMTManagement] + + @property + def supported_power_interfaces(self): + """List of supported power interfaces.""" + return [amt_power.AMTPower] diff --git a/ironic_staging_drivers/ansible/__init__.py b/ironic_staging_drivers/ansible/__init__.py index 2455ab9..6284869 100644 --- a/ironic_staging_drivers/ansible/__init__.py +++ b/ironic_staging_drivers/ansible/__init__.py @@ -11,6 +11,7 @@ # limitations under the License. from ironic.drivers import base +from ironic.drivers import ipmi from ironic.drivers.modules import fake from ironic.drivers.modules import ipmitool from ironic.drivers.modules import pxe @@ -51,3 +52,14 @@ class AnsibleAndLibvirtDriver(base.BaseDriver): self.boot = pxe.PXEBoot() self.deploy = ansible_deploy.AnsibleDeploy() self.management = libvirt_power.LibvirtManagement() + + +# NOTE(yuriyz): This class is not a "real" hardware. +# Added to support the ansible deploy interface in 'ipmi' hardware +class AnsibleDeployIPMI(ipmi.IPMIHardware): + + @property + def supported_deploy_interfaces(self): + """List of supported deploy interfaces.""" + return (super(AnsibleDeployIPMI, self).supported_deploy_interfaces + + [ansible_deploy.AnsibleDeploy]) diff --git a/ironic_staging_drivers/iboot/__init__.py b/ironic_staging_drivers/iboot/__init__.py index bbc6563..1d9641d 100644 --- a/ironic_staging_drivers/iboot/__init__.py +++ b/ironic_staging_drivers/iboot/__init__.py @@ -17,6 +17,7 @@ from ironic.common import exception as ironic_exception from ironic.common.i18n import _ from ironic.drivers import base +from ironic.drivers import generic from ironic.drivers.modules import agent from ironic.drivers.modules import fake from ironic.drivers.modules import iscsi_deploy @@ -77,3 +78,20 @@ class PXEIBootAgentDriver(base.BaseDriver): self.power = iboot_power.IBootPower() self.boot = pxe.PXEBoot() self.deploy = agent.AgentDeploy() + + +class IBootHardware(generic.GenericHardware): + """IBoot hardware type. + + Uses IBoot for power management. + """ + + @property + def supported_management_interfaces(self): + """List of supported management interfaces.""" + return [fake.FakeManagement] + + @property + def supported_power_interfaces(self): + """List of supported power interfaces.""" + return [iboot_power.IBootPower] diff --git a/ironic_staging_drivers/intel_nm/__init__.py b/ironic_staging_drivers/intel_nm/__init__.py index 12d56cf..8259f37 100644 --- a/ironic_staging_drivers/intel_nm/__init__.py +++ b/ironic_staging_drivers/intel_nm/__init__.py @@ -11,6 +11,7 @@ # under the License. from ironic.drivers import base +from ironic.drivers import ipmi from ironic.drivers.modules import agent from ironic.drivers.modules import fake from ironic.drivers.modules import inspector @@ -57,3 +58,16 @@ class AgentAndIPMIToolIntelNMDriver(base.BaseDriver): self.raid = agent.AgentRAID() self.inspect = inspector.Inspector.create_if_enabled( 'AgentAndIPMIToolDriver') + + +class IntelNMHardware(ipmi.IPMIHardware): + """Intel NM hardware type. + + Hardware type with Intel Node Manager vendor methods. + """ + + @property + def supported_vendor_interfaces(self): + """List of supported vendor interfaces.""" + return (super(IntelNMHardware, self).supported_vendor_interfaces + + [nm_vendor.IntelNMVendorPassthru]) diff --git a/ironic_staging_drivers/libvirt/__init__.py b/ironic_staging_drivers/libvirt/__init__.py index 509eafd..5526231 100644 --- a/ironic_staging_drivers/libvirt/__init__.py +++ b/ironic_staging_drivers/libvirt/__init__.py @@ -11,11 +11,13 @@ # under the License. from ironic.drivers import base +from ironic.drivers import generic from ironic.drivers.modules import agent from ironic.drivers.modules import fake from ironic.drivers.modules import iscsi_deploy from ironic.drivers.modules import pxe +from ironic_staging_drivers.ansible import deploy as ansible_deploy from ironic_staging_drivers.libvirt import power @@ -65,3 +67,27 @@ class PXELibvirtISCSIDriver(base.BaseDriver): self.boot = pxe.PXEBoot() self.deploy = iscsi_deploy.ISCSIDeploy() self.management = power.LibvirtManagement() + + +class LibvirtHardware(generic.GenericHardware): + """Libvirt hardware type. + + Uses Libvirt for power and management. + Also support ansible-deploy. + """ + + @property + def supported_deploy_interfaces(self): + """List of supported deploy interfaces.""" + return (super(LibvirtHardware, self).supported_deploy_interfaces + + [ansible_deploy.AnsibleDeploy]) + + @property + def supported_management_interfaces(self): + """List of supported management interfaces.""" + return [power.LibvirtManagement] + + @property + def supported_power_interfaces(self): + """List of supported power interfaces.""" + return [power.LibvirtPower] diff --git a/ironic_staging_drivers/wol/__init__.py b/ironic_staging_drivers/wol/__init__.py index a21c4df..111d67b 100644 --- a/ironic_staging_drivers/wol/__init__.py +++ b/ironic_staging_drivers/wol/__init__.py @@ -14,6 +14,7 @@ # under the License. from ironic.drivers import base +from ironic.drivers import generic from ironic.drivers.modules import agent from ironic.drivers.modules import fake from ironic.drivers.modules import iscsi_deploy @@ -63,3 +64,20 @@ class PXEWakeOnLanAgentDriver(base.BaseDriver): self.boot = pxe.PXEBoot() self.power = wol_power.WakeOnLanPower() self.deploy = agent.AgentDeploy() + + +class WOLHardware(generic.GenericHardware): + """WOL hardware type. + + Uses wake on lan for power on. + """ + + @property + def supported_management_interfaces(self): + """List of supported management interfaces.""" + return [fake.FakeManagement] + + @property + def supported_power_interfaces(self): + """List of supported power interfaces.""" + return [wol_power.WakeOnLanPower] diff --git a/releasenotes/notes/hardware-types-e8e384faae3d50c3.yaml b/releasenotes/notes/hardware-types-e8e384faae3d50c3.yaml new file mode 100644 index 0000000..32564ef --- /dev/null +++ b/releasenotes/notes/hardware-types-e8e384faae3d50c3.yaml @@ -0,0 +1,45 @@ +--- +features: + - | + Adds 'staging-amt' hardware type for AMT hardware. + Supported driver interfaces different from Generic Hardware are: + + - power: staging-amt + - management: staging-amt + - deploy: direct, staging-amt + + - | + Adds 'staging-wol' hardware type for Wake-on-Lan hardware. + Supported driver interfaces different from Generic Hardware are: + + - power: staging-wol + - management: fake + + - | + Adds 'staging-iboot' hardware type for iBoot hardware. + Supported driver interfaces different from Generic Hardware are: + + - power: staging-iboot + - management: fake + + - | + Adds 'staging-libvirt' hardware type for libvirt-managed virtual hardware. + Supported driver interfaces different from Generic Hardware are: + + - power: staging-libvirt + - management: staging-libvirt + - deploy: direct, iscsi, staging-ansible + + - | + Adds 'staging-nm' hardware type for Intel NodeManager hardware. + Supported driver interfaces different from ``ipmi`` hardware type are: + + - vendor: ipmitool, no-vendor, staging-nm + + - | + Adds 'staging-ansible-ipmi' hardware type for IPMI hardware. + This is not a real hardware type, but it is needed to enable + ansible-deploy interface for standard ``ipmi`` hardware type. + Supported driver interfaces different from ``ipmi`` hardware are: + + - deploy: direct, iscsi, staging-ansible diff --git a/setup.cfg b/setup.cfg index cc2e14a..b806ccb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -42,6 +42,31 @@ ironic.drivers = pxe_ipmitool_ansible = ironic_staging_drivers.ansible:AnsibleAndIPMIToolDriver pxe_libvirt_ansible = ironic_staging_drivers.ansible:AnsibleAndLibvirtDriver +ironic.hardware.interfaces.deploy = + staging-ansible = ironic_staging_drivers.ansible.deploy:AnsibleDeploy + staging-amt = ironic_staging_drivers.amt.deploy:AMTISCSIDeploy + +ironic.hardware.interfaces.management = + staging-amt = ironic_staging_drivers.amt.management:AMTManagement + staging-libvirt = ironic_staging_drivers.libvirt.power:LibvirtManagement + +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-wol = ironic_staging_drivers.wol.power:WakeOnLanPower + +ironic.hardware.interfaces.vendor = + staging-nm = ironic_staging_drivers.intel_nm.nm_vendor:IntelNMVendorPassthru + +ironic.hardware.types = + staging-amt = ironic_staging_drivers.amt.drivers:AMTHardware + staging-ansible-ipmi = ironic_staging_drivers.ansible:AnsibleDeployIPMI + staging-iboot = ironic_staging_drivers.iboot:IBootHardware + staging-nm = ironic_staging_drivers.intel_nm:IntelNMHardware + staging-libvirt = ironic_staging_drivers.libvirt:LibvirtHardware + staging-wol = ironic_staging_drivers.wol:WOLHardware + [build_sphinx] source-dir = doc/source build-dir = doc/build diff --git a/tools/list-package-entrypoints.py b/tools/list-package-entrypoints.py new file mode 100644 index 0000000..ed66f30 --- /dev/null +++ b/tools/list-package-entrypoints.py @@ -0,0 +1,83 @@ +# 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. + +"""List entrypoint names registered by package, possibly per type""" + +from __future__ import print_function + +import argparse +import sys + +import pkg_resources + + +def filter_ep_names(eps, ep_type, skips=None, filters=None): + if not skips: + skips = [] + if not filters: + filters = [] + + def filter_func(name): + return (all([s not in name for s in skips]) and + all([f in name for f in filters])) + + return filter(filter_func, list(eps.get(ep_type, {}).keys())) + + +def list_package_entrypoints(package_name, ep_types=None, skips=None, + filters=None): + eps = pkg_resources.get_entry_map( + pkg_resources.get_distribution(package_name)) + + if not ep_types: + ep_types = eps.keys() + if not skips: + skips = [] + if not filters: + filters = [] + + if len(ep_types) == 1: + names = filter_ep_names(eps, ep_types[0], skips=skips, + filters=filters) + if names: + print(','.join(names)) + else: + for ep_t in ep_types: + print("%s=%s" % (ep_t, + ','.join(filter_ep_names(eps, ep_t, + skips=skips, + filters=filters)))) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('package', metavar='PACKAGE_NAME', type=str, + help='Name of Python package') + parser.add_argument('-t', '--entrypoint-types', dest='ep_types', nargs='+', + metavar="ENTRYPOINT_TYPE", + help='type of entrypoints to find, all if not set') + parser.add_argument('-s', '--skip-names', dest='ep_skips', nargs='+', + metavar='SKIP_ENTRYPOINT', + help='do not output entrypoint names containing any ' + 'of these substrings, ignored if not set') + parser.add_argument('-f', '--filter-names', dest='ep_filters', nargs='+', + metavar='FILTER_ENTRYPOINT', + help='only output entrypoint names containing all ' + 'these substrings, ignored if not set') + args = parser.parse_args() + + sys.exit(list_package_entrypoints(args.package, + ep_types=args.ep_types, + skips=args.ep_skips, + filters=args.ep_filters))