Merge "Remove support for the old bash ramdisk"
This commit is contained in:
commit
6a1083d7a1
@ -86,9 +86,6 @@ components. There is a plugin for installing **ironic-inspector** on DevStack.
|
|||||||
Example local.conf
|
Example local.conf
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
Using IPA
|
|
||||||
~~~~~~~~~
|
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
[[local|localrc]]
|
[[local|localrc]]
|
||||||
@ -108,7 +105,6 @@ Using IPA
|
|||||||
|
|
||||||
IRONIC_DEPLOY_DRIVER_ISCSI_WITH_IPA=True
|
IRONIC_DEPLOY_DRIVER_ISCSI_WITH_IPA=True
|
||||||
IRONIC_BUILD_DEPLOY_RAMDISK=False
|
IRONIC_BUILD_DEPLOY_RAMDISK=False
|
||||||
IRONIC_INSPECTOR_RAMDISK_ELEMENT=ironic-agent
|
|
||||||
IRONIC_INSPECTOR_BUILD_RAMDISK=False
|
IRONIC_INSPECTOR_BUILD_RAMDISK=False
|
||||||
|
|
||||||
VIRT_DRIVER=ironic
|
VIRT_DRIVER=ironic
|
||||||
@ -136,52 +132,6 @@ Notes
|
|||||||
* This configuration disables Heat and Cinder, adjust it if you need these
|
* This configuration disables Heat and Cinder, adjust it if you need these
|
||||||
services.
|
services.
|
||||||
|
|
||||||
Using simple ramdisk
|
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
This ramdisk is deprecated and should not be used.
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
[[local|localrc]]
|
|
||||||
enable_service ironic ir-api ir-cond
|
|
||||||
disable_service n-net n-novnc
|
|
||||||
enable_service neutron q-svc q-agt q-dhcp q-l3 q-meta
|
|
||||||
enable_service s-proxy s-object s-container s-account
|
|
||||||
disable_service heat h-api h-api-cfn h-api-cw h-eng
|
|
||||||
disable_service cinder c-sch c-api c-vol
|
|
||||||
|
|
||||||
enable_plugin ironic https://github.com/openstack/ironic
|
|
||||||
enable_plugin ironic-inspector https://github.com/openstack/ironic-inspector
|
|
||||||
|
|
||||||
IRONIC_BAREMETAL_BASIC_OPS=True
|
|
||||||
IRONIC_VM_COUNT=2
|
|
||||||
IRONIC_VM_SPECS_RAM=1024
|
|
||||||
IRONIC_DEPLOY_FLAVOR="fedora deploy-ironic"
|
|
||||||
|
|
||||||
IRONIC_INSPECTOR_RAMDISK_FLAVOR="fedora ironic-discoverd-ramdisk"
|
|
||||||
|
|
||||||
VIRT_DRIVER=ironic
|
|
||||||
|
|
||||||
LOGDAYS=1
|
|
||||||
LOGFILE=~/logs/stack.sh.log
|
|
||||||
SCREEN_LOGDIR=~/logs/screen
|
|
||||||
|
|
||||||
DEFAULT_INSTANCE_TYPE=baremetal
|
|
||||||
TEMPEST_ALLOW_TENANT_ISOLATION=False
|
|
||||||
|
|
||||||
Notes
|
|
||||||
-----
|
|
||||||
|
|
||||||
* Replace "fedora" with whatever you have
|
|
||||||
|
|
||||||
* You need at least 1G of RAM for VMs, default value of 512 MB won't work
|
|
||||||
|
|
||||||
* Before restarting stack.sh::
|
|
||||||
|
|
||||||
rm -rf /opt/stack/ironic-inspector
|
|
||||||
|
|
||||||
Test
|
Test
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -18,8 +18,6 @@ IRONIC_INSPECTOR_URI="http://$IRONIC_INSPECTOR_HOST:$IRONIC_INSPECTOR_PORT"
|
|||||||
IRONIC_INSPECTOR_BUILD_RAMDISK=$(trueorfalse False IRONIC_INSPECTOR_BUILD_RAMDISK)
|
IRONIC_INSPECTOR_BUILD_RAMDISK=$(trueorfalse False IRONIC_INSPECTOR_BUILD_RAMDISK)
|
||||||
IRONIC_AGENT_KERNEL_URL=${IRONIC_AGENT_KERNEL_URL:-http://tarballs.openstack.org/ironic-python-agent/coreos/files/coreos_production_pxe.vmlinuz}
|
IRONIC_AGENT_KERNEL_URL=${IRONIC_AGENT_KERNEL_URL:-http://tarballs.openstack.org/ironic-python-agent/coreos/files/coreos_production_pxe.vmlinuz}
|
||||||
IRONIC_AGENT_RAMDISK_URL=${IRONIC_AGENT_RAMDISK_URL:-http://tarballs.openstack.org/ironic-python-agent/coreos/files/coreos_production_pxe_image-oem.cpio.gz}
|
IRONIC_AGENT_RAMDISK_URL=${IRONIC_AGENT_RAMDISK_URL:-http://tarballs.openstack.org/ironic-python-agent/coreos/files/coreos_production_pxe_image-oem.cpio.gz}
|
||||||
IRONIC_INSPECTOR_RAMDISK_ELEMENT=${IRONIC_INSPECTOR_RAMDISK_ELEMENT:-ironic-discoverd-ramdisk}
|
|
||||||
IRONIC_INSPECTOR_RAMDISK_FLAVOR=${IRONIC_INSPECTOR_RAMDISK_FLAVOR:-fedora $IRONIC_INSPECTOR_RAMDISK_ELEMENT}
|
|
||||||
IRONIC_INSPECTOR_COLLECTORS=${IRONIC_INSPECTOR_COLLECTORS:-default,logs}
|
IRONIC_INSPECTOR_COLLECTORS=${IRONIC_INSPECTOR_COLLECTORS:-default,logs}
|
||||||
IRONIC_INSPECTOR_RAMDISK_LOGDIR=${IRONIC_INSPECTOR_RAMDISK_LOGDIR:-$IRONIC_INSPECTOR_DATA_DIR/ramdisk-logs}
|
IRONIC_INSPECTOR_RAMDISK_LOGDIR=${IRONIC_INSPECTOR_RAMDISK_LOGDIR:-$IRONIC_INSPECTOR_DATA_DIR/ramdisk-logs}
|
||||||
IRONIC_INSPECTOR_ALWAYS_STORE_RAMDISK_LOGS=${IRONIC_INSPECTOR_ALWAYS_STORE_RAMDISK_LOGS:-True}
|
IRONIC_INSPECTOR_ALWAYS_STORE_RAMDISK_LOGS=${IRONIC_INSPECTOR_ALWAYS_STORE_RAMDISK_LOGS:-True}
|
||||||
@ -91,11 +89,6 @@ function stop_inspector_dhcp {
|
|||||||
screen -S $SCREEN_NAME -p ironic-inspector-dhcp -X kill
|
screen -S $SCREEN_NAME -p ironic-inspector-dhcp -X kill
|
||||||
}
|
}
|
||||||
|
|
||||||
function inspector_uses_ipa {
|
|
||||||
[[ $IRONIC_INSPECTOR_RAMDISK_ELEMENT = "ironic-agent" ]] || [[ $IRONIC_INSPECTOR_RAMDISK_FLAVOR =~ (ironic-agent$|^ironic-agent) ]] && return 0
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
function prepare_tftp {
|
function prepare_tftp {
|
||||||
@ -104,35 +97,24 @@ function prepare_tftp {
|
|||||||
IRONIC_INSPECTOR_INITRAMFS_PATH="$IRONIC_INSPECTOR_IMAGE_PATH.initramfs"
|
IRONIC_INSPECTOR_INITRAMFS_PATH="$IRONIC_INSPECTOR_IMAGE_PATH.initramfs"
|
||||||
IRONIC_INSPECTOR_CALLBACK_URI="$IRONIC_INSPECTOR_INTERNAL_URI/v1/continue"
|
IRONIC_INSPECTOR_CALLBACK_URI="$IRONIC_INSPECTOR_INTERNAL_URI/v1/continue"
|
||||||
|
|
||||||
if inspector_uses_ipa; then
|
IRONIC_INSPECTOR_KERNEL_CMDLINE="ipa-inspection-callback-url=$IRONIC_INSPECTOR_CALLBACK_URI systemd.journald.forward_to_console=yes"
|
||||||
IRONIC_INSPECTOR_KERNEL_CMDLINE="ipa-inspection-callback-url=$IRONIC_INSPECTOR_CALLBACK_URI systemd.journald.forward_to_console=yes"
|
IRONIC_INSPECTOR_KERNEL_CMDLINE="$IRONIC_INSPECTOR_KERNEL_CMDLINE vga=normal console=tty0 console=ttyS0"
|
||||||
IRONIC_INSPECTOR_KERNEL_CMDLINE="$IRONIC_INSPECTOR_KERNEL_CMDLINE vga=normal console=tty0 console=ttyS0"
|
IRONIC_INSPECTOR_KERNEL_CMDLINE="$IRONIC_INSPECTOR_KERNEL_CMDLINE ipa-inspection-collectors=$IRONIC_INSPECTOR_COLLECTORS"
|
||||||
IRONIC_INSPECTOR_KERNEL_CMDLINE="$IRONIC_INSPECTOR_KERNEL_CMDLINE ipa-inspection-collectors=$IRONIC_INSPECTOR_COLLECTORS"
|
IRONIC_INSPECTOR_KERNEL_CMDLINE="$IRONIC_INSPECTOR_KERNEL_CMDLINE ipa-debug=1"
|
||||||
IRONIC_INSPECTOR_KERNEL_CMDLINE="$IRONIC_INSPECTOR_KERNEL_CMDLINE ipa-debug=1"
|
if [[ "$IRONIC_INSPECTOR_BUILD_RAMDISK" == "True" ]]; then
|
||||||
if [[ "$IRONIC_INSPECTOR_BUILD_RAMDISK" == "True" ]]; then
|
if [ ! -e "$IRONIC_INSPECTOR_KERNEL_PATH" -o ! -e "$IRONIC_INSPECTOR_INITRAMFS_PATH" ]; then
|
||||||
if [ ! -e "$IRONIC_INSPECTOR_KERNEL_PATH" -o ! -e "$IRONIC_INSPECTOR_INITRAMFS_PATH" ]; then
|
build_ipa_coreos_ramdisk "$IRONIC_INSPECTOR_KERNEL_PATH" "$IRONIC_INSPECTOR_INITRAMFS_PATH"
|
||||||
build_ipa_coreos_ramdisk "$IRONIC_INSPECTOR_KERNEL_PATH" "$IRONIC_INSPECTOR_INITRAMFS_PATH"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# download the agent image tarball
|
|
||||||
if [ ! -e "$IRONIC_INSPECTOR_KERNEL_PATH" -o ! -e "$IRONIC_INSPECTOR_INITRAMFS_PATH" ]; then
|
|
||||||
if [ -e "$IRONIC_DEPLOY_KERNEL_PATH" -a -e "$IRONIC_DEPLOY_RAMDISK_PATH" ]; then
|
|
||||||
cp $IRONIC_DEPLOY_KERNEL_PATH $IRONIC_INSPECTOR_KERNEL_PATH
|
|
||||||
cp $IRONIC_DEPLOY_RAMDISK_PATH $IRONIC_INSPECTOR_INITRAMFS_PATH
|
|
||||||
else
|
|
||||||
wget "$IRONIC_AGENT_KERNEL_URL" -O $IRONIC_INSPECTOR_KERNEL_PATH
|
|
||||||
wget "$IRONIC_AGENT_RAMDISK_URL" -O $IRONIC_INSPECTOR_INITRAMFS_PATH
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
IRONIC_INSPECTOR_KERNEL_CMDLINE="discoverd_callback_url=$IRONIC_INSPECTOR_CALLBACK_URI inspector_callback_url=$IRONIC_INSPECTOR_CALLBACK_URI"
|
# download the agent image tarball
|
||||||
if [ ! -e "$IRONIC_INSPECTOR_KERNEL_PATH" -o ! -e "$IRONIC_INSPECTOR_INITRAMFS_PATH" ]; then
|
if [ ! -e "$IRONIC_INSPECTOR_KERNEL_PATH" -o ! -e "$IRONIC_INSPECTOR_INITRAMFS_PATH" ]; then
|
||||||
if [[ $(type -P ramdisk-image-create) == "" ]]; then
|
if [ -e "$IRONIC_DEPLOY_KERNEL_PATH" -a -e "$IRONIC_DEPLOY_RAMDISK_PATH" ]; then
|
||||||
pip_install diskimage_builder
|
cp $IRONIC_DEPLOY_KERNEL_PATH $IRONIC_INSPECTOR_KERNEL_PATH
|
||||||
|
cp $IRONIC_DEPLOY_RAMDISK_PATH $IRONIC_INSPECTOR_INITRAMFS_PATH
|
||||||
|
else
|
||||||
|
wget "$IRONIC_AGENT_KERNEL_URL" -O $IRONIC_INSPECTOR_KERNEL_PATH
|
||||||
|
wget "$IRONIC_AGENT_RAMDISK_URL" -O $IRONIC_INSPECTOR_INITRAMFS_PATH
|
||||||
fi
|
fi
|
||||||
ramdisk-image-create $IRONIC_INSPECTOR_RAMDISK_FLAVOR \
|
|
||||||
-o $IRONIC_INSPECTOR_IMAGE_PATH
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -217,22 +217,6 @@ Optionally the following keys might be provided:
|
|||||||
|
|
||||||
* ``logs`` base64-encoded logs from the ramdisk.
|
* ``logs`` base64-encoded logs from the ramdisk.
|
||||||
|
|
||||||
The following keys are supported for backward compatibility with the old
|
|
||||||
bash-based ramdisk, when ``inventory`` is not provided:
|
|
||||||
|
|
||||||
* ``cpus`` number of CPU
|
|
||||||
|
|
||||||
* ``cpu_arch`` architecture of the CPU
|
|
||||||
|
|
||||||
* ``memory_mb`` RAM in MiB
|
|
||||||
|
|
||||||
* ``local_gb`` hard drive size in GiB
|
|
||||||
|
|
||||||
* ``ipmi_address`` IP address of BMC, may be missing on VM
|
|
||||||
|
|
||||||
* ``block_devices`` block devices information for the ``raid_device`` plugin,
|
|
||||||
dictionary with one key: ``serials`` list of serial numbers of block devices.
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
This list highly depends on enabled plugins, provided above are
|
This list highly depends on enabled plugins, provided above are
|
||||||
expected keys for the default set of plugins. See :ref:`plugins`
|
expected keys for the default set of plugins. See :ref:`plugins`
|
||||||
|
@ -132,9 +132,8 @@ As for PXE boot environment, you'll need:
|
|||||||
simultaneously cause conflicts - the same IP address is suggested to
|
simultaneously cause conflicts - the same IP address is suggested to
|
||||||
several nodes.
|
several nodes.
|
||||||
|
|
||||||
* You have to install and configure one of 2 available ramdisks: simple
|
* You have to install and configure the ramdisk to be run on target machines -
|
||||||
bash-based (see `Using simple ramdisk`_) or more complex based on
|
see `Configuring IPA`_.
|
||||||
ironic-python-agent_ (See `Using IPA`_).
|
|
||||||
|
|
||||||
Here is *inspector.conf* you may end up with::
|
Here is *inspector.conf* you may end up with::
|
||||||
|
|
||||||
@ -152,8 +151,8 @@ Here is *inspector.conf* you may end up with::
|
|||||||
.. note::
|
.. note::
|
||||||
Set ``debug = true`` if you want to see complete logs.
|
Set ``debug = true`` if you want to see complete logs.
|
||||||
|
|
||||||
Using IPA
|
Configuring IPA
|
||||||
^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
ironic-python-agent_ is a ramdisk developed for Ironic. During the Liberty
|
ironic-python-agent_ is a ramdisk developed for Ironic. During the Liberty
|
||||||
cycle support for **ironic-inspector** was added. This is the default ramdisk
|
cycle support for **ironic-inspector** was added. This is the default ramdisk
|
||||||
@ -215,34 +214,6 @@ This ramdisk is pluggable: you can insert introspection plugins called
|
|||||||
.. _diskimage-builder: https://github.com/openstack/diskimage-builder
|
.. _diskimage-builder: https://github.com/openstack/diskimage-builder
|
||||||
.. _ironic-python-agent: https://github.com/openstack/ironic-python-agent
|
.. _ironic-python-agent: https://github.com/openstack/ironic-python-agent
|
||||||
|
|
||||||
Using simple ramdisk
|
|
||||||
^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
This ramdisk is deprecated, its use is not recommended.
|
|
||||||
|
|
||||||
* Build and put into your TFTP the kernel and ramdisk created using the
|
|
||||||
diskimage-builder_ `ironic-discoverd-ramdisk element`_::
|
|
||||||
|
|
||||||
ramdisk-image-create -o discovery fedora ironic-discoverd-ramdisk
|
|
||||||
|
|
||||||
You need diskimage-builder_ 0.1.38 or newer to do it (using the latest one
|
|
||||||
is always advised).
|
|
||||||
|
|
||||||
* Configure your ``$TFTPROOT/pxelinux.cfg/default`` with something like::
|
|
||||||
|
|
||||||
default introspect
|
|
||||||
|
|
||||||
label introspect
|
|
||||||
kernel discovery.kernel
|
|
||||||
append initrd=discovery.initramfs discoverd_callback_url=http://{IP}:5050/v1/continue
|
|
||||||
|
|
||||||
ipappend 3
|
|
||||||
|
|
||||||
Replace ``{IP}`` with IP of the machine (do not use loopback interface, it
|
|
||||||
will be accessed by ramdisk on a booting machine).
|
|
||||||
|
|
||||||
.. _ironic-discoverd-ramdisk element: https://github.com/openstack/diskimage-builder/tree/master/elements/ironic-discoverd-ramdisk
|
|
||||||
|
|
||||||
Managing the **ironic-inspector** database
|
Managing the **ironic-inspector** database
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -46,13 +46,6 @@ class RootDiskSelectionHook(base.ProcessingHook):
|
|||||||
node_info=node_info, data=introspection_data)
|
node_info=node_info, data=introspection_data)
|
||||||
return
|
return
|
||||||
|
|
||||||
inventory = introspection_data.get('inventory')
|
|
||||||
if not inventory:
|
|
||||||
raise utils.Error(
|
|
||||||
_('Root device selection requires ironic-python-agent '
|
|
||||||
'as an inspection ramdisk'),
|
|
||||||
node_info=node_info, data=introspection_data)
|
|
||||||
|
|
||||||
if 'size' in hints:
|
if 'size' in hints:
|
||||||
# Special case to match IPA behaviour
|
# Special case to match IPA behaviour
|
||||||
try:
|
try:
|
||||||
@ -62,12 +55,9 @@ class RootDiskSelectionHook(base.ProcessingHook):
|
|||||||
'an integer, got %s') % hints['size'],
|
'an integer, got %s') % hints['size'],
|
||||||
node_info=node_info, data=introspection_data)
|
node_info=node_info, data=introspection_data)
|
||||||
|
|
||||||
disks = inventory.get('disks', [])
|
inventory = utils.get_inventory(introspection_data,
|
||||||
if not disks:
|
node_info=node_info)
|
||||||
raise utils.Error(_('No disks found'),
|
for disk in inventory['disks']:
|
||||||
node_info=node_info, data=introspection_data)
|
|
||||||
|
|
||||||
for disk in disks:
|
|
||||||
properties = disk.copy()
|
properties = disk.copy()
|
||||||
# Root device hints are in GiB, data from IPA is in bytes
|
# Root device hints are in GiB, data from IPA is in bytes
|
||||||
properties['size'] //= units.Gi
|
properties['size'] //= units.Gi
|
||||||
@ -100,7 +90,8 @@ class SchedulerHook(base.ProcessingHook):
|
|||||||
|
|
||||||
def before_update(self, introspection_data, node_info, **kwargs):
|
def before_update(self, introspection_data, node_info, **kwargs):
|
||||||
"""Update node with scheduler properties."""
|
"""Update node with scheduler properties."""
|
||||||
inventory = introspection_data.get('inventory')
|
inventory = utils.get_inventory(introspection_data,
|
||||||
|
node_info=node_info)
|
||||||
errors = []
|
errors = []
|
||||||
|
|
||||||
root_disk = introspection_data.get('root_disk')
|
root_disk = introspection_data.get('root_disk')
|
||||||
@ -108,40 +99,25 @@ class SchedulerHook(base.ProcessingHook):
|
|||||||
introspection_data['local_gb'] = root_disk['size'] // units.Gi
|
introspection_data['local_gb'] = root_disk['size'] // units.Gi
|
||||||
if CONF.processing.disk_partitioning_spacing:
|
if CONF.processing.disk_partitioning_spacing:
|
||||||
introspection_data['local_gb'] -= 1
|
introspection_data['local_gb'] -= 1
|
||||||
elif inventory:
|
else:
|
||||||
errors.append(_('root disk is not supplied by the ramdisk and '
|
errors.append(_('root disk is not supplied by the ramdisk and '
|
||||||
'root_disk_selection hook is not enabled'))
|
'root_disk_selection hook is not enabled'))
|
||||||
|
|
||||||
if inventory:
|
try:
|
||||||
try:
|
introspection_data['cpus'] = int(inventory['cpu']['count'])
|
||||||
introspection_data['cpus'] = int(inventory['cpu']['count'])
|
introspection_data['cpu_arch'] = six.text_type(
|
||||||
introspection_data['cpu_arch'] = six.text_type(
|
inventory['cpu']['architecture'])
|
||||||
inventory['cpu']['architecture'])
|
except (KeyError, ValueError, TypeError):
|
||||||
except (KeyError, ValueError, TypeError):
|
errors.append(_('malformed or missing CPU information: %s') %
|
||||||
errors.append(_('malformed or missing CPU information: %s') %
|
inventory.get('cpu'))
|
||||||
inventory.get('cpu'))
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
introspection_data['memory_mb'] = int(
|
introspection_data['memory_mb'] = int(
|
||||||
inventory['memory']['physical_mb'])
|
inventory['memory']['physical_mb'])
|
||||||
except (KeyError, ValueError, TypeError):
|
except (KeyError, ValueError, TypeError):
|
||||||
errors.append(_('malformed or missing memory information: %s; '
|
errors.append(_('malformed or missing memory information: %s; '
|
||||||
'introspection requires physical memory size '
|
'introspection requires physical memory size '
|
||||||
'from dmidecode') %
|
'from dmidecode') % inventory.get('memory'))
|
||||||
inventory.get('memory'))
|
|
||||||
else:
|
|
||||||
LOG.warning(_LW('No inventory provided: using old bash ramdisk '
|
|
||||||
'is deprecated, please switch to '
|
|
||||||
'ironic-python-agent'),
|
|
||||||
node_info=node_info, data=introspection_data)
|
|
||||||
|
|
||||||
missing = [key for key in self.KEYS
|
|
||||||
if not introspection_data.get(key)]
|
|
||||||
if missing:
|
|
||||||
raise utils.Error(
|
|
||||||
_('The following required parameters are missing: %s') %
|
|
||||||
missing,
|
|
||||||
node_info=node_info, data=introspection_data)
|
|
||||||
|
|
||||||
if errors:
|
if errors:
|
||||||
raise utils.Error(_('The following problems encountered: %s') %
|
raise utils.Error(_('The following problems encountered: %s') %
|
||||||
@ -184,42 +160,36 @@ class ValidateInterfacesHook(base.ProcessingHook):
|
|||||||
:return: dict interface name -> dict with keys 'mac' and 'ip'
|
:return: dict interface name -> dict with keys 'mac' and 'ip'
|
||||||
"""
|
"""
|
||||||
result = {}
|
result = {}
|
||||||
inventory = data.get('inventory', {})
|
inventory = utils.get_inventory(data)
|
||||||
|
|
||||||
if inventory:
|
for iface in inventory['interfaces']:
|
||||||
for iface in inventory.get('interfaces', ()):
|
name = iface.get('name')
|
||||||
name = iface.get('name')
|
mac = iface.get('mac_address')
|
||||||
mac = iface.get('mac_address')
|
ip = iface.get('ipv4_address')
|
||||||
ip = iface.get('ipv4_address')
|
|
||||||
|
|
||||||
if not name:
|
if not name:
|
||||||
LOG.error(_LE('Malformed interface record: %s'),
|
LOG.error(_LE('Malformed interface record: %s'),
|
||||||
iface, data=data)
|
iface, data=data)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not mac:
|
if not mac:
|
||||||
LOG.debug('Skipping interface %s without link information',
|
LOG.debug('Skipping interface %s without link information',
|
||||||
name, data=data)
|
name, data=data)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not utils.is_valid_mac(mac):
|
if not utils.is_valid_mac(mac):
|
||||||
LOG.warning(_LW('MAC %(mac)s for interface %(name)s is '
|
LOG.warning(_LW('MAC %(mac)s for interface %(name)s is '
|
||||||
'not valid, skipping'),
|
'not valid, skipping'),
|
||||||
{'mac': mac, 'name': name},
|
{'mac': mac, 'name': name},
|
||||||
data=data)
|
data=data)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
mac = mac.lower()
|
mac = mac.lower()
|
||||||
|
|
||||||
LOG.debug('Found interface %(name)s with MAC "%(mac)s" and '
|
LOG.debug('Found interface %(name)s with MAC "%(mac)s" and '
|
||||||
'IP address "%(ip)s"',
|
'IP address "%(ip)s"',
|
||||||
{'name': name, 'mac': mac, 'ip': ip}, data=data)
|
{'name': name, 'mac': mac, 'ip': ip}, data=data)
|
||||||
result[name] = {'ip': ip, 'mac': mac}
|
result[name] = {'ip': ip, 'mac': mac}
|
||||||
else:
|
|
||||||
LOG.warning(_LW('No inventory provided: using old bash ramdisk '
|
|
||||||
'is deprecated, please switch to '
|
|
||||||
'ironic-python-agent'), data=data)
|
|
||||||
result = data.get('interfaces')
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -286,10 +286,10 @@ def _finish_set_ipmi_credentials(ironic, node, node_info, introspection_data,
|
|||||||
'value': new_username},
|
'value': new_username},
|
||||||
{'op': 'add', 'path': '/driver_info/ipmi_password',
|
{'op': 'add', 'path': '/driver_info/ipmi_password',
|
||||||
'value': new_password}]
|
'value': new_password}]
|
||||||
if (not ir_utils.get_ipmi_address(node) and
|
new_ipmi_address = utils.get_ipmi_address_from_data(introspection_data)
|
||||||
introspection_data.get('ipmi_address')):
|
if not ir_utils.get_ipmi_address(node) and new_ipmi_address:
|
||||||
patch.append({'op': 'add', 'path': '/driver_info/ipmi_address',
|
patch.append({'op': 'add', 'path': '/driver_info/ipmi_address',
|
||||||
'value': introspection_data['ipmi_address']})
|
'value': new_ipmi_address})
|
||||||
node_info.patch(patch)
|
node_info.patch(patch)
|
||||||
|
|
||||||
for attempt in range(_CREDENTIALS_WAIT_RETRIES):
|
for attempt in range(_CREDENTIALS_WAIT_RETRIES):
|
||||||
|
@ -19,6 +19,7 @@ from oslo_concurrency import lockutils
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_config import fixture as config_fixture
|
from oslo_config import fixture as config_fixture
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
from oslo_utils import units
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
from ironic_inspector.common import i18n
|
from ironic_inspector.common import i18n
|
||||||
@ -78,12 +79,66 @@ class BaseTest(fixtures.TestWithFixtures):
|
|||||||
self.assertPatchEqual(actual, expected)
|
self.assertPatchEqual(actual, expected)
|
||||||
|
|
||||||
|
|
||||||
class NodeTest(BaseTest):
|
class InventoryTest(BaseTest):
|
||||||
|
def setUp(self):
|
||||||
|
super(InventoryTest, self).setUp()
|
||||||
|
# Prepare some realistic inventory
|
||||||
|
# https://github.com/openstack/ironic-inspector/blob/master/HTTP-API.rst # noqa
|
||||||
|
self.bmc_address = '1.2.3.4'
|
||||||
|
self.macs = ['11:22:33:44:55:66', '66:55:44:33:22:11']
|
||||||
|
self.ips = ['1.2.1.2', '1.2.1.1']
|
||||||
|
self.inactive_mac = '12:12:21:12:21:12'
|
||||||
|
self.pxe_mac = self.macs[0]
|
||||||
|
self.all_macs = self.macs + [self.inactive_mac]
|
||||||
|
self.pxe_iface_name = 'eth1'
|
||||||
|
self.data = {
|
||||||
|
'boot_interface': '01-' + self.pxe_mac.replace(':', '-'),
|
||||||
|
'inventory': {
|
||||||
|
'interfaces': [
|
||||||
|
{'name': 'eth1', 'mac_address': self.macs[0],
|
||||||
|
'ipv4_address': self.ips[0]},
|
||||||
|
{'name': 'eth2', 'mac_address': self.inactive_mac},
|
||||||
|
{'name': 'eth3', 'mac_address': self.macs[1],
|
||||||
|
'ipv4_address': self.ips[1]},
|
||||||
|
],
|
||||||
|
'disks': [
|
||||||
|
{'name': '/dev/sda', 'model': 'Big Data Disk',
|
||||||
|
'size': 1000 * units.Gi},
|
||||||
|
{'name': '/dev/sdb', 'model': 'Small OS Disk',
|
||||||
|
'size': 20 * units.Gi},
|
||||||
|
],
|
||||||
|
'cpu': {
|
||||||
|
'count': 4,
|
||||||
|
'architecture': 'x86_64'
|
||||||
|
},
|
||||||
|
'memory': {
|
||||||
|
'physical_mb': 12288
|
||||||
|
},
|
||||||
|
'bmc_address': self.bmc_address
|
||||||
|
},
|
||||||
|
'root_disk': {'name': '/dev/sda', 'model': 'Big Data Disk',
|
||||||
|
'size': 1000 * units.Gi,
|
||||||
|
'wwn': None},
|
||||||
|
}
|
||||||
|
self.inventory = self.data['inventory']
|
||||||
|
self.all_interfaces = {
|
||||||
|
'eth1': {'mac': self.macs[0], 'ip': self.ips[0]},
|
||||||
|
'eth2': {'mac': self.inactive_mac, 'ip': None},
|
||||||
|
'eth3': {'mac': self.macs[1], 'ip': self.ips[1]}
|
||||||
|
}
|
||||||
|
self.active_interfaces = {
|
||||||
|
'eth1': {'mac': self.macs[0], 'ip': self.ips[0]},
|
||||||
|
'eth3': {'mac': self.macs[1], 'ip': self.ips[1]}
|
||||||
|
}
|
||||||
|
self.pxe_interfaces = {
|
||||||
|
self.pxe_iface_name: self.all_interfaces[self.pxe_iface_name]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class NodeTest(InventoryTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(NodeTest, self).setUp()
|
super(NodeTest, self).setUp()
|
||||||
self.uuid = uuidutils.generate_uuid()
|
self.uuid = uuidutils.generate_uuid()
|
||||||
self.bmc_address = '1.2.3.4'
|
|
||||||
self.macs = ['11:22:33:44:55:66', '66:55:44:33:22:11']
|
|
||||||
fake_node = {
|
fake_node = {
|
||||||
'driver': 'pxe_ipmitool',
|
'driver': 'pxe_ipmitool',
|
||||||
'driver_info': {'ipmi_address': self.bmc_address},
|
'driver_info': {'ipmi_address': self.bmc_address},
|
||||||
|
@ -24,7 +24,6 @@ import unittest
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_utils import units
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from ironic_inspector.common import ironic as ir_utils
|
from ironic_inspector.common import ironic as ir_utils
|
||||||
@ -70,62 +69,12 @@ class Base(base.NodeTest):
|
|||||||
self.cli.node.update.return_value = self.node
|
self.cli.node.update.return_value = self.node
|
||||||
self.cli.node.list.return_value = [self.node]
|
self.cli.node.list.return_value = [self.node]
|
||||||
|
|
||||||
# https://github.com/openstack/ironic-inspector/blob/master/HTTP-API.rst # noqa
|
|
||||||
self.data = {
|
|
||||||
'boot_interface': '01-' + self.macs[0].replace(':', '-'),
|
|
||||||
'inventory': {
|
|
||||||
'interfaces': [
|
|
||||||
{'name': 'eth1', 'mac_address': self.macs[0],
|
|
||||||
'ipv4_address': '1.2.1.2'},
|
|
||||||
{'name': 'eth2', 'mac_address': '12:12:21:12:21:12'},
|
|
||||||
{'name': 'eth3', 'mac_address': self.macs[1],
|
|
||||||
'ipv4_address': '1.2.1.1'},
|
|
||||||
],
|
|
||||||
'disks': [
|
|
||||||
{'name': '/dev/sda', 'model': 'Big Data Disk',
|
|
||||||
'size': 1000 * units.Gi},
|
|
||||||
{'name': '/dev/sdb', 'model': 'Small OS Disk',
|
|
||||||
'size': 20 * units.Gi},
|
|
||||||
],
|
|
||||||
'cpu': {
|
|
||||||
'count': 4,
|
|
||||||
'architecture': 'x86_64'
|
|
||||||
},
|
|
||||||
'memory': {
|
|
||||||
'physical_mb': 12288
|
|
||||||
},
|
|
||||||
'bmc_address': self.bmc_address
|
|
||||||
},
|
|
||||||
'root_disk': {'name': '/dev/sda', 'model': 'Big Data Disk',
|
|
||||||
'size': 1000 * units.Gi,
|
|
||||||
'wwn': None},
|
|
||||||
}
|
|
||||||
self.data_old_ramdisk = {
|
|
||||||
'cpus': 4,
|
|
||||||
'cpu_arch': 'x86_64',
|
|
||||||
'memory_mb': 12288,
|
|
||||||
'local_gb': 464,
|
|
||||||
'interfaces': {
|
|
||||||
'eth1': {'mac': self.macs[0], 'ip': '1.2.1.2'},
|
|
||||||
'eth2': {'mac': '12:12:21:12:21:12'},
|
|
||||||
'eth3': {'mac': self.macs[1], 'ip': '1.2.1.1'},
|
|
||||||
},
|
|
||||||
'boot_interface': '01-' + self.macs[0].replace(':', '-'),
|
|
||||||
'ipmi_address': self.bmc_address,
|
|
||||||
}
|
|
||||||
|
|
||||||
self.patch = [
|
self.patch = [
|
||||||
{'op': 'add', 'path': '/properties/cpus', 'value': '4'},
|
{'op': 'add', 'path': '/properties/cpus', 'value': '4'},
|
||||||
{'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
|
{'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
|
||||||
{'op': 'add', 'path': '/properties/memory_mb', 'value': '12288'},
|
{'op': 'add', 'path': '/properties/memory_mb', 'value': '12288'},
|
||||||
{'path': '/properties/local_gb', 'value': '999', 'op': 'add'}
|
{'path': '/properties/local_gb', 'value': '999', 'op': 'add'}
|
||||||
]
|
]
|
||||||
self.patch_old_ramdisk = [
|
|
||||||
{'op': 'add', 'path': '/properties/cpus', 'value': '4'},
|
|
||||||
{'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
|
|
||||||
{'op': 'add', 'path': '/properties/memory_mb', 'value': '12288'},
|
|
||||||
{'path': '/properties/local_gb', 'value': '464', 'op': 'add'}
|
|
||||||
]
|
|
||||||
self.patch_root_hints = [
|
self.patch_root_hints = [
|
||||||
{'op': 'add', 'path': '/properties/cpus', 'value': '4'},
|
{'op': 'add', 'path': '/properties/cpus', 'value': '4'},
|
||||||
{'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
|
{'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
|
||||||
@ -211,27 +160,6 @@ class Test(Base):
|
|||||||
status = self.call_get_status(self.uuid)
|
status = self.call_get_status(self.uuid)
|
||||||
self.assertEqual({'finished': True, 'error': None}, status)
|
self.assertEqual({'finished': True, 'error': None}, status)
|
||||||
|
|
||||||
def test_old_ramdisk(self):
|
|
||||||
self.call_introspect(self.uuid)
|
|
||||||
eventlet.greenthread.sleep(DEFAULT_SLEEP)
|
|
||||||
self.cli.node.set_power_state.assert_called_once_with(self.uuid,
|
|
||||||
'reboot')
|
|
||||||
|
|
||||||
status = self.call_get_status(self.uuid)
|
|
||||||
self.assertEqual({'finished': False, 'error': None}, status)
|
|
||||||
|
|
||||||
res = self.call_continue(self.data_old_ramdisk)
|
|
||||||
self.assertEqual({'uuid': self.uuid}, res)
|
|
||||||
eventlet.greenthread.sleep(DEFAULT_SLEEP)
|
|
||||||
|
|
||||||
self.assertCalledWithPatch(self.patch_old_ramdisk,
|
|
||||||
self.cli.node.update)
|
|
||||||
self.cli.port.create.assert_called_once_with(
|
|
||||||
node_uuid=self.uuid, address='11:22:33:44:55:66')
|
|
||||||
|
|
||||||
status = self.call_get_status(self.uuid)
|
|
||||||
self.assertEqual({'finished': True, 'error': None}, status)
|
|
||||||
|
|
||||||
def test_setup_ipmi(self):
|
def test_setup_ipmi(self):
|
||||||
patch_credentials = [
|
patch_credentials = [
|
||||||
{'op': 'add', 'path': '/driver_info/ipmi_username',
|
{'op': 'add', 'path': '/driver_info/ipmi_username',
|
||||||
|
@ -29,22 +29,6 @@ class TestSchedulerHook(test_base.NodeTest):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestSchedulerHook, self).setUp()
|
super(TestSchedulerHook, self).setUp()
|
||||||
self.hook = std_plugins.SchedulerHook()
|
self.hook = std_plugins.SchedulerHook()
|
||||||
self.data = {
|
|
||||||
'inventory': {
|
|
||||||
'cpu': {'count': 2, 'architecture': 'x86_64'},
|
|
||||||
'memory': {'physical_mb': 1024},
|
|
||||||
},
|
|
||||||
'root_disk': {
|
|
||||||
'name': '/dev/sda',
|
|
||||||
'size': 21 * units.Gi
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.old_data = {
|
|
||||||
'local_gb': 20,
|
|
||||||
'memory_mb': 1024,
|
|
||||||
'cpus': 2,
|
|
||||||
'cpu_arch': 'x86_64'
|
|
||||||
}
|
|
||||||
self.node_info = node_cache.NodeInfo(uuid=self.uuid, started_at=0,
|
self.node_info = node_cache.NodeInfo(uuid=self.uuid, started_at=0,
|
||||||
node=self.node)
|
node=self.node)
|
||||||
|
|
||||||
@ -53,43 +37,24 @@ class TestSchedulerHook(test_base.NodeTest):
|
|||||||
ext = base.processing_hooks_manager()['scheduler']
|
ext = base.processing_hooks_manager()['scheduler']
|
||||||
self.assertIsInstance(ext.obj, std_plugins.SchedulerHook)
|
self.assertIsInstance(ext.obj, std_plugins.SchedulerHook)
|
||||||
|
|
||||||
def test_compat_missing(self):
|
|
||||||
for key in self.old_data:
|
|
||||||
new_data = self.old_data.copy()
|
|
||||||
del new_data[key]
|
|
||||||
self.assertRaisesRegexp(utils.Error, key,
|
|
||||||
self.hook.before_update, new_data,
|
|
||||||
self.node_info)
|
|
||||||
|
|
||||||
def test_no_root_disk(self):
|
def test_no_root_disk(self):
|
||||||
self.assertRaisesRegexp(utils.Error, 'root disk is not supplied',
|
del self.inventory['disks']
|
||||||
self.hook.before_update,
|
self.assertRaisesRegexp(utils.Error, 'disks key is missing or empty',
|
||||||
{'inventory': {'disks': []}}, self.node_info)
|
self.hook.before_update, self.data,
|
||||||
|
self.node_info)
|
||||||
|
|
||||||
@mock.patch.object(node_cache.NodeInfo, 'patch')
|
@mock.patch.object(node_cache.NodeInfo, 'patch')
|
||||||
def test_ok(self, mock_patch):
|
def test_ok(self, mock_patch):
|
||||||
patch = [
|
patch = [
|
||||||
{'path': '/properties/cpus', 'value': '2', 'op': 'add'},
|
{'path': '/properties/cpus', 'value': '4', 'op': 'add'},
|
||||||
{'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
|
{'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
|
||||||
{'path': '/properties/memory_mb', 'value': '1024', 'op': 'add'},
|
{'path': '/properties/memory_mb', 'value': '12288', 'op': 'add'},
|
||||||
{'path': '/properties/local_gb', 'value': '20', 'op': 'add'}
|
{'path': '/properties/local_gb', 'value': '999', 'op': 'add'}
|
||||||
]
|
]
|
||||||
|
|
||||||
self.hook.before_update(self.data, self.node_info)
|
self.hook.before_update(self.data, self.node_info)
|
||||||
self.assertCalledWithPatch(patch, mock_patch)
|
self.assertCalledWithPatch(patch, mock_patch)
|
||||||
|
|
||||||
@mock.patch.object(node_cache.NodeInfo, 'patch')
|
|
||||||
def test_compat_ok(self, mock_patch):
|
|
||||||
patch = [
|
|
||||||
{'path': '/properties/cpus', 'value': '2', 'op': 'add'},
|
|
||||||
{'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
|
|
||||||
{'path': '/properties/memory_mb', 'value': '1024', 'op': 'add'},
|
|
||||||
{'path': '/properties/local_gb', 'value': '20', 'op': 'add'}
|
|
||||||
]
|
|
||||||
|
|
||||||
self.hook.before_update(self.old_data, self.node_info)
|
|
||||||
self.assertCalledWithPatch(patch, mock_patch)
|
|
||||||
|
|
||||||
@mock.patch.object(node_cache.NodeInfo, 'patch')
|
@mock.patch.object(node_cache.NodeInfo, 'patch')
|
||||||
def test_no_overwrite(self, mock_patch):
|
def test_no_overwrite(self, mock_patch):
|
||||||
CONF.set_override('overwrite_existing', False, 'processing')
|
CONF.set_override('overwrite_existing', False, 'processing')
|
||||||
@ -98,36 +63,21 @@ class TestSchedulerHook(test_base.NodeTest):
|
|||||||
'cpu_arch': 'i686'
|
'cpu_arch': 'i686'
|
||||||
}
|
}
|
||||||
patch = [
|
patch = [
|
||||||
{'path': '/properties/cpus', 'value': '2', 'op': 'add'},
|
{'path': '/properties/cpus', 'value': '4', 'op': 'add'},
|
||||||
{'path': '/properties/local_gb', 'value': '20', 'op': 'add'}
|
{'path': '/properties/local_gb', 'value': '999', 'op': 'add'}
|
||||||
]
|
]
|
||||||
|
|
||||||
self.hook.before_update(self.data, self.node_info)
|
self.hook.before_update(self.data, self.node_info)
|
||||||
self.assertCalledWithPatch(patch, mock_patch)
|
self.assertCalledWithPatch(patch, mock_patch)
|
||||||
|
|
||||||
@mock.patch.object(node_cache.NodeInfo, 'patch')
|
|
||||||
def test_compat_root_disk(self, mock_patch):
|
|
||||||
self.old_data['root_disk'] = {'name': '/dev/sda',
|
|
||||||
'size': 42 * units.Gi}
|
|
||||||
patch = [
|
|
||||||
{'path': '/properties/cpus', 'value': '2', 'op': 'add'},
|
|
||||||
{'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
|
|
||||||
{'path': '/properties/memory_mb', 'value': '1024', 'op': 'add'},
|
|
||||||
{'path': '/properties/local_gb', 'value': '41', 'op': 'add'}
|
|
||||||
]
|
|
||||||
|
|
||||||
self.hook.before_update(self.old_data, self.node_info)
|
|
||||||
self.assertCalledWithPatch(patch, mock_patch)
|
|
||||||
|
|
||||||
@mock.patch.object(node_cache.NodeInfo, 'patch')
|
@mock.patch.object(node_cache.NodeInfo, 'patch')
|
||||||
def test_root_disk_no_spacing(self, mock_patch):
|
def test_root_disk_no_spacing(self, mock_patch):
|
||||||
CONF.set_override('disk_partitioning_spacing', False, 'processing')
|
CONF.set_override('disk_partitioning_spacing', False, 'processing')
|
||||||
self.data['root_disk'] = {'name': '/dev/sda', 'size': 42 * units.Gi}
|
|
||||||
patch = [
|
patch = [
|
||||||
{'path': '/properties/cpus', 'value': '2', 'op': 'add'},
|
{'path': '/properties/cpus', 'value': '4', 'op': 'add'},
|
||||||
{'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
|
{'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
|
||||||
{'path': '/properties/memory_mb', 'value': '1024', 'op': 'add'},
|
{'path': '/properties/memory_mb', 'value': '12288', 'op': 'add'},
|
||||||
{'path': '/properties/local_gb', 'value': '42', 'op': 'add'}
|
{'path': '/properties/local_gb', 'value': '1000', 'op': 'add'}
|
||||||
]
|
]
|
||||||
|
|
||||||
self.hook.before_update(self.data, self.node_info)
|
self.hook.before_update(self.data, self.node_info)
|
||||||
@ -138,38 +88,9 @@ class TestValidateInterfacesHook(test_base.NodeTest):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestValidateInterfacesHook, self).setUp()
|
super(TestValidateInterfacesHook, self).setUp()
|
||||||
self.hook = std_plugins.ValidateInterfacesHook()
|
self.hook = std_plugins.ValidateInterfacesHook()
|
||||||
self.data = {
|
|
||||||
'inventory': {
|
|
||||||
'interfaces': [
|
|
||||||
{'name': 'em1', 'mac_address': '11:11:11:11:11:11',
|
|
||||||
'ipv4_address': '1.1.1.1'},
|
|
||||||
{'name': 'em2', 'mac_address': '22:22:22:22:22:22',
|
|
||||||
'ipv4_address': '2.2.2.2'},
|
|
||||||
{'name': 'em3', 'mac_address': '33:33:33:33:33:33',
|
|
||||||
'ipv4_address': None},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'boot_interface': '01-22-22-22-22-22-22'
|
|
||||||
}
|
|
||||||
self.old_data = {
|
|
||||||
'interfaces': {
|
|
||||||
'em1': {'mac': '11:11:11:11:11:11', 'ip': '1.1.1.1'},
|
|
||||||
'em2': {'mac': '22:22:22:22:22:22', 'ip': '2.2.2.2'},
|
|
||||||
'em3': {'mac': '33:33:33:33:33:33'}
|
|
||||||
},
|
|
||||||
'boot_interface': '01-22-22-22-22-22-22',
|
|
||||||
}
|
|
||||||
self.orig_interfaces = self.old_data['interfaces'].copy()
|
|
||||||
self.orig_interfaces['em3']['ip'] = None
|
|
||||||
self.pxe_interface = self.old_data['interfaces']['em2']
|
|
||||||
self.active_interfaces = {
|
|
||||||
'em1': {'mac': '11:11:11:11:11:11', 'ip': '1.1.1.1'},
|
|
||||||
'em2': {'mac': '22:22:22:22:22:22', 'ip': '2.2.2.2'},
|
|
||||||
}
|
|
||||||
|
|
||||||
self.existing_ports = [mock.Mock(spec=['address', 'uuid'],
|
self.existing_ports = [mock.Mock(spec=['address', 'uuid'],
|
||||||
address=a)
|
address=a)
|
||||||
for a in ('11:11:11:11:11:11',
|
for a in (self.macs[1],
|
||||||
'44:44:44:44:44:44')]
|
'44:44:44:44:44:44')]
|
||||||
self.node_info = node_cache.NodeInfo(uuid=self.uuid, started_at=0,
|
self.node_info = node_cache.NodeInfo(uuid=self.uuid, started_at=0,
|
||||||
node=self.node,
|
node=self.node,
|
||||||
@ -190,29 +111,31 @@ class TestValidateInterfacesHook(test_base.NodeTest):
|
|||||||
self.assertRaises(SystemExit, std_plugins.ValidateInterfacesHook)
|
self.assertRaises(SystemExit, std_plugins.ValidateInterfacesHook)
|
||||||
|
|
||||||
def test_no_interfaces(self):
|
def test_no_interfaces(self):
|
||||||
self.assertRaisesRegexp(utils.Error, 'No interfaces',
|
self.assertRaisesRegexp(utils.Error,
|
||||||
|
'Hardware inventory is empty or missing',
|
||||||
self.hook.before_processing, {})
|
self.hook.before_processing, {})
|
||||||
self.assertRaisesRegexp(utils.Error, 'No interfaces',
|
self.assertRaisesRegexp(utils.Error,
|
||||||
|
'Hardware inventory is empty or missing',
|
||||||
self.hook.before_processing, {'inventory': {}})
|
self.hook.before_processing, {'inventory': {}})
|
||||||
self.assertRaisesRegexp(utils.Error, 'No interfaces',
|
del self.inventory['interfaces']
|
||||||
self.hook.before_processing, {'inventory': {
|
self.assertRaisesRegexp(utils.Error,
|
||||||
'interfaces': []
|
'interfaces key is missing or empty',
|
||||||
}})
|
self.hook.before_processing, self.data)
|
||||||
|
|
||||||
def test_only_pxe(self):
|
def test_only_pxe(self):
|
||||||
self.hook.before_processing(self.data)
|
self.hook.before_processing(self.data)
|
||||||
|
|
||||||
self.assertEqual({'em2': self.pxe_interface}, self.data['interfaces'])
|
self.assertEqual(self.pxe_interfaces, self.data['interfaces'])
|
||||||
self.assertEqual([self.pxe_interface['mac']], self.data['macs'])
|
self.assertEqual([self.pxe_mac], self.data['macs'])
|
||||||
self.assertEqual(self.orig_interfaces, self.data['all_interfaces'])
|
self.assertEqual(self.all_interfaces, self.data['all_interfaces'])
|
||||||
|
|
||||||
def test_only_pxe_mac_format(self):
|
def test_only_pxe_mac_format(self):
|
||||||
self.data['boot_interface'] = '22:22:22:22:22:22'
|
self.data['boot_interface'] = self.pxe_mac
|
||||||
self.hook.before_processing(self.data)
|
self.hook.before_processing(self.data)
|
||||||
|
|
||||||
self.assertEqual({'em2': self.pxe_interface}, self.data['interfaces'])
|
self.assertEqual(self.pxe_interfaces, self.data['interfaces'])
|
||||||
self.assertEqual([self.pxe_interface['mac']], self.data['macs'])
|
self.assertEqual([self.pxe_mac], self.data['macs'])
|
||||||
self.assertEqual(self.orig_interfaces, self.data['all_interfaces'])
|
self.assertEqual(self.all_interfaces, self.data['all_interfaces'])
|
||||||
|
|
||||||
def test_only_pxe_not_found(self):
|
def test_only_pxe_not_found(self):
|
||||||
self.data['boot_interface'] = 'aa:bb:cc:dd:ee:ff'
|
self.data['boot_interface'] = 'aa:bb:cc:dd:ee:ff'
|
||||||
@ -227,7 +150,7 @@ class TestValidateInterfacesHook(test_base.NodeTest):
|
|||||||
self.assertEqual(sorted(i['mac'] for i in
|
self.assertEqual(sorted(i['mac'] for i in
|
||||||
self.active_interfaces.values()),
|
self.active_interfaces.values()),
|
||||||
sorted(self.data['macs']))
|
sorted(self.data['macs']))
|
||||||
self.assertEqual(self.orig_interfaces, self.data['all_interfaces'])
|
self.assertEqual(self.all_interfaces, self.data['all_interfaces'])
|
||||||
|
|
||||||
def test_only_active(self):
|
def test_only_active(self):
|
||||||
CONF.set_override('add_ports', 'active', 'processing')
|
CONF.set_override('add_ports', 'active', 'processing')
|
||||||
@ -237,52 +160,43 @@ class TestValidateInterfacesHook(test_base.NodeTest):
|
|||||||
self.assertEqual(sorted(i['mac'] for i in
|
self.assertEqual(sorted(i['mac'] for i in
|
||||||
self.active_interfaces.values()),
|
self.active_interfaces.values()),
|
||||||
sorted(self.data['macs']))
|
sorted(self.data['macs']))
|
||||||
self.assertEqual(self.orig_interfaces, self.data['all_interfaces'])
|
self.assertEqual(self.all_interfaces, self.data['all_interfaces'])
|
||||||
|
|
||||||
def test_all(self):
|
def test_all(self):
|
||||||
CONF.set_override('add_ports', 'all', 'processing')
|
CONF.set_override('add_ports', 'all', 'processing')
|
||||||
self.hook.before_processing(self.data)
|
self.hook.before_processing(self.data)
|
||||||
|
|
||||||
self.assertEqual(self.orig_interfaces, self.data['interfaces'])
|
self.assertEqual(self.all_interfaces, self.data['interfaces'])
|
||||||
self.assertEqual(sorted(i['mac'] for i in
|
self.assertEqual(sorted(i['mac'] for i in
|
||||||
self.orig_interfaces.values()),
|
self.all_interfaces.values()),
|
||||||
sorted(self.data['macs']))
|
sorted(self.data['macs']))
|
||||||
self.assertEqual(self.orig_interfaces, self.data['all_interfaces'])
|
self.assertEqual(self.all_interfaces, self.data['all_interfaces'])
|
||||||
|
|
||||||
def test_malformed_interfaces(self):
|
def test_malformed_interfaces(self):
|
||||||
self.data = {
|
self.inventory['interfaces'] = [
|
||||||
'inventory': {
|
# no name
|
||||||
'interfaces': [
|
{'mac_address': '11:11:11:11:11:11', 'ipv4_address': '1.1.1.1'},
|
||||||
# no name
|
# empty
|
||||||
{'mac_address': '11:11:11:11:11:11',
|
{},
|
||||||
'ipv4_address': '1.1.1.1'},
|
]
|
||||||
# empty
|
|
||||||
{},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
self.assertRaisesRegexp(utils.Error, 'No interfaces supplied',
|
self.assertRaisesRegexp(utils.Error, 'No interfaces supplied',
|
||||||
self.hook.before_processing, self.data)
|
self.hook.before_processing, self.data)
|
||||||
|
|
||||||
def test_skipped_interfaces(self):
|
def test_skipped_interfaces(self):
|
||||||
CONF.set_override('add_ports', 'all', 'processing')
|
CONF.set_override('add_ports', 'all', 'processing')
|
||||||
self.data = {
|
self.inventory['interfaces'] = [
|
||||||
'inventory': {
|
# local interface (by name)
|
||||||
'interfaces': [
|
{'name': 'lo', 'mac_address': '11:11:11:11:11:11',
|
||||||
# local interface (by name)
|
'ipv4_address': '1.1.1.1'},
|
||||||
{'name': 'lo', 'mac_address': '11:11:11:11:11:11',
|
# local interface (by IP address)
|
||||||
'ipv4_address': '1.1.1.1'},
|
{'name': 'em1', 'mac_address': '22:22:22:22:22:22',
|
||||||
# local interface (by IP address)
|
'ipv4_address': '127.0.0.1'},
|
||||||
{'name': 'em1', 'mac_address': '22:22:22:22:22:22',
|
# no MAC provided
|
||||||
'ipv4_address': '127.0.0.1'},
|
{'name': 'em3', 'ipv4_address': '2.2.2.2'},
|
||||||
# no MAC provided
|
# malformed MAC provided
|
||||||
{'name': 'em3', 'ipv4_address': '2.2.2.2'},
|
{'name': 'em4', 'mac_address': 'foobar',
|
||||||
# malformed MAC provided
|
'ipv4_address': '2.2.2.2'},
|
||||||
{'name': 'em4', 'mac_address': 'foobar',
|
]
|
||||||
'ipv4_address': '2.2.2.2'},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
self.assertRaisesRegexp(utils.Error, 'No suitable interfaces found',
|
self.assertRaisesRegexp(utils.Error, 'No suitable interfaces found',
|
||||||
self.hook.before_processing, self.data)
|
self.hook.before_processing, self.data)
|
||||||
|
|
||||||
@ -294,7 +208,7 @@ class TestValidateInterfacesHook(test_base.NodeTest):
|
|||||||
@mock.patch.object(node_cache.NodeInfo, 'delete_port')
|
@mock.patch.object(node_cache.NodeInfo, 'delete_port')
|
||||||
def test_keep_present(self, mock_delete_port):
|
def test_keep_present(self, mock_delete_port):
|
||||||
CONF.set_override('keep_ports', 'present', 'processing')
|
CONF.set_override('keep_ports', 'present', 'processing')
|
||||||
self.data['all_interfaces'] = self.orig_interfaces
|
self.data['all_interfaces'] = self.all_interfaces
|
||||||
self.hook.before_update(self.data, self.node_info)
|
self.hook.before_update(self.data, self.node_info)
|
||||||
|
|
||||||
mock_delete_port.assert_called_once_with(self.existing_ports[1])
|
mock_delete_port.assert_called_once_with(self.existing_ports[1])
|
||||||
@ -302,7 +216,7 @@ class TestValidateInterfacesHook(test_base.NodeTest):
|
|||||||
@mock.patch.object(node_cache.NodeInfo, 'delete_port')
|
@mock.patch.object(node_cache.NodeInfo, 'delete_port')
|
||||||
def test_keep_added(self, mock_delete_port):
|
def test_keep_added(self, mock_delete_port):
|
||||||
CONF.set_override('keep_ports', 'added', 'processing')
|
CONF.set_override('keep_ports', 'added', 'processing')
|
||||||
self.data['macs'] = [self.pxe_interface['mac']]
|
self.data['macs'] = [self.pxe_mac]
|
||||||
self.hook.before_update(self.data, self.node_info)
|
self.hook.before_update(self.data, self.node_info)
|
||||||
|
|
||||||
mock_delete_port.assert_any_call(self.existing_ports[0])
|
mock_delete_port.assert_any_call(self.existing_ports[0])
|
||||||
@ -313,28 +227,21 @@ class TestRootDiskSelection(test_base.NodeTest):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestRootDiskSelection, self).setUp()
|
super(TestRootDiskSelection, self).setUp()
|
||||||
self.hook = std_plugins.RootDiskSelectionHook()
|
self.hook = std_plugins.RootDiskSelectionHook()
|
||||||
self.data = {
|
self.inventory['disks'] = [
|
||||||
'inventory': {
|
{'model': 'Model 1', 'size': 20 * units.Gi, 'name': '/dev/sdb'},
|
||||||
'disks': [
|
{'model': 'Model 2', 'size': 5 * units.Gi, 'name': '/dev/sda'},
|
||||||
{'model': 'Model 1', 'size': 20 * units.Gi,
|
{'model': 'Model 3', 'size': 10 * units.Gi, 'name': '/dev/sdc'},
|
||||||
'name': '/dev/sdb'},
|
{'model': 'Model 4', 'size': 4 * units.Gi, 'name': '/dev/sdd'},
|
||||||
{'model': 'Model 2', 'size': 5 * units.Gi,
|
{'model': 'Too Small', 'size': 1 * units.Gi, 'name': '/dev/sde'},
|
||||||
'name': '/dev/sda'},
|
]
|
||||||
{'model': 'Model 3', 'size': 10 * units.Gi,
|
self.matched = self.inventory['disks'][2].copy()
|
||||||
'name': '/dev/sdc'},
|
|
||||||
{'model': 'Model 4', 'size': 4 * units.Gi,
|
|
||||||
'name': '/dev/sdd'},
|
|
||||||
{'model': 'Too Small', 'size': 1 * units.Gi,
|
|
||||||
'name': '/dev/sde'},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.matched = self.data['inventory']['disks'][2].copy()
|
|
||||||
self.node_info = mock.Mock(spec=node_cache.NodeInfo,
|
self.node_info = mock.Mock(spec=node_cache.NodeInfo,
|
||||||
uuid=self.uuid,
|
uuid=self.uuid,
|
||||||
**{'node.return_value': self.node})
|
**{'node.return_value': self.node})
|
||||||
|
|
||||||
def test_no_hints(self):
|
def test_no_hints(self):
|
||||||
|
del self.data['root_disk']
|
||||||
|
|
||||||
self.hook.before_update(self.data, self.node_info)
|
self.hook.before_update(self.data, self.node_info)
|
||||||
|
|
||||||
self.assertNotIn('local_gb', self.data)
|
self.assertNotIn('local_gb', self.data)
|
||||||
@ -343,9 +250,10 @@ class TestRootDiskSelection(test_base.NodeTest):
|
|||||||
def test_no_inventory(self):
|
def test_no_inventory(self):
|
||||||
self.node.properties['root_device'] = {'model': 'foo'}
|
self.node.properties['root_device'] = {'model': 'foo'}
|
||||||
del self.data['inventory']
|
del self.data['inventory']
|
||||||
|
del self.data['root_disk']
|
||||||
|
|
||||||
self.assertRaisesRegexp(utils.Error,
|
self.assertRaisesRegexp(utils.Error,
|
||||||
'requires ironic-python-agent',
|
'Hardware inventory is empty or missing',
|
||||||
self.hook.before_update,
|
self.hook.before_update,
|
||||||
self.data, self.node_info)
|
self.data, self.node_info)
|
||||||
|
|
||||||
@ -354,10 +262,10 @@ class TestRootDiskSelection(test_base.NodeTest):
|
|||||||
|
|
||||||
def test_no_disks(self):
|
def test_no_disks(self):
|
||||||
self.node.properties['root_device'] = {'size': 10}
|
self.node.properties['root_device'] = {'size': 10}
|
||||||
self.data['inventory']['disks'] = []
|
self.inventory['disks'] = []
|
||||||
|
|
||||||
self.assertRaisesRegexp(utils.Error,
|
self.assertRaisesRegexp(utils.Error,
|
||||||
'No disks found',
|
'disks key is missing or empty',
|
||||||
self.hook.before_update,
|
self.hook.before_update,
|
||||||
self.data, self.node_info)
|
self.data, self.node_info)
|
||||||
|
|
||||||
@ -379,6 +287,7 @@ class TestRootDiskSelection(test_base.NodeTest):
|
|||||||
def test_one_fails(self):
|
def test_one_fails(self):
|
||||||
self.node.properties['root_device'] = {'size': 10,
|
self.node.properties['root_device'] = {'size': 10,
|
||||||
'model': 'Model 42'}
|
'model': 'Model 42'}
|
||||||
|
del self.data['root_disk']
|
||||||
|
|
||||||
self.assertRaisesRegexp(utils.Error,
|
self.assertRaisesRegexp(utils.Error,
|
||||||
'No disks satisfied root device hints',
|
'No disks satisfied root device hints',
|
||||||
@ -402,15 +311,12 @@ class TestRootDiskSelection(test_base.NodeTest):
|
|||||||
self.data, self.node_info)
|
self.data, self.node_info)
|
||||||
|
|
||||||
|
|
||||||
class TestRamdiskError(test_base.BaseTest):
|
class TestRamdiskError(test_base.InventoryTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestRamdiskError, self).setUp()
|
super(TestRamdiskError, self).setUp()
|
||||||
self.msg = 'BOOM'
|
self.msg = 'BOOM'
|
||||||
self.bmc_address = '1.2.3.4'
|
self.bmc_address = '1.2.3.4'
|
||||||
self.data = {
|
self.data['error'] = self.msg
|
||||||
'error': self.msg,
|
|
||||||
'ipmi_address': self.bmc_address,
|
|
||||||
}
|
|
||||||
|
|
||||||
def test_no_logs(self):
|
def test_no_logs(self):
|
||||||
self.assertRaisesRegexp(utils.Error,
|
self.assertRaisesRegexp(utils.Error,
|
||||||
|
@ -43,24 +43,9 @@ class BaseTest(test_base.NodeTest):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(BaseTest, self).setUp()
|
super(BaseTest, self).setUp()
|
||||||
self.started_at = time.time()
|
self.started_at = time.time()
|
||||||
self.pxe_mac = self.macs[1]
|
|
||||||
self.data = {
|
|
||||||
'ipmi_address': self.bmc_address,
|
|
||||||
'cpus': 2,
|
|
||||||
'cpu_arch': 'x86_64',
|
|
||||||
'memory_mb': 1024,
|
|
||||||
'local_gb': 20,
|
|
||||||
'interfaces': {
|
|
||||||
'em1': {'mac': self.macs[0], 'ip': '1.2.0.1'},
|
|
||||||
'em2': {'mac': self.macs[1], 'ip': '1.2.0.2'},
|
|
||||||
'em3': {'mac': 'DE:AD:BE:EF:DE:AD'},
|
|
||||||
},
|
|
||||||
'boot_interface': '01-' + self.pxe_mac.replace(':', '-'),
|
|
||||||
}
|
|
||||||
self.all_ports = [mock.Mock(uuid=uuidutils.generate_uuid(),
|
self.all_ports = [mock.Mock(uuid=uuidutils.generate_uuid(),
|
||||||
address=mac) for mac in self.macs]
|
address=mac) for mac in self.macs]
|
||||||
self.ports = [self.all_ports[1]]
|
self.ports = [self.all_ports[1]]
|
||||||
self.all_macs = self.macs + ['DE:AD:BE:EF:DE:AD']
|
|
||||||
self.fake_result_json = 'node json'
|
self.fake_result_json = 'node json'
|
||||||
|
|
||||||
self.cli_fixture = self.useFixture(
|
self.cli_fixture = self.useFixture(
|
||||||
@ -94,10 +79,6 @@ class TestProcess(BaseProcessTest):
|
|||||||
|
|
||||||
self.assertEqual(self.fake_result_json, res)
|
self.assertEqual(self.fake_result_json, res)
|
||||||
|
|
||||||
# Only boot interface is added by default
|
|
||||||
self.assertEqual(['em2'], sorted(self.data['interfaces']))
|
|
||||||
self.assertEqual([self.pxe_mac], self.data['macs'])
|
|
||||||
|
|
||||||
self.find_mock.assert_called_once_with(bmc_address=self.bmc_address,
|
self.find_mock.assert_called_once_with(bmc_address=self.bmc_address,
|
||||||
mac=mock.ANY)
|
mac=mock.ANY)
|
||||||
actual_macs = self.find_mock.call_args[1]['mac']
|
actual_macs = self.find_mock.call_args[1]['mac']
|
||||||
@ -107,7 +88,7 @@ class TestProcess(BaseProcessTest):
|
|||||||
self.node, self.data, self.node_info)
|
self.node, self.data, self.node_info)
|
||||||
|
|
||||||
def test_no_ipmi(self):
|
def test_no_ipmi(self):
|
||||||
del self.data['ipmi_address']
|
del self.inventory['bmc_address']
|
||||||
process.process(self.data)
|
process.process(self.data)
|
||||||
|
|
||||||
self.find_mock.assert_called_once_with(bmc_address=None, mac=mock.ANY)
|
self.find_mock.assert_called_once_with(bmc_address=None, mac=mock.ANY)
|
||||||
@ -349,15 +330,8 @@ class TestProcessNode(BaseTest):
|
|||||||
'processing')
|
'processing')
|
||||||
self.validate_attempts = 5
|
self.validate_attempts = 5
|
||||||
self.data['macs'] = self.macs # validate_interfaces hook
|
self.data['macs'] = self.macs # validate_interfaces hook
|
||||||
self.data['all_interfaces'] = self.data['interfaces']
|
|
||||||
self.ports = self.all_ports
|
self.ports = self.all_ports
|
||||||
|
|
||||||
self.patch_props = [
|
|
||||||
{'path': '/properties/cpus', 'value': '2', 'op': 'add'},
|
|
||||||
{'path': '/properties/cpu_arch', 'value': 'x86_64', 'op': 'add'},
|
|
||||||
{'path': '/properties/memory_mb', 'value': '1024', 'op': 'add'},
|
|
||||||
{'path': '/properties/local_gb', 'value': '20', 'op': 'add'}
|
|
||||||
] # scheduler hook
|
|
||||||
self.new_creds = ('user', 'password')
|
self.new_creds = ('user', 'password')
|
||||||
self.patch_credentials = [
|
self.patch_credentials = [
|
||||||
{'op': 'add', 'path': '/driver_info/ipmi_username',
|
{'op': 'add', 'path': '/driver_info/ipmi_username',
|
||||||
@ -405,24 +379,12 @@ class TestProcessNode(BaseTest):
|
|||||||
address=self.macs[0])
|
address=self.macs[0])
|
||||||
self.cli.port.create.assert_any_call(node_uuid=self.uuid,
|
self.cli.port.create.assert_any_call(node_uuid=self.uuid,
|
||||||
address=self.macs[1])
|
address=self.macs[1])
|
||||||
self.assertCalledWithPatch(self.patch_props, self.cli.node.update)
|
|
||||||
self.cli.node.set_power_state.assert_called_once_with(self.uuid, 'off')
|
self.cli.node.set_power_state.assert_called_once_with(self.uuid, 'off')
|
||||||
self.assertFalse(self.cli.node.validate.called)
|
self.assertFalse(self.cli.node.validate.called)
|
||||||
|
|
||||||
post_hook_mock.assert_called_once_with(self.data, self.node_info)
|
post_hook_mock.assert_called_once_with(self.data, self.node_info)
|
||||||
finished_mock.assert_called_once_with(mock.ANY)
|
finished_mock.assert_called_once_with(mock.ANY)
|
||||||
|
|
||||||
def test_overwrite_disabled(self):
|
|
||||||
CONF.set_override('overwrite_existing', False, 'processing')
|
|
||||||
patch = [
|
|
||||||
{'op': 'add', 'path': '/properties/cpus', 'value': '2'},
|
|
||||||
{'op': 'add', 'path': '/properties/memory_mb', 'value': '1024'},
|
|
||||||
]
|
|
||||||
|
|
||||||
process._process_node(self.node, self.data, self.node_info)
|
|
||||||
|
|
||||||
self.assertCalledWithPatch(patch, self.cli.node.update)
|
|
||||||
|
|
||||||
def test_port_failed(self):
|
def test_port_failed(self):
|
||||||
self.cli.port.create.side_effect = (
|
self.cli.port.create.side_effect = (
|
||||||
[exceptions.Conflict()] + self.ports[1:])
|
[exceptions.Conflict()] + self.ports[1:])
|
||||||
@ -433,7 +395,6 @@ class TestProcessNode(BaseTest):
|
|||||||
address=self.macs[0])
|
address=self.macs[0])
|
||||||
self.cli.port.create.assert_any_call(node_uuid=self.uuid,
|
self.cli.port.create.assert_any_call(node_uuid=self.uuid,
|
||||||
address=self.macs[1])
|
address=self.macs[1])
|
||||||
self.assertCalledWithPatch(self.patch_props, self.cli.node.update)
|
|
||||||
|
|
||||||
def test_set_ipmi_credentials(self):
|
def test_set_ipmi_credentials(self):
|
||||||
self.node_info.set_option('new_ipmi_credentials', self.new_creds)
|
self.node_info.set_option('new_ipmi_credentials', self.new_creds)
|
||||||
@ -485,7 +446,6 @@ class TestProcessNode(BaseTest):
|
|||||||
process._process_node(self.node, self.data, self.node_info)
|
process._process_node(self.node, self.data, self.node_info)
|
||||||
|
|
||||||
self.cli.node.set_power_state.assert_called_once_with(self.uuid, 'off')
|
self.cli.node.set_power_state.assert_called_once_with(self.uuid, 'off')
|
||||||
self.assertCalledWithPatch(self.patch_props, self.cli.node.update)
|
|
||||||
finished_mock.assert_called_once_with(
|
finished_mock.assert_called_once_with(
|
||||||
mock.ANY,
|
mock.ANY,
|
||||||
error='Failed to power off node %s, check its power '
|
error='Failed to power off node %s, check its power '
|
||||||
@ -516,22 +476,19 @@ class TestProcessNode(BaseTest):
|
|||||||
swift_conn.create_object.assert_called_once_with(name, mock.ANY)
|
swift_conn.create_object.assert_called_once_with(name, mock.ANY)
|
||||||
self.assertEqual(expected,
|
self.assertEqual(expected,
|
||||||
json.loads(swift_conn.create_object.call_args[0][1]))
|
json.loads(swift_conn.create_object.call_args[0][1]))
|
||||||
self.assertCalledWithPatch(self.patch_props, self.cli.node.update)
|
|
||||||
|
|
||||||
@mock.patch.object(process.swift, 'SwiftAPI', autospec=True)
|
@mock.patch.object(process.swift, 'SwiftAPI', autospec=True)
|
||||||
def test_store_data_no_logs(self, swift_mock):
|
def test_store_data_no_logs(self, swift_mock):
|
||||||
CONF.set_override('store_data', 'swift', 'processing')
|
CONF.set_override('store_data', 'swift', 'processing')
|
||||||
swift_conn = swift_mock.return_value
|
swift_conn = swift_mock.return_value
|
||||||
name = 'inspector_data-%s' % self.uuid
|
name = 'inspector_data-%s' % self.uuid
|
||||||
expected = self.data.copy()
|
|
||||||
self.data['logs'] = 'something'
|
self.data['logs'] = 'something'
|
||||||
|
|
||||||
process._process_node(self.node, self.data, self.node_info)
|
process._process_node(self.node, self.data, self.node_info)
|
||||||
|
|
||||||
swift_conn.create_object.assert_called_once_with(name, mock.ANY)
|
swift_conn.create_object.assert_called_once_with(name, mock.ANY)
|
||||||
self.assertEqual(expected,
|
self.assertNotIn('logs',
|
||||||
json.loads(swift_conn.create_object.call_args[0][1]))
|
json.loads(swift_conn.create_object.call_args[0][1]))
|
||||||
self.assertCalledWithPatch(self.patch_props, self.cli.node.update)
|
|
||||||
|
|
||||||
@mock.patch.object(process.swift, 'SwiftAPI', autospec=True)
|
@mock.patch.object(process.swift, 'SwiftAPI', autospec=True)
|
||||||
def test_store_data_location(self, swift_mock):
|
def test_store_data_location(self, swift_mock):
|
||||||
@ -540,11 +497,8 @@ class TestProcessNode(BaseTest):
|
|||||||
'processing')
|
'processing')
|
||||||
swift_conn = swift_mock.return_value
|
swift_conn = swift_mock.return_value
|
||||||
name = 'inspector_data-%s' % self.uuid
|
name = 'inspector_data-%s' % self.uuid
|
||||||
self.patch_props.append(
|
patch = [{'path': '/extra/inspector_data_object',
|
||||||
{'path': '/extra/inspector_data_object',
|
'value': name, 'op': 'add'}]
|
||||||
'value': name,
|
|
||||||
'op': 'add'}
|
|
||||||
)
|
|
||||||
expected = self.data
|
expected = self.data
|
||||||
|
|
||||||
process._process_node(self.node, self.data, self.node_info)
|
process._process_node(self.node, self.data, self.node_info)
|
||||||
@ -552,7 +506,7 @@ class TestProcessNode(BaseTest):
|
|||||||
swift_conn.create_object.assert_called_once_with(name, mock.ANY)
|
swift_conn.create_object.assert_called_once_with(name, mock.ANY)
|
||||||
self.assertEqual(expected,
|
self.assertEqual(expected,
|
||||||
json.loads(swift_conn.create_object.call_args[0][1]))
|
json.loads(swift_conn.create_object.call_args[0][1]))
|
||||||
self.assertCalledWithPatch(self.patch_props, self.cli.node.update)
|
self.cli.node.update.assert_any_call(self.uuid, patch)
|
||||||
|
|
||||||
|
|
||||||
@mock.patch.object(process, '_reapply', autospec=True)
|
@mock.patch.object(process, '_reapply', autospec=True)
|
||||||
@ -613,7 +567,6 @@ class TestReapplyNode(BaseTest):
|
|||||||
'processing')
|
'processing')
|
||||||
CONF.set_override('store_data', 'swift', 'processing')
|
CONF.set_override('store_data', 'swift', 'processing')
|
||||||
self.data['macs'] = self.macs
|
self.data['macs'] = self.macs
|
||||||
self.data['all_interfaces'] = self.data['interfaces']
|
|
||||||
self.ports = self.all_ports
|
self.ports = self.all_ports
|
||||||
self.node_info = node_cache.NodeInfo(uuid=self.uuid,
|
self.node_info = node_cache.NodeInfo(uuid=self.uuid,
|
||||||
started_at=self.started_at,
|
started_at=self.started_at,
|
||||||
@ -666,8 +619,7 @@ class TestReapplyNode(BaseTest):
|
|||||||
finished_mock.assert_called_once_with(self.node_info)
|
finished_mock.assert_called_once_with(self.node_info)
|
||||||
|
|
||||||
# asserting validate_interfaces was called
|
# asserting validate_interfaces was called
|
||||||
self.assertEqual({'em2': self.data['interfaces']['em2']},
|
self.assertEqual(self.pxe_interfaces, swifted_data['interfaces'])
|
||||||
swifted_data['interfaces'])
|
|
||||||
self.assertEqual([self.pxe_mac], swifted_data['macs'])
|
self.assertEqual([self.pxe_mac], swifted_data['macs'])
|
||||||
|
|
||||||
# assert ports were created with whatever there was left
|
# assert ports were created with whatever there was left
|
||||||
|
@ -205,3 +205,22 @@ def get_valid_macs(data):
|
|||||||
return [m['mac']
|
return [m['mac']
|
||||||
for m in data.get('all_interfaces', {}).values()
|
for m in data.get('all_interfaces', {}).values()
|
||||||
if m.get('mac')]
|
if m.get('mac')]
|
||||||
|
|
||||||
|
|
||||||
|
_INVENTORY_MANDATORY_KEYS = ('disks', 'memory', 'cpu', 'interfaces')
|
||||||
|
|
||||||
|
|
||||||
|
def get_inventory(data, node_info=None):
|
||||||
|
"""Get and validate the hardware inventory from introspection data."""
|
||||||
|
inventory = data.get('inventory')
|
||||||
|
# TODO(dtantsur): validate inventory using JSON schema
|
||||||
|
if not inventory:
|
||||||
|
raise Error(_('Hardware inventory is empty or missing'),
|
||||||
|
data=data, node_info=node_info)
|
||||||
|
|
||||||
|
for key in _INVENTORY_MANDATORY_KEYS:
|
||||||
|
if not inventory.get(key):
|
||||||
|
raise Error(_('Invalid hardware inventory: %s key is missing '
|
||||||
|
'or empty') % key, data=data, node_info=node_info)
|
||||||
|
|
||||||
|
return inventory
|
||||||
|
7
releasenotes/notes/no-old-ramdisk-095b05e1245131d8.yaml
Normal file
7
releasenotes/notes/no-old-ramdisk-095b05e1245131d8.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
prelude: >
|
||||||
|
Starting with this release only ironic-python-agent (IPA) is supported
|
||||||
|
as an introspection ramdisk.
|
||||||
|
upgrade:
|
||||||
|
- Support for the old bash-based ramdisk was removed. Please switch to IPA
|
||||||
|
before upgrading.
|
Loading…
Reference in New Issue
Block a user