summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2017-08-04 02:20:49 +0000
committerGerrit Code Review <review@openstack.org>2017-08-04 02:20:49 +0000
commitbeb14094d4aed6b7d364f7616c98dc610b4fc616 (patch)
treed4423559a0a40d01ed7a05a39c3042b442aa9dce
parent92047176ca355589ab71dd58ff93c100d89deb7c (diff)
parent3d9895cc0b6b9e41cdc5cc389d10504cd31ffa9d (diff)
downloadironic-beb14094d4aed6b7d364f7616c98dc610b4fc616.tar.gz
Merge "Remove SSH-based driver interfaces and drivers"
-rw-r--r--devstack/lib/ironic79
-rw-r--r--doc/source/admin/drivers.rst9
-rw-r--r--doc/source/admin/drivers/ilo.rst4
-rw-r--r--doc/source/admin/drivers/oneview.rst2
-rw-r--r--doc/source/admin/drivers/xenserver.rst41
-rw-r--r--doc/source/admin/inspection.rst2
-rw-r--r--doc/source/admin/report.txt7
-rw-r--r--doc/source/contributor/dev-quickstart.rst5
-rw-r--r--doc/source/contributor/ironic-multitenant-networking.rst5
-rw-r--r--doc/source/install/get_started.rst3
-rw-r--r--doc/source/install/standalone.rst2
-rw-r--r--etc/ironic/ironic.conf.sample19
-rw-r--r--ironic/common/exception.py8
-rw-r--r--ironic/common/utils.py41
-rw-r--r--ironic/conf/__init__.py2
-rw-r--r--ironic/conf/opts.py2
-rw-r--r--ironic/conf/ssh.py38
-rw-r--r--ironic/drivers/agent.py27
-rw-r--r--ironic/drivers/fake.py13
-rw-r--r--ironic/drivers/modules/ssh.py902
-rw-r--r--ironic/drivers/pxe.py27
-rw-r--r--ironic/tests/unit/api/v1/test_nodes.py4
-rw-r--r--ironic/tests/unit/conductor/test_manager.py16
-rw-r--r--ironic/tests/unit/db/utils.py28
-rw-r--r--ironic/tests/unit/drivers/modules/test_inspector.py4
-rw-r--r--ironic/tests/unit/drivers/modules/test_ssh.py1247
-rw-r--r--ironic/tests/unit/drivers/test_pxe.py11
-rw-r--r--releasenotes/notes/no-ssh-drivers-6ee5ff4c3ecdd3fb.yaml9
-rw-r--r--requirements.txt1
-rw-r--r--setup.cfg3
-rw-r--r--vagrant.yaml2
31 files changed, 25 insertions, 2538 deletions
diff --git a/devstack/lib/ironic b/devstack/lib/ironic
index a8f159190..059b27c7f 100644
--- a/devstack/lib/ironic
+++ b/devstack/lib/ironic
@@ -113,17 +113,8 @@ IRONIC_NODE_UUID=${IRONIC_NODE_UUID:-`uuidgen`}
IRONIC_SCRIPTS_DIR=${IRONIC_SCRIPTS_DIR:-$IRONIC_DEVSTACK_DIR/tools/ironic/scripts}
IRONIC_TEMPLATES_DIR=${IRONIC_TEMPLATES_DIR:-$IRONIC_DEVSTACK_DIR/tools/ironic/templates}
IRONIC_BAREMETAL_BASIC_OPS=$(trueorfalse False IRONIC_BAREMETAL_BASIC_OPS)
-IRONIC_SSH_USERNAME=${IRONIC_SSH_USERNAME:-`whoami`}
-IRONIC_SSH_TIMEOUT=${IRONIC_SSH_TIMEOUT:-15}
-IRONIC_SSH_ATTEMPTS=${IRONIC_SSH_ATTEMPTS:-5}
-IRONIC_SSH_KEY_DIR=${IRONIC_SSH_KEY_DIR:-$IRONIC_DATA_DIR/ssh_keys}
-IRONIC_SSH_KEY_FILENAME=${IRONIC_SSH_KEY_FILENAME:-ironic_key}
-IRONIC_KEY_FILE=${IRONIC_KEY_FILE:-$IRONIC_SSH_KEY_DIR/$IRONIC_SSH_KEY_FILENAME}
-IRONIC_SSH_VIRT_TYPE=${IRONIC_SSH_VIRT_TYPE:-virsh}
IRONIC_TFTPBOOT_DIR=${IRONIC_TFTPBOOT_DIR:-$IRONIC_DATA_DIR/tftpboot}
IRONIC_TFTPSERVER_IP=${IRONIC_TFTPSERVER_IP:-$HOST_IP}
-IRONIC_VM_SSH_PORT=${IRONIC_VM_SSH_PORT:-22}
-IRONIC_VM_SSH_ADDRESS=${IRONIC_VM_SSH_ADDRESS:-$HOST_IP}
IRONIC_VM_COUNT=${IRONIC_VM_COUNT:-1}
IRONIC_VM_SPECS_CPU=${IRONIC_VM_SPECS_CPU:-1}
IRONIC_VM_SPECS_RAM=${IRONIC_VM_SPECS_RAM:-1280}
@@ -137,7 +128,6 @@ IRONIC_VM_NETWORK_BRIDGE=${IRONIC_VM_NETWORK_BRIDGE:-brbm}
IRONIC_VM_NETWORK_RANGE=${IRONIC_VM_NETWORK_RANGE:-192.0.2.0/24}
IRONIC_VM_INTERFACE_COUNT=${IRONIC_VM_INTERFACE_COUNT:-2}
IRONIC_VM_MACS_CSV_FILE=${IRONIC_VM_MACS_CSV_FILE:-$IRONIC_DATA_DIR/ironic_macs.csv}
-IRONIC_AUTHORIZED_KEYS_FILE=${IRONIC_AUTHORIZED_KEYS_FILE:-$HOME/.ssh/authorized_keys}
IRONIC_CLEAN_NET_NAME=${IRONIC_CLEAN_NET_NAME:-${IRONIC_PROVISION_NETWORK_NAME:-${PRIVATE_NETWORK_NAME}}}
IRONIC_EXTRA_PXE_PARAMS=${IRONIC_EXTRA_PXE_PARAMS:-}
IRONIC_TTY_DEV=${IRONIC_TTY_DEV:-ttyS0}
@@ -263,8 +253,7 @@ if [[ "$IRONIC_DEPLOY_ISO_REQUIRED" = "True" \
or set IRONIC_BUILD_DEPLOY_RAMDISK=True to use ISOs"
fi
# Which deploy driver to use - valid choices right now
-# are ``pxe_ssh``, ``pxe_ipmitool``, ``agent_ssh``, ``agent_ipmitool``,
-# ``pxe_snmp`` and ``ipmi``.
+# are ``pxe_ipmitool``, ``agent_ipmitool``, ``pxe_snmp`` and ``ipmi``.
#
# Additional valid choices if IRONIC_IS_HARDWARE == true are:
# ``pxe_iscsi_cimc``, ``pxe_agent_cimc``, ``pxe_ucs``, ``pxe_cimc``,
@@ -1630,13 +1619,6 @@ function enroll_nodes {
-i redfish_address=http://${HOST_IP}:${IRONIC_REDFISH_EMULATOR_PORT} \
-i redfish_username=admin \
-i redfish_password=password"
- else
- local node_options="\
- -i ssh_virt_type=$IRONIC_SSH_VIRT_TYPE \
- -i ssh_address=$IRONIC_VM_SSH_ADDRESS \
- -i ssh_port=$IRONIC_VM_SSH_PORT \
- -i ssh_username=$IRONIC_SSH_USERNAME \
- -i ssh_key_filename=$IRONIC_KEY_FILE"
fi
node_options="\
$node_options \
@@ -1941,54 +1923,6 @@ function configure_tftpd {
restart_service xinetd
}
-function configure_ironic_ssh_keypair {
- if [[ ! -d $HOME/.ssh ]]; then
- mkdir -p $HOME/.ssh
- chmod 700 $HOME/.ssh
- fi
- # recreate ssh if any part is missing
- if [[ ! -e $IRONIC_KEY_FILE ]] || [[ ! -e $IRONIC_KEY_FILE.pub ]]; then
- if [[ ! -d $(dirname $IRONIC_KEY_FILE) ]]; then
- mkdir -p $(dirname $IRONIC_KEY_FILE)
- fi
- echo -e 'n\n' | ssh-keygen -q -t rsa -P '' -f $IRONIC_KEY_FILE
- fi
- # NOTE(vsaienko) check for new line character, add if doesn't exist.
- if [[ "$(tail -c1 $IRONIC_AUTHORIZED_KEYS_FILE | wc -l)" == "0" ]]; then
- echo "" >> $IRONIC_AUTHORIZED_KEYS_FILE
- fi
- cat $IRONIC_KEY_FILE.pub | tee -a $IRONIC_AUTHORIZED_KEYS_FILE
- # remove duplicate keys.
- sort -u -o $IRONIC_AUTHORIZED_KEYS_FILE $IRONIC_AUTHORIZED_KEYS_FILE
-}
-
-function ironic_ssh_check {
- local key_file=$1
- local floating_ip=$2
- local port=$3
- local default_instance_user=$4
- local attempt=$5
- local status=false
- local ssh_options="-o BatchMode=yes -o ConnectTimeout=$IRONIC_SSH_TIMEOUT -o StrictHostKeyChecking=no"
- while [[ $attempt -gt 0 ]]; do
- ssh -p $port $ssh_options -i $key_file ${default_instance_user}@$floating_ip exit
- if [[ "$?" == "0" ]]; then
- status=true
- break
- fi
- attempt=$((attempt - 1))
- echo "SSH connection failed. $attempt attempts left."
- done
- if ! $status; then
- die $LINENO "server didn't become ssh-able!"
- fi
-}
-
-function configure_ironic_auxiliary {
- configure_ironic_ssh_keypair
- ironic_ssh_check $IRONIC_KEY_FILE $IRONIC_VM_SSH_ADDRESS $IRONIC_VM_SSH_PORT $IRONIC_SSH_USERNAME $IRONIC_SSH_ATTEMPTS
-}
-
function build_ipa_ramdisk {
local kernel_path=$1
local ramdisk_path=$2
@@ -2153,10 +2087,6 @@ function prepare_baremetal_basic_ops {
return 0
fi
- if [[ "$IRONIC_IS_HARDWARE" == "False" ]]; then
- configure_ironic_auxiliary
- fi
-
if ! is_service_enabled nova && [[ "$IRONIC_IPXE_ENABLED" == "True" ]] ; then
local image_file_path
if [[ ${IRONIC_WHOLEDISK_IMAGE_NAME} =~ \.img$ ]]; then
@@ -2178,13 +2108,6 @@ function cleanup_baremetal_basic_ops {
return 0
fi
rm -f $IRONIC_VM_MACS_CSV_FILE
- if [ -f $IRONIC_KEY_FILE ]; then
- local key
- key=$(cat $IRONIC_KEY_FILE.pub)
- # remove public key from authorized_keys
- grep -v "$key" $IRONIC_AUTHORIZED_KEYS_FILE > temp && mv temp $IRONIC_AUTHORIZED_KEYS_FILE
- chmod 0600 $IRONIC_AUTHORIZED_KEYS_FILE
- fi
sudo rm -rf $IRONIC_DATA_DIR $IRONIC_STATE_PATH
local vm_name
diff --git a/doc/source/admin/drivers.rst b/doc/source/admin/drivers.rst
index eef6e503e..ac1d3a654 100644
--- a/doc/source/admin/drivers.rst
+++ b/doc/source/admin/drivers.rst
@@ -83,15 +83,6 @@ OneView driver
drivers/oneview
-XenServer ssh driver
---------------------
-
-.. toctree::
- :maxdepth: 1
-
- drivers/xenserver
-
-
Redfish driver
--------------
diff --git a/doc/source/admin/drivers/ilo.rst b/doc/source/admin/drivers/ilo.rst
index 295aa418c..7e945b684 100644
--- a/doc/source/admin/drivers/ilo.rst
+++ b/doc/source/admin/drivers/ilo.rst
@@ -177,7 +177,7 @@ Enable driver
4. Add the driver name to the list of ``enabled_drivers`` in
``/etc/ironic/ironic.conf``. For example, for `iscsi_ilo` driver::
- enabled_drivers = fake,pxe_ssh,pxe_ipmitool,iscsi_ilo
+ enabled_drivers = fake,pxe_ipmitool,iscsi_ilo
Similarly it can be added for ``agent_ilo`` and ``pxe_ilo`` drivers.
@@ -570,7 +570,7 @@ Configuring and Enabling the driver
3. Add ``pxe_ilo`` to the list of ``enabled_drivers`` in
``/etc/ironic/ironic.conf``. For example:::
- enabled_drivers = fake,pxe_ssh,pxe_ipmitool,pxe_ilo
+ enabled_drivers = fake,pxe_ipmitool,pxe_ilo
4. Restart the ironic conductor service::
diff --git a/doc/source/admin/drivers/oneview.rst b/doc/source/admin/drivers/oneview.rst
index 07e2b1e6b..3a9e0da44 100644
--- a/doc/source/admin/drivers/oneview.rst
+++ b/doc/source/admin/drivers/oneview.rst
@@ -163,7 +163,7 @@ Configuring and enabling the driver
1. Add ``agent_pxe_oneview`` to the list of ``enabled_drivers`` in your
``ironic.conf``. For example::
- enabled_drivers = fake,pxe_ssh,pxe_ipmitool,agent_pxe_oneview
+ enabled_drivers = fake,pxe_ipmitool,agent_pxe_oneview
2. Update the [oneview] section of your ``ironic.conf`` file with your
OneView credentials and CA certificate files information.
diff --git a/doc/source/admin/drivers/xenserver.rst b/doc/source/admin/drivers/xenserver.rst
deleted file mode 100644
index e866059d3..000000000
--- a/doc/source/admin/drivers/xenserver.rst
+++ /dev/null
@@ -1,41 +0,0 @@
-.. _xenserver:
-.. _bug 1498576: https://bugs.launchpad.net/diskimage-builder/+bug/1498576
-
-=================
-XenServer drivers
-=================
-
-Overview
-========
-
-XenServer drivers can be used to deploy hosts with Ironic by using XenServer
-VMs to simulate bare metal nodes.
-
-Ironic provides support via the ``pxe_ssh`` and ``agent_ssh`` drivers for
-using a XenServer VM as a bare metal target and do provisioning on it. It
-works by connecting via SSH into the XenServer host and running commands using
-the 'xe' command.
-
-This is particularly useful for deploying overclouds that use XenServer for VM
-hosting as the Compute node must be run as a virtual machine on the XenServer
-host it will be controlling. In this case, one VM per hypervisor needs to be
-installed.
-
-This support has been tested with XenServer 6.5.
-
-Usage
-=====
-
-* Install the VMs using the "Other Install Media" template, which will ensure
- that they are HVM guests
-
-* Set the HVM guests to boot from network first
-
-* If your generated initramfs does not have the fix for `bug 1498576`_,
- disable the Xen PV drivers as a work around
-
-::
-
- xe vm-param-set uuid=<uuid> xenstore-data:vm-data="vm_data/disable_pf: 1"
-
-
diff --git a/doc/source/admin/inspection.rst b/doc/source/admin/inspection.rst
index f517b3476..1611d60ae 100644
--- a/doc/source/admin/inspection.rst
+++ b/doc/source/admin/inspection.rst
@@ -85,10 +85,8 @@ Currently it is supported by the following generic drivers::
pxe_ipmitool
pxe_ipminative
- pxe_ssh
agent_ipmitool
agent_ipminative
- agent_ssh
fake_inspector
It is also the default inspection approach for the following vendor drivers::
diff --git a/doc/source/admin/report.txt b/doc/source/admin/report.txt
index 616070579..fb5aa8ad8 100644
--- a/doc/source/admin/report.txt
+++ b/doc/source/admin/report.txt
@@ -264,10 +264,8 @@ default:
iscsi
enabled_drivers =
agent_ipmitool
- agent_ssh
fake
pxe_ipmitool
- pxe_ssh
enabled_hardware_types =
ipmi
redfish
@@ -643,11 +641,6 @@ snmp:
power_timeout = 10
reboot_delay = 0
-ssh:
- get_vm_name_attempts = 3
- get_vm_name_retry_interval = 3
- libvirt_uri = qemu:///system
-
swift:
auth_section = None
auth_type = password
diff --git a/doc/source/contributor/dev-quickstart.rst b/doc/source/contributor/dev-quickstart.rst
index 14136c43a..601569a5b 100644
--- a/doc/source/contributor/dev-quickstart.rst
+++ b/doc/source/contributor/dev-quickstart.rst
@@ -481,7 +481,6 @@ and uses the ``agent_ipmitool`` driver by default::
# Create 3 virtual machines to pose as Ironic's baremetal nodes.
IRONIC_VM_COUNT=3
- IRONIC_VM_SSH_PORT=22
IRONIC_BAREMETAL_BASIC_OPS=True
DEFAULT_INSTANCE_TYPE=baremetal
@@ -612,8 +611,8 @@ It should be powered on and in a 'wait call-back' provisioning state::
| 4099e31c-576c-48f8-b460-75e1b14e497f | node-2 | a2c7f812-e386-4a22-b393-fe1802abd56e | power on | wait call-back | False |
+--------------------------------------+--------+--------------------------------------+-------------+--------------------+-------------+
-At this point, Ironic conductor has called to libvirt via SSH to power on a
-virtual machine, which will PXE + TFTP boot from the conductor node and
+At this point, Ironic conductor has called to libvirt (via virtualbmc) to
+power on a virtual machine, which will PXE + TFTP boot from the conductor node and
progress through the Ironic provisioning workflow. One libvirt domain should
be active now::
diff --git a/doc/source/contributor/ironic-multitenant-networking.rst b/doc/source/contributor/ironic-multitenant-networking.rst
index afbaa8ce8..df091c0b8 100644
--- a/doc/source/contributor/ironic-multitenant-networking.rst
+++ b/doc/source/contributor/ironic-multitenant-networking.rst
@@ -100,15 +100,14 @@ configured in Neutron.
# Create 3 virtual machines to pose as Ironic's baremetal nodes.
IRONIC_VM_COUNT=3
- IRONIC_VM_SSH_PORT=22
IRONIC_BAREMETAL_BASIC_OPS=True
# Enable Ironic drivers.
- IRONIC_ENABLED_DRIVERS=fake,agent_ssh,agent_ipmitool,pxe_ssh,pxe_ipmitool
+ IRONIC_ENABLED_DRIVERS=fake,agent_ipmitool,pxe_ipmitool
# Change this to alter the default driver for nodes created by devstack.
# This driver should be in the enabled list above.
- IRONIC_DEPLOY_DRIVER=agent_ssh
+ IRONIC_DEPLOY_DRIVER=agent_ipmitool
# The parameters below represent the minimum possible values to create
# functional nodes.
diff --git a/doc/source/install/get_started.rst b/doc/source/install/get_started.rst
index c394b297a..3ab9d7b5e 100644
--- a/doc/source/install/get_started.rst
+++ b/doc/source/install/get_started.rst
@@ -33,7 +33,8 @@ ironic-api
ironic-conductor over `remote procedure call (RPC)`_.
ironic-conductor
- Adds/edits/deletes nodes; powers on/off nodes with ipmi or ssh;
+ Adds/edits/deletes nodes; powers on/off nodes with ipmi or other
+ vendor-specific protocol;
provisions/deploys/cleans bare metal nodes.
ironic-python-agent
diff --git a/doc/source/install/standalone.rst b/doc/source/install/standalone.rst
index 16c6bbc22..7a12d159c 100644
--- a/doc/source/install/standalone.rst
+++ b/doc/source/install/standalone.rst
@@ -41,7 +41,7 @@ service via hrefs.
There are however some limitations for different drivers:
* If you're using one of the drivers that use agent deploy method (namely,
- ``agent_ilo``, ``agent_ipmitool``, or ``agent_ssh``)
+ ``agent_ilo`` or ``agent_ipmitool``)
you have to know MD5 checksum for your instance image. To
compute it, you can use the following command::
diff --git a/etc/ironic/ironic.conf.sample b/etc/ironic/ironic.conf.sample
index 1c9868f77..513ae08e2 100644
--- a/etc/ironic/ironic.conf.sample
+++ b/etc/ironic/ironic.conf.sample
@@ -3610,25 +3610,6 @@
#reboot_delay = 0
-[ssh]
-
-#
-# From ironic
-#
-
-# libvirt URI. (string value)
-#libvirt_uri = qemu:///system
-
-# Number of attempts to try to get VM name used by the host
-# that corresponds to a node's MAC address. (integer value)
-#get_vm_name_attempts = 3
-
-# Number of seconds to wait between attempts to get VM name
-# used by the host that corresponds to a node's MAC address.
-# (integer value)
-#get_vm_name_retry_interval = 3
-
-
[ssl]
#
diff --git a/ironic/common/exception.py b/ironic/common/exception.py
index 745d01b1c..f619b5b12 100644
--- a/ironic/common/exception.py
+++ b/ironic/common/exception.py
@@ -481,14 +481,6 @@ class IPMIFailure(IronicException):
_msg_fmt = _("IPMI call failed: %(cmd)s.")
-class SSHConnectFailed(IronicException):
- _msg_fmt = _("Failed to establish SSH connection to host %(host)s.")
-
-
-class SSHCommandFailed(IronicException):
- _msg_fmt = _("Failed to execute command via SSH: %(cmd)s.")
-
-
class UnsupportedDriverExtension(Invalid):
_msg_fmt = _('Driver %(driver)s does not support %(extension)s '
'(disabled or not implemented).')
diff --git a/ironic/common/utils.py b/ironic/common/utils.py
index c6085d74e..963e1d2f8 100644
--- a/ironic/common/utils.py
+++ b/ironic/common/utils.py
@@ -32,7 +32,6 @@ from oslo_concurrency import processutils
from oslo_log import log as logging
from oslo_utils import netutils
from oslo_utils import timeutils
-import paramiko
import pytz
import six
@@ -79,46 +78,6 @@ def execute(*cmd, **kwargs):
return result
-def ssh_connect(connection):
- """Method to connect to a remote system using ssh protocol.
-
- :param connection: a dict of connection parameters.
- :returns: paramiko.SSHClient -- an active ssh connection.
- :raises: SSHConnectFailed
-
- """
- try:
- ssh = paramiko.SSHClient()
- ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
- key_contents = connection.get('key_contents')
- if key_contents:
- data = six.StringIO(key_contents)
- if "BEGIN RSA PRIVATE" in key_contents:
- pkey = paramiko.RSAKey.from_private_key(data)
- elif "BEGIN DSA PRIVATE" in key_contents:
- pkey = paramiko.DSSKey.from_private_key(data)
- else:
- # Can't include the key contents - secure material.
- raise ValueError(_("Invalid private key"))
- else:
- pkey = None
- ssh.connect(connection.get('host'),
- username=connection.get('username'),
- password=connection.get('password'),
- port=connection.get('port', 22),
- pkey=pkey,
- key_filename=connection.get('key_filename'),
- timeout=connection.get('timeout', 10))
-
- # send TCP keepalive packets every 20 seconds
- ssh.get_transport().set_keepalive(20)
- except Exception as e:
- LOG.debug("SSH connect failed: %s", e)
- raise exception.SSHConnectFailed(host=connection.get('host'))
-
- return ssh
-
-
def is_valid_datapath_id(datapath_id):
"""Verify the format of an OpenFlow datapath_id.
diff --git a/ironic/conf/__init__.py b/ironic/conf/__init__.py
index d490ecb7e..d6f85efce 100644
--- a/ironic/conf/__init__.py
+++ b/ironic/conf/__init__.py
@@ -42,7 +42,6 @@ from ironic.conf import pxe
from ironic.conf import redfish
from ironic.conf import service_catalog
from ironic.conf import snmp
-from ironic.conf import ssh
from ironic.conf import swift
CONF = cfg.CONF
@@ -74,5 +73,4 @@ pxe.register_opts(CONF)
redfish.register_opts(CONF)
service_catalog.register_opts(CONF)
snmp.register_opts(CONF)
-ssh.register_opts(CONF)
swift.register_opts(CONF)
diff --git a/ironic/conf/opts.py b/ironic/conf/opts.py
index bf522c17b..b8e2c9d03 100644
--- a/ironic/conf/opts.py
+++ b/ironic/conf/opts.py
@@ -59,7 +59,6 @@ _opts = [
('pxe', ironic.conf.pxe.opts),
('service_catalog', ironic.conf.service_catalog.list_opts()),
('snmp', ironic.conf.snmp.opts),
- ('ssh', ironic.conf.ssh.opts),
('swift', ironic.conf.swift.list_opts()),
]
@@ -96,7 +95,6 @@ def update_opt_defaults():
'stevedore=INFO',
'eventlet.wsgi.server=INFO',
'iso8601=WARNING',
- 'paramiko=WARNING',
'requests=WARNING',
'neutronclient=WARNING',
'glanceclient=WARNING',
diff --git a/ironic/conf/ssh.py b/ironic/conf/ssh.py
deleted file mode 100644
index 4ae4aabc1..000000000
--- a/ironic/conf/ssh.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright 2016 Intel Corporation
-# Copyright 2013 Hewlett-Packard Development Company, L.P.
-# 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 oslo_config import cfg
-
-from ironic.common.i18n import _
-
-opts = [
- cfg.StrOpt('libvirt_uri',
- default='qemu:///system',
- help=_('libvirt URI.')),
- cfg.IntOpt('get_vm_name_attempts',
- default=3,
- help=_("Number of attempts to try to get VM name used by the "
- "host that corresponds to a node's MAC address.")),
- cfg.IntOpt('get_vm_name_retry_interval',
- default=3,
- help=_("Number of seconds to wait between attempts to get "
- "VM name used by the host that corresponds to a "
- "node's MAC address.")),
-]
-
-
-def register_opts(conf):
- conf.register_opts(opts, group='ssh')
diff --git a/ironic/drivers/agent.py b/ironic/drivers/agent.py
index 6a3472356..75502fd5d 100644
--- a/ironic/drivers/agent.py
+++ b/ironic/drivers/agent.py
@@ -23,7 +23,6 @@ from ironic.drivers.modules.cimc import management as cimc_mgmt
from ironic.drivers.modules.cimc import power as cimc_power
from ironic.drivers.modules import inspector
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
@@ -33,32 +32,6 @@ AgentAndIPMIToolDriver = ipmi.AgentAndIPMIToolDriver
AgentAndIPMIToolAndSocatDriver = ipmi.AgentAndIPMIToolAndSocatDriver
-class AgentAndSSHDriver(base.BaseDriver):
- """Agent + SSH driver.
-
- NOTE: This driver is meant only for testing environments.
-
- This driver implements the `core` functionality, combining
- :class:`ironic.drivers.modules.ssh.SSH` (for power on/off and reboot of
- virtual machines tunneled over SSH), 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):
- self.power = ssh.SSHPower()
- self.boot = pxe.PXEBoot()
- self.deploy = agent.AgentDeploy()
- self.management = ssh.SSHManagement()
- self.raid = agent.AgentRAID()
- self.inspect = inspector.Inspector.create_if_enabled(
- 'AgentAndSSHDriver')
- self.console = ssh.ShellinaboxConsole()
-
-
class AgentAndUcsDriver(base.BaseDriver):
"""Agent + Cisco UCSM driver.
diff --git a/ironic/drivers/fake.py b/ironic/drivers/fake.py
index 441ed4a16..d43f83def 100644
--- a/ironic/drivers/fake.py
+++ b/ironic/drivers/fake.py
@@ -46,7 +46,6 @@ 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 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 import utils
@@ -112,18 +111,6 @@ class FakePXEDriver(base.BaseDriver):
self.deploy = iscsi_deploy.ISCSIDeploy()
-class FakeSSHDriver(base.BaseDriver):
- """Example implementation of a Driver."""
-
- supported = False
-
- def __init__(self):
- self.power = ssh.SSHPower()
- self.deploy = fake.FakeDeploy()
- self.management = ssh.SSHManagement()
- self.console = ssh.ShellinaboxConsole()
-
-
class FakeAgentDriver(base.BaseDriver):
"""Example implementation of an AgentDriver."""
diff --git a/ironic/drivers/modules/ssh.py b/ironic/drivers/modules/ssh.py
deleted file mode 100644
index 5b4aa0627..000000000
--- a/ironic/drivers/modules/ssh.py
+++ /dev/null
@@ -1,902 +0,0 @@
-# Copyright 2013 Hewlett-Packard Development Company, L.P.
-# 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.
-
-"""
-Ironic SSH power manager.
-
-Provides basic power control of virtual machines via SSH.
-
-For use in dev and test environments.
-
-Currently supported environments are:
- Virtual Box (vbox)
- Virsh (virsh)
- VMware (vmware)
- Parallels (parallels)
- XenServer (xenserver)
-"""
-
-import os
-
-from oslo_concurrency import processutils
-from oslo_log import log as logging
-from oslo_utils import excutils
-from oslo_utils import strutils
-
-import retrying
-
-from ironic.common import boot_devices
-from ironic.common import exception
-from ironic.common.i18n import _
-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
-from ironic.drivers import utils as driver_utils
-
-LOG = logging.getLogger(__name__)
-
-REQUIRED_PROPERTIES = {
- 'ssh_address': _("IP address or hostname of the node to ssh into. "
- "Required."),
- 'ssh_username': _("username to authenticate as. Required."),
- 'ssh_virt_type': _("virtualization software to use; one of vbox, virsh, "
- "vmware, parallels, xenserver. Required.")
-}
-OTHER_PROPERTIES = {
- 'ssh_key_contents': _("private key(s). If ssh_password is also specified "
- "it will be used for unlocking the private key. Do "
- "not specify ssh_key_filename when this property is "
- "specified."),
- 'ssh_key_filename': _("(list of) filename(s) of optional private key(s) "
- "for authentication. If ssh_password is also "
- "specified it will be used for unlocking the "
- "private key. Do not specify ssh_key_contents when "
- "this property is specified."),
- 'ssh_password': _("password to use for authentication or for unlocking a "
- "private key. At least one of this, ssh_key_contents, "
- "or ssh_key_filename must be specified."),
- 'ssh_port': _("port on the node to connect to; default is 22. Optional."),
- 'vbox_use_headless': _("True or False (Default). Optional. "
- "In the case of VirtualBox 3.2 and above, allows "
- "the user to use a headless remote VirtualBox "
- "machine.")
-}
-COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy()
-COMMON_PROPERTIES.update(OTHER_PROPERTIES)
-CONSOLE_PROPERTIES = {
- 'ssh_terminal_port': _("node's UDP port to connect to. Only required for "
- "console access and only applicable for 'virsh'.")
-}
-
-# NOTE(dguerri) Generic boot device map. Virtualisation types that don't define
-# a more specific one, will use this.
-# This is left for compatibility with other modules and is still valid for
-# virsh and vmware.
-_BOOT_DEVICES_MAP = {
- boot_devices.DISK: 'hd',
- boot_devices.PXE: 'network',
- boot_devices.CDROM: 'cdrom',
-}
-
-
-def _get_boot_device_map(virt_type):
- if virt_type in ('virsh', 'vmware'):
- return _BOOT_DEVICES_MAP
- elif virt_type == 'vbox':
- return {
- boot_devices.DISK: 'disk',
- boot_devices.PXE: 'net',
- boot_devices.CDROM: 'dvd',
- }
- elif virt_type == 'xenserver':
- return {
- boot_devices.DISK: 'c',
- boot_devices.PXE: 'n',
- boot_devices.CDROM: 'd',
- }
- elif virt_type == 'parallels':
- return {
- boot_devices.DISK: 'hdd0',
- boot_devices.PXE: 'net0',
- boot_devices.CDROM: 'cdrom0',
- }
- else:
- raise exception.InvalidParameterValue(_(
- "SSHPowerDriver '%(virt_type)s' is not a valid virt_type.") %
- {'virt_type': virt_type})
-
-
-def _get_command_sets(virt_type, use_headless=False):
- """Retrieves the virt_type-specific commands to control power
-
- :param virt_type: Hypervisor type (virsh, vmware, vbox, parallels,
- xenserver)
- :param use_headless: boolean value, defaults to False.
- use_headless is used by some Hypervisors (only VBox v3.2 and above)
- to determine if the hypervisor is being used on a headless box.
- This is only relevant to Desktop Hypervisors that have different
- CLI settings depending upon the availability of a graphical
- environment working on the hypervisor itself. Again, only VBox
- makes this distinction and allows "--type headless" to some of
- its sub-commands. This is needed for support of tripleo with
- VBox as the Hypervisor but some other Hypervisors could make
- use of it in the future (Parallels, VMWare Workstation, etc...)
-
- Required commands are as follows:
-
- base_cmd: Used by most sub-commands as the primary executable
- list_all: Lists all VMs (by virt_type identifier) that can be managed.
- One name per line, must not be quoted.
- list_running: Lists all running VMs (by virt_type identifier).
- One name per line, can be quoted.
- start_cmd / stop_cmd: Starts or stops the identified VM
- get_node_macs: Retrieves all MACs for an identified VM.
- One MAC per line, any standard format (see driver_utils.normalize_mac)
- get_boot_device / set_boot_device: Gets or sets the primary boot device
- """
- if virt_type == 'vbox':
- vbox_headless_str = ''
- if use_headless:
- vbox_headless_str = ' --type headless'
- return {
- 'base_cmd': 'LC_ALL=C /usr/bin/VBoxManage',
- 'start_cmd': 'startvm {_NodeName_}%s' % vbox_headless_str,
- 'stop_cmd': 'controlvm {_NodeName_} poweroff',
- 'reboot_cmd': 'controlvm {_NodeName_} reset',
- 'list_all': "list vms|awk -F'\"' '{print $2}'",
- 'list_running': 'list runningvms',
- 'get_node_macs': (
- "showvminfo --machinereadable {_NodeName_} | "
- "awk -F '\"' '/macaddress/{print $2}'"),
- 'set_boot_device': (
- '{_BaseCmd_} modifyvm {_NodeName_} '
- '--boot1 {_BootDevice_}'),
- 'get_boot_device': (
- "{_BaseCmd_} showvminfo "
- "--machinereadable {_NodeName_} | "
- "awk -F '\"' '/boot1/{print $2}'"),
- }
- elif virt_type == 'vmware':
- return {
- 'base_cmd': 'LC_ALL=C /bin/vim-cmd',
- 'start_cmd': 'vmsvc/power.on {_NodeName_}',
- 'stop_cmd': 'vmsvc/power.off {_NodeName_}',
- 'reboot_cmd': 'vmsvc/power.reboot {_NodeName_}',
- 'list_all': "vmsvc/getallvms | awk '$1 ~ /^[0-9]+$/ {print $1}'",
- # NOTE(arata): In spite of its name, list_running_cmd shows a
- # single vmid, not a list. But it is OK.
- 'list_running': (
- "vmsvc/power.getstate {_NodeName_} | "
- "grep 'Powered on' >/dev/null && "
- "echo '\"{_NodeName_}\"' || true"),
- # NOTE(arata): `true` is needed to handle a false vmid, which can
- # be returned by list_cmd. In that case, get_node_macs
- # returns an empty list rather than fails with
- # non-zero status code.
- 'get_node_macs': (
- "vmsvc/device.getdevices {_NodeName_} | "
- "grep macAddress | awk -F '\"' '{print $2}' || true"),
- }
- elif virt_type == "virsh":
- # NOTE(NobodyCam): changes to the virsh commands will impact CI
- # see https://review.openstack.org/83906
- # Change-Id: I160e4202952b7551b855dc7d91784d6a184cb0ed
- # for more detail.
- virsh_cmds = {
- 'base_cmd': 'LC_ALL=C /usr/bin/virsh',
- 'start_cmd': 'start {_NodeName_}',
- 'stop_cmd': 'destroy {_NodeName_}',
- 'reboot_cmd': 'reset {_NodeName_}',
- 'list_all': 'list --all --name',
- 'list_running': 'list --name',
- 'get_node_macs': (
- "dumpxml {_NodeName_} | "
- "awk -F \"'\" '/mac address/{print $2}'| tr -d ':'"),
- 'set_boot_device': (
- "EDITOR=\"sed -i '/<boot \(dev\|order\)=*\>/d;"
- "/<\/os>/i\<boot dev=\\\"{_BootDevice_}\\\"/>'\" "
- "{_BaseCmd_} edit {_NodeName_}"),
- 'get_boot_device': (
- "{_BaseCmd_} dumpxml {_NodeName_} | "
- "awk '/boot dev=/ { gsub( \".*dev=\" Q, \"\" ); "
- "gsub( Q \".*\", \"\" ); print; }' "
- "Q=\"'\" RS=\"[<>]\" | "
- "head -1"),
- }
-
- if CONF.ssh.libvirt_uri:
- virsh_cmds['base_cmd'] += ' --connect %s' % CONF.ssh.libvirt_uri
-
- return virsh_cmds
- elif virt_type == 'parallels':
- return {
- 'base_cmd': 'LC_ALL=C /usr/bin/prlctl',
- 'start_cmd': 'start {_NodeName_}',
- 'stop_cmd': 'stop {_NodeName_} --kill',
- 'reboot_cmd': 'reset {_NodeName_}',
- 'list_all': "list -a -o name |tail -n +2",
- 'list_running': 'list -o name |tail -n +2',
- 'get_node_macs': (
- "list -j -i \"{_NodeName_}\" | "
- "awk -F'\"' '/\"mac\":/ {print $4}' | "
- "sed 's/\\(..\\)\\(..\\)\\(..\\)\\(..\\)\\(..\\)\\(..\\)/"
- "\\1:\\2:\\3:\\4:\\5\\6/' | "
- "tr '[:upper:]' '[:lower:]'"),
- 'set_boot_device': (
- "{_BaseCmd_} set {_NodeName_} "
- "--device-bootorder \"{_BootDevice_}\""),
- 'get_boot_device': (
- "{_BaseCmd_} list -i {_NodeName_} | "
- "awk '/^Boot order:/ {print $3}'"),
- }
- elif virt_type == 'xenserver':
- return {
- 'base_cmd': 'LC_ALL=C /opt/xensource/bin/xe',
- # Note(bobba): XenServer appears to have a condition where
- # vm-start can return before the power-state
- # has been updated to 'running'. Ironic
- # expects the power-state to be updated
- # immediately, so may find that power-state
- # is still 'halted' and attempt to start the
- # VM a second time. Sleep to avoid the race.
- 'start_cmd': 'vm-start uuid={_NodeName_} && sleep 10s',
- 'stop_cmd': 'vm-shutdown uuid={_NodeName_} force=true',
- 'list_all': "vm-list --minimal | tr ',' '\n'",
- 'list_running': (
- "vm-list power-state=running --minimal |"
- " tr ',' '\n'"),
- 'get_node_macs': (
- "vif-list vm-uuid={_NodeName_}"
- " params=MAC --minimal | tr ',' '\n'"),
- 'set_boot_device': (
- "{_BaseCmd_} vm-param-set uuid={_NodeName_}"
- " HVM-boot-params:order='{_BootDevice_}'"),
- 'get_boot_device': (
- "{_BaseCmd_} vm-param-get uuid={_NodeName_}"
- " --param-name=HVM-boot-params param-key=order | cut -b 1"),
- }
- else:
- raise exception.InvalidParameterValue(_(
- "SSHPowerDriver '%(virt_type)s' is not a valid virt_type, ") %
- {'virt_type': virt_type})
-
-
-def _get_boot_device(ssh_obj, driver_info):
- """Get the current boot device.
-
- :param ssh_obj: paramiko.SSHClient, an active ssh connection.
- :param driver_info: information for accessing the node.
- :raises: SSHCommandFailed on an error from ssh.
- :raises: NotImplementedError if the virt_type does not support
- getting the boot device.
- :raises: NodeNotFound if could not find a VM corresponding to any
- of the provided MACs.
-
- """
- cmd_to_exec = driver_info['cmd_set'].get('get_boot_device')
- if cmd_to_exec:
- boot_device_map = _get_boot_device_map(driver_info['virt_type'])
- node_name = _get_hosts_name_for_node(ssh_obj, driver_info)
- base_cmd = driver_info['cmd_set']['base_cmd']
- cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', node_name)
- cmd_to_exec = cmd_to_exec.replace('{_BaseCmd_}', base_cmd)
- stdout, stderr = _ssh_execute(ssh_obj, cmd_to_exec)
- return next((dev for dev, hdev in boot_device_map.items()
- if hdev == stdout), None)
- else:
- raise NotImplementedError()
-
-
-def _set_boot_device(ssh_obj, driver_info, device):
- """Set the boot device.
-
- :param ssh_obj: paramiko.SSHClient, an active ssh connection.
- :param driver_info: information for accessing the node.
- :param device: the boot device.
- :raises: SSHCommandFailed on an error from ssh.
- :raises: NotImplementedError if the virt_type does not support
- setting the boot device.
- :raises: NodeNotFound if could not find a VM corresponding to any
- of the provided MACs.
-
- """
- cmd_to_exec = driver_info['cmd_set'].get('set_boot_device')
- if cmd_to_exec:
- node_name = _get_hosts_name_for_node(ssh_obj, driver_info)
- base_cmd = driver_info['cmd_set']['base_cmd']
- cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', node_name)
- cmd_to_exec = cmd_to_exec.replace('{_BootDevice_}', device)
- cmd_to_exec = cmd_to_exec.replace('{_BaseCmd_}', base_cmd)
- _ssh_execute(ssh_obj, cmd_to_exec)
- else:
- raise NotImplementedError()
-
-
-def _ssh_execute(ssh_obj, cmd_to_exec):
- """Executes a command via ssh.
-
- Executes a command via ssh and returns a list of the lines of the
- output from the command.
-
- :param ssh_obj: paramiko.SSHClient, an active ssh connection.
- :param cmd_to_exec: command to execute.
- :returns: list of the lines of output from the command.
- :raises: SSHCommandFailed on an error from ssh.
-
- """
- try:
- output_list = processutils.ssh_execute(ssh_obj,
- cmd_to_exec)[0].split('\n')
- except Exception as e:
- LOG.error("Cannot execute SSH cmd %(cmd)s. Reason: %(err)s.",
- {'cmd': cmd_to_exec, 'err': e})
- raise exception.SSHCommandFailed(cmd=cmd_to_exec)
-
- return output_list
-
-
-def _parse_driver_info(node):
- """Gets the information needed for accessing the node.
-
- :param node: the Node of interest.
- :returns: dictionary of information.
- :raises: InvalidParameterValue if any required parameters are incorrect.
- :raises: MissingParameterValue if any required parameters are missing.
-
- """
- info = node.driver_info or {}
- missing_info = [key for key in REQUIRED_PROPERTIES if not info.get(key)]
- if missing_info:
- raise exception.MissingParameterValue(_(
- "SSHPowerDriver requires the following parameters to be set in "
- "node's driver_info: %s.") % missing_info)
-
- address = info.get('ssh_address')
- username = info.get('ssh_username')
- password = info.get('ssh_password')
- port = info.get('ssh_port', 22)
- port = utils.validate_network_port(port, 'ssh_port')
- key_contents = info.get('ssh_key_contents')
- key_filename = info.get('ssh_key_filename')
- use_headless = strutils.bool_from_string(info.get('vbox_use_headless',
- False))
- virt_type = info.get('ssh_virt_type')
- terminal_port = info.get('ssh_terminal_port')
-
- if terminal_port is not None:
- terminal_port = utils.validate_network_port(terminal_port,
- 'ssh_terminal_port')
-
- # NOTE(deva): we map 'address' from API to 'host' for common utils
- res = {
- 'host': address,
- 'username': username,
- 'port': port,
- 'use_headless': use_headless,
- 'virt_type': virt_type,
- 'uuid': node.uuid,
- 'terminal_port': terminal_port
- }
-
- cmd_set = _get_command_sets(virt_type, use_headless)
- res['cmd_set'] = cmd_set
-
- # Set at least one credential method.
- if len([v for v in (password, key_filename, key_contents) if v]) == 0:
- raise exception.InvalidParameterValue(_(
- "SSHPowerDriver requires at least one of ssh_password, "
- "ssh_key_contents and ssh_key_filename to be set."))
-
- # Set only credential file or content but not both
- if key_filename and key_contents:
- raise exception.InvalidParameterValue(_(
- "SSHPowerDriver requires one and only one of "
- "ssh_key_contents and ssh_key_filename to be set."))
-
- if password:
- res['password'] = password
-
- if key_contents:
- res['key_contents'] = key_contents
-
- if key_filename:
- if not os.path.isfile(key_filename):
- raise exception.InvalidParameterValue(_(
- "SSH key file %s not found.") % key_filename)
- res['key_filename'] = key_filename
-
- return res
-
-
-def _get_power_status(ssh_obj, driver_info):
- """Returns a node's current power state.
-
- :param ssh_obj: paramiko.SSHClient, an active ssh connection.
- :param driver_info: information for accessing the node.
- :returns: one of ironic.common.states POWER_OFF, POWER_ON.
- :raises: NodeNotFound if could not find a VM corresponding to any
- of the provided MACs.
-
- """
- power_state = None
- node_name = _get_hosts_name_for_node(ssh_obj, driver_info)
- # Get a list of vms running on the host. If the command supports
- # it, explicitly specify the desired node."
- cmd_to_exec = "%s %s" % (driver_info['cmd_set']['base_cmd'],
- driver_info['cmd_set']['list_running'])
- cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', node_name)
- running_list = _ssh_execute(ssh_obj, cmd_to_exec)
-
- # Command should return a list of running vms. If the current node is
- # not listed then we can assume it is not powered on.
- quoted_node_name = '"%s"' % node_name
- for node in running_list:
- if not node:
- continue
- # 'node' here is a formatted output from the virt cli's. The
- # node name is either an exact match or quoted (optionally with
- # other information, e.g. vbox returns '"NodeName" {<uuid>}')
- if (quoted_node_name in node) or (node_name == node):
- power_state = states.POWER_ON
- break
- if not power_state:
- power_state = states.POWER_OFF
-
- return power_state
-
-
-def _get_connection(node):
- """Returns an SSH client connected to a node.
-
- :param node: the Node.
- :returns: paramiko.SSHClient, an active ssh connection.
-
- """
- return utils.ssh_connect(_parse_driver_info(node))
-
-
-def _get_hosts_name_for_node(ssh_obj, driver_info):
- """Get the name the host uses to reference the node.
-
- :param ssh_obj: paramiko.SSHClient, an active ssh connection.
- :param driver_info: information for accessing the node.
- :returns: the name of the node.
- :raises: NodeNotFound if could not find a VM corresponding to any of
- the provided MACs
-
- """
-
- @retrying.retry(
- retry_on_result=lambda v: v is None,
- retry_on_exception=lambda _: False, # Do not retry on SSHCommandFailed
- stop_max_attempt_number=CONF.ssh.get_vm_name_attempts,
- wait_fixed=CONF.ssh.get_vm_name_retry_interval * 1000)
- def _with_retries():
- matched_name = None
- cmd_to_exec = "%s %s" % (driver_info['cmd_set']['base_cmd'],
- driver_info['cmd_set']['list_all'])
- full_node_list = _ssh_execute(ssh_obj, cmd_to_exec)
- LOG.debug("Retrieved Node List: %s", repr(full_node_list))
- # for each node check Mac Addresses
- for node in full_node_list:
- if not node:
- continue
- LOG.debug("Checking Node: %s's Mac address.", node)
- cmd_to_exec = "%s %s" % (driver_info['cmd_set']['base_cmd'],
- driver_info['cmd_set']['get_node_macs'])
- cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', node)
- hosts_node_mac_list = _ssh_execute(ssh_obj, cmd_to_exec)
-
- for host_mac in hosts_node_mac_list:
- if not host_mac:
- continue
- for node_mac in driver_info['macs']:
- if (driver_utils.normalize_mac(host_mac)
- in driver_utils.normalize_mac(node_mac)):
- LOG.debug("Found Mac address: %s", node_mac)
- matched_name = node
- break
-
- if matched_name:
- break
- if matched_name:
- break
-
- return matched_name
-
- try:
- return _with_retries()
- except retrying.RetryError:
- raise exception.NodeNotFound(
- _("SSH driver was not able to find a VM with any of the "
- "specified MACs: %(macs)s for node %(node)s.") %
- {'macs': driver_info['macs'], 'node': driver_info['uuid']})
-
-
-def _power_on(ssh_obj, driver_info):
- """Power ON this node.
-
- :param ssh_obj: paramiko.SSHClient, an active ssh connection.
- :param driver_info: information for accessing the node.
- :returns: one of ironic.common.states POWER_ON or ERROR.
-
- """
- current_pstate = _get_power_status(ssh_obj, driver_info)
- if current_pstate == states.POWER_ON:
- _power_off(ssh_obj, driver_info)
-
- node_name = _get_hosts_name_for_node(ssh_obj, driver_info)
- cmd_to_power_on = "%s %s" % (driver_info['cmd_set']['base_cmd'],
- driver_info['cmd_set']['start_cmd'])
- cmd_to_power_on = cmd_to_power_on.replace('{_NodeName_}', node_name)
-
- _ssh_execute(ssh_obj, cmd_to_power_on)
-
- current_pstate = _get_power_status(ssh_obj, driver_info)
- if current_pstate == states.POWER_ON:
- return current_pstate
- else:
- return states.ERROR
-
-
-def _power_off(ssh_obj, driver_info):
- """Power OFF this node.
-
- :param ssh_obj: paramiko.SSHClient, an active ssh connection.
- :param driver_info: information for accessing the node.
- :returns: one of ironic.common.states POWER_OFF or ERROR.
-
- """
- current_pstate = _get_power_status(ssh_obj, driver_info)
- if current_pstate == states.POWER_OFF:
- return current_pstate
-
- node_name = _get_hosts_name_for_node(ssh_obj, driver_info)
- cmd_to_power_off = "%s %s" % (driver_info['cmd_set']['base_cmd'],
- driver_info['cmd_set']['stop_cmd'])
- cmd_to_power_off = cmd_to_power_off.replace('{_NodeName_}', node_name)
-
- _ssh_execute(ssh_obj, cmd_to_power_off)
-
- current_pstate = _get_power_status(ssh_obj, driver_info)
- if current_pstate == states.POWER_OFF:
- return current_pstate
- else:
- return states.ERROR
-
-
-class SSHPower(base.PowerInterface):
- """SSH Power Interface.
-
- This PowerInterface class provides a mechanism for controlling the power
- state of virtual machines via SSH.
-
- NOTE: This driver supports VirtualBox and Virsh commands.
- NOTE: This driver does not currently support multi-node operations.
- """
-
- def get_properties(self):
- return COMMON_PROPERTIES
-
- def validate(self, task):
- """Check that the node's 'driver_info' is valid.
-
- Check that the node's 'driver_info' contains the requisite fields
- and that an SSH connection to the node can be established.
-
- :param task: a TaskManager instance containing the node to act on.
- :raises: InvalidParameterValue if any connection parameters are
- incorrect or if ssh failed to connect to the node.
- :raises: MissingParameterValue if no ports are enrolled for the given
- node.
- """
- if not driver_utils.get_node_mac_addresses(task):
- raise exception.MissingParameterValue(
- _("Node %s does not have any port associated with it."
- ) % task.node.uuid)
- try:
- _get_connection(task.node)
- except exception.SSHConnectFailed as e:
- raise exception.InvalidParameterValue(_("SSH connection cannot"
- " be established: %s") % e)
-
- 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 task's node.
-
- :param task: a TaskManager instance containing the node to act on.
- :returns: power state. One of :class:`ironic.common.states`.
- :raises: InvalidParameterValue if any connection parameters are
- incorrect.
- :raises: MissingParameterValue when a required parameter is missing
- :raises: NodeNotFound if could not find a VM corresponding to any
- of the provided MACs.
- :raises: SSHCommandFailed on an error from ssh.
- :raises: SSHConnectFailed if ssh failed to connect to the node.
- """
- driver_info = _parse_driver_info(task.node)
- driver_info['macs'] = driver_utils.get_node_mac_addresses(task)
- ssh_obj = _get_connection(task.node)
- return _get_power_status(ssh_obj, driver_info)
-
- @task_manager.require_exclusive_lock
- def set_power_state(self, task, pstate):
- """Turn the power on or off.
-
- Set the power state of the task's 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 any connection parameters are
- incorrect, or if the desired power state is invalid.
- :raises: MissingParameterValue when a required parameter is missing
- :raises: NodeNotFound if could not find a VM corresponding to any
- of the provided MACs.
- :raises: PowerStateFailure if it failed to set power state to pstate.
- :raises: SSHCommandFailed on an error from ssh.
- :raises: SSHConnectFailed if ssh failed to connect to the node.
- """
- driver_info = _parse_driver_info(task.node)
- driver_info['macs'] = driver_utils.get_node_mac_addresses(task)
- ssh_obj = _get_connection(task.node)
-
- if pstate == states.POWER_ON:
- state = _power_on(ssh_obj, driver_info)
- elif pstate == states.POWER_OFF:
- state = _power_off(ssh_obj, driver_info)
- else:
- raise exception.InvalidParameterValue(
- _("set_power_state called with invalid power state %s."
- ) % pstate)
-
- 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.
-
- Power cycles a node.
-
- :param task: a TaskManager instance containing the node to act on.
- :raises: InvalidParameterValue if any connection parameters are
- incorrect.
- :raises: MissingParameterValue when a required parameter is missing
- :raises: NodeNotFound if could not find a VM corresponding to any
- of the provided MACs.
- :raises: PowerStateFailure if it failed to set power state to POWER_ON.
- :raises: SSHCommandFailed on an error from ssh.
- :raises: SSHConnectFailed if ssh failed to connect to the node.
- """
- driver_info = _parse_driver_info(task.node)
- driver_info['macs'] = driver_utils.get_node_mac_addresses(task)
- ssh_obj = _get_connection(task.node)
-
- # _power_on will turn the power off if it's already on.
- state = _power_on(ssh_obj, driver_info)
-
- if state != states.POWER_ON:
- raise exception.PowerStateFailure(pstate=states.POWER_ON)
-
-
-class SSHManagement(base.ManagementInterface):
-
- def get_properties(self):
- return COMMON_PROPERTIES
-
- def validate(self, task):
- """Check that 'driver_info' contains SSH 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: InvalidParameterValue if any connection parameters are
- incorrect.
- :raises: MissingParameterValue if 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 any connection parameters are incorrect.
- :raises: MissingParameterValue if a required parameter is missing
- :raises: SSHConnectFailed if ssh failed to connect to the node.
- :raises: SSHCommandFailed on an error from ssh.
- :raises: NotImplementedError if the virt_type does not support
- setting the boot device.
- :raises: NodeNotFound if could not find a VM corresponding to any
- of the provided MACs.
-
- """
- node = task.node
- driver_info = _parse_driver_info(node)
- if device not in self.get_supported_boot_devices(task):
- raise exception.InvalidParameterValue(_(
- "Invalid boot device %s specified.") % device)
- driver_info['macs'] = driver_utils.get_node_mac_addresses(task)
- ssh_obj = _get_connection(node)
-
- node_name = _get_hosts_name_for_node(ssh_obj, driver_info)
- virt_type = driver_info['virt_type']
- use_headless = driver_info['use_headless']
-
- if virt_type == 'vbox':
- if use_headless:
- current_pstate = _get_power_status(ssh_obj, driver_info)
- if current_pstate == states.POWER_ON:
- LOG.debug("Forcing VBox VM %s to power off "
- "in order to set the boot device.",
- node_name)
- _power_off(ssh_obj, driver_info)
-
- boot_device_map = _get_boot_device_map(driver_info['virt_type'])
- try:
- _set_boot_device(ssh_obj, driver_info, boot_device_map[device])
- except NotImplementedError:
- with excutils.save_and_reraise_exception():
- LOG.error("Failed to set boot device for node %(node)s, "
- "virt_type %(vtype)s does not support this "
- "operation", {'node': node.uuid,
- 'vtype': driver_info['virt_type']})
-
- def get_boot_device(self, task):
- """Get the current boot device for the task's node.
-
- Provides the current boot device of the node. Be aware that not
- all drivers support this.
-
- :param task: a task from TaskManager.
- :raises: InvalidParameterValue if any connection parameters are
- incorrect.
- :raises: MissingParameterValue if a required parameter is missing
- :raises: SSHConnectFailed if ssh failed to connect to the node.
- :raises: SSHCommandFailed on an error from ssh.
- :raises: NodeNotFound if could not find a VM corresponding to any
- of the provided MACs.
- :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.
-
- """
- node = task.node
- driver_info = _parse_driver_info(node)
- driver_info['macs'] = driver_utils.get_node_mac_addresses(task)
- ssh_obj = _get_connection(node)
- response = {'boot_device': None, 'persistent': None}
- try:
- response['boot_device'] = _get_boot_device(ssh_obj, driver_info)
- except NotImplementedError:
- LOG.warning("Failed to get boot device for node %(node)s, "
- "virt_type %(vtype)s does not support this "
- "operation",
- {'node': node.uuid, 'vtype': driver_info['virt_type']})
- return response
-
- def get_sensors_data(self, task):
- """Get sensors data.
-
- Not implemented by this driver.
-
- :param task: a TaskManager instance.
-
- """
- raise NotImplementedError()
-
-
-class ShellinaboxConsole(base.ConsoleInterface):
- """A ConsoleInterface that uses ssh and shellinabox."""
-
- def get_properties(self):
- properties = COMMON_PROPERTIES.copy()
- properties.update(CONSOLE_PROPERTIES)
- return properties
-
- def validate(self, task):
- """Validate the Node console info.
-
- :param task: a task from TaskManager.
- :raises: MissingParameterValue if required ssh parameters are
- missing
- :raises: InvalidParameterValue if required parameters are invalid.
- """
- driver_info = _parse_driver_info(task.node)
-
- if driver_info['virt_type'] != 'virsh':
- raise exception.InvalidParameterValue(_(
- "not supported for non-virsh types"))
-
- if not driver_info['terminal_port']:
- raise exception.MissingParameterValue(_(
- "Missing 'ssh_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 ssh 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 parameters are invalid.
- """
-
- driver_info = _parse_driver_info(task.node)
- driver_info['macs'] = driver_utils.get_node_mac_addresses(task)
- ssh_obj = _get_connection(task.node)
- node_name = _get_hosts_name_for_node(ssh_obj, driver_info)
-
- ssh_cmd = ("/:%(uid)s:%(gid)s:HOME:virsh console %(node)s"
- % {'uid': os.getuid(),
- 'gid': os.getgid(),
- 'node': node_name})
-
- console_utils.start_shellinabox_console(driver_info['uuid'],
- driver_info['terminal_port'],
- ssh_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.
-
- :param task: a task from TaskManager
- :raises: MissingParameterValue if required ssh 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['terminal_port'])
- return {'type': 'shellinabox', 'url': url}
diff --git a/ironic/drivers/pxe.py b/ironic/drivers/pxe.py
index f21db501e..3fff137e4 100644
--- a/ironic/drivers/pxe.py
+++ b/ironic/drivers/pxe.py
@@ -41,7 +41,6 @@ from ironic.drivers.modules.irmc import power as irmc_power
from ironic.drivers.modules import iscsi_deploy
from ironic.drivers.modules import pxe
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
@@ -51,32 +50,6 @@ PXEAndIPMIToolDriver = ipmi.PXEAndIPMIToolDriver
PXEAndIPMIToolAndSocatDriver = ipmi.PXEAndIPMIToolAndSocatDriver
-class PXEAndSSHDriver(base.BaseDriver):
- """PXE + SSH driver.
-
- NOTE: This driver is meant only for testing environments.
-
- This driver implements the `core` functionality, combining
- :class:`ironic.drivers.modules.ssh.SSH` for power on/off and
- reboot of virtual machines tunneled over SSH, 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 = ssh.SSHPower()
- self.boot = pxe.PXEBoot()
- self.deploy = iscsi_deploy.ISCSIDeploy()
- self.management = ssh.SSHManagement()
- self.inspect = inspector.Inspector.create_if_enabled(
- 'PXEAndSSHDriver')
- self.raid = agent.AgentRAID()
- self.console = ssh.ShellinaboxConsole()
-
-
class PXEAndIloDriver(base.BaseDriver):
"""PXE + Ilo Driver using IloClient interface.
diff --git a/ironic/tests/unit/api/v1/test_nodes.py b/ironic/tests/unit/api/v1/test_nodes.py
index 02c2be9ba..9ded998ea 100644
--- a/ironic/tests/unit/api/v1/test_nodes.py
+++ b/ironic/tests/unit/api/v1/test_nodes.py
@@ -1045,12 +1045,12 @@ class TestListNodes(test_api_base.BaseApiTest):
def test_get_nodes_by_driver(self):
node = obj_utils.create_test_node(self.context,
uuid=uuidutils.generate_uuid(),
- driver='pxe_ssh')
+ driver='pxe_ipmitool')
node1 = obj_utils.create_test_node(self.context,
uuid=uuidutils.generate_uuid(),
driver='fake')
- data = self.get_json('/nodes?driver=pxe_ssh',
+ data = self.get_json('/nodes?driver=pxe_ipmitool',
headers={api_base.Version.string: "1.16"})
uuids = [n['uuid'] for n in data['nodes']]
self.assertIn(node.uuid, uuids)
diff --git a/ironic/tests/unit/conductor/test_manager.py b/ironic/tests/unit/conductor/test_manager.py
index dda03594c..7873b4ff7 100644
--- a/ironic/tests/unit/conductor/test_manager.py
+++ b/ironic/tests/unit/conductor/test_manager.py
@@ -4979,13 +4979,6 @@ class ManagerTestProperties(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
]
self._check_driver_properties("fake_ipmitool", expected)
- def test_driver_properties_fake_ssh(self):
- expected = ['ssh_address', 'ssh_username',
- 'vbox_use_headless', 'ssh_virt_type',
- 'ssh_key_contents', 'ssh_key_filename',
- 'ssh_password', 'ssh_port', 'ssh_terminal_port']
- self._check_driver_properties("fake_ssh", expected)
-
def test_driver_properties_fake_pxe(self):
expected = ['deploy_kernel', 'deploy_ramdisk',
'deploy_forces_oob_reboot']
@@ -5006,15 +4999,6 @@ class ManagerTestProperties(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
'ipmi_force_boot_device', 'deploy_forces_oob_reboot']
self._check_driver_properties("pxe_ipmitool", expected)
- def test_driver_properties_pxe_ssh(self):
- expected = ['deploy_kernel', 'deploy_ramdisk',
- 'ssh_address', 'ssh_username',
- 'vbox_use_headless', 'ssh_virt_type',
- 'ssh_key_contents', 'ssh_key_filename',
- 'ssh_password', 'ssh_port', 'ssh_terminal_port',
- 'deploy_forces_oob_reboot']
- self._check_driver_properties("pxe_ssh", expected)
-
def test_driver_properties_pxe_snmp(self):
expected = ['deploy_kernel', 'deploy_ramdisk',
'snmp_driver', 'snmp_address', 'snmp_port', 'snmp_version',
diff --git a/ironic/tests/unit/db/utils.py b/ironic/tests/unit/db/utils.py
index 75f6469a1..7c5244d3e 100644
--- a/ironic/tests/unit/db/utils.py
+++ b/ironic/tests/unit/db/utils.py
@@ -48,34 +48,6 @@ def get_test_ipmi_bridging_parameters():
}
-def get_test_ssh_info(auth_type='password', virt_type='virsh'):
- result = {
- "ssh_address": "1.2.3.4",
- "ssh_username": "admin",
- "ssh_port": 22,
- "ssh_virt_type": virt_type,
- }
- if 'password' == auth_type:
- result['ssh_password'] = 'fake'
- elif 'file' == auth_type:
- result['ssh_key_filename'] = '/not/real/file'
- elif 'key' == auth_type:
- result['ssh_key_contents'] = '--BEGIN PRIVATE ...blah'
- elif 'file_with_passphrase' == auth_type:
- result['ssh_password'] = 'fake'
- result['ssh_key_filename'] = '/not/real/file'
- elif 'key_with_passphrase' == auth_type:
- result['ssh_password'] = 'fake'
- result['ssh_key_contents'] = '--BEGIN PRIVATE ...blah'
- elif 'too_many' == auth_type:
- result['ssh_key_contents'] = '--BEGIN PRIVATE ...blah'
- result['ssh_key_filename'] = '/not/real/file'
- else:
- # No auth details (is invalid)
- pass
- return result
-
-
def get_test_pxe_driver_info():
return {
"deploy_kernel": "glance://deploy_kernel_uuid",
diff --git a/ironic/tests/unit/drivers/modules/test_inspector.py b/ironic/tests/unit/drivers/modules/test_inspector.py
index bcd197b4c..73b1abcb0 100644
--- a/ironic/tests/unit/drivers/modules/test_inspector.py
+++ b/ironic/tests/unit/drivers/modules/test_inspector.py
@@ -27,8 +27,8 @@ from ironic.tests.unit.objects import utils as obj_utils
class DisabledTestCase(db_base.DbTestCase):
def _do_mock(self):
# NOTE(dtantsur): fake driver always has inspection, using another one
- mgr_utils.mock_the_extension_manager("pxe_ssh")
- self.driver = driver_factory.get_driver("pxe_ssh")
+ mgr_utils.mock_the_extension_manager("pxe_ipmitool")
+ self.driver = driver_factory.get_driver("pxe_ipmitool")
def test_disabled(self):
self.config(enabled=False, group='inspector')
diff --git a/ironic/tests/unit/drivers/modules/test_ssh.py b/ironic/tests/unit/drivers/modules/test_ssh.py
deleted file mode 100644
index 008c0a8b0..000000000
--- a/ironic/tests/unit/drivers/modules/test_ssh.py
+++ /dev/null
@@ -1,1247 +0,0 @@
-# Copyright 2013 Hewlett-Packard Development Company, L.P.
-# 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.
-
-"""Test class for Ironic SSH power driver."""
-
-import tempfile
-
-import mock
-from oslo_concurrency import processutils
-from oslo_config import cfg
-from oslo_utils import uuidutils
-import paramiko
-
-from ironic.common import boot_devices
-from ironic.common import driver_factory
-from ironic.common import exception
-from ironic.common import states
-from ironic.common import utils
-from ironic.conductor import task_manager
-from ironic.drivers.modules import console_utils
-from ironic.drivers.modules import ssh
-from ironic.drivers import utils as driver_utils
-from ironic.tests.unit.conductor import mgr_utils
-from ironic.tests.unit.db import base as db_base
-from ironic.tests.unit.db import utils as db_utils
-from ironic.tests.unit.objects import utils as obj_utils
-
-
-CONF = cfg.CONF
-
-
-class SSHValidateParametersTestCase(db_base.DbTestCase):
-
- def test__parse_driver_info_good_password(self):
- # make sure we get back the expected things
- node = obj_utils.get_test_node(
- self.context,
- driver='fake_ssh',
- driver_info=db_utils.get_test_ssh_info('password'))
- info = ssh._parse_driver_info(node)
- self.assertEqual('1.2.3.4', info['host'])
- self.assertEqual('admin', info['username'])
- self.assertEqual('fake', info['password'])
- self.assertEqual(22, info['port'])
- self.assertEqual('virsh', info['virt_type'])
- self.assertIsNotNone(info['cmd_set'])
- self.assertEqual('1be26c0b-03f2-4d2e-ae87-c02d7f33c123',
- info['uuid'])
-
- def test__parse_driver_info_good_key(self):
- # make sure we get back the expected things
- node = obj_utils.get_test_node(
- self.context,
- driver='fake_ssh',
- driver_info=db_utils.get_test_ssh_info('key'))
- info = ssh._parse_driver_info(node)
- self.assertEqual('1.2.3.4', info['host'])
- self.assertEqual('admin', info['username'])
- self.assertEqual('--BEGIN PRIVATE ...blah', info['key_contents'])
- self.assertEqual(22, info['port'])
- self.assertEqual('virsh', info['virt_type'])
- self.assertIsNotNone(info['cmd_set'])
- self.assertEqual('1be26c0b-03f2-4d2e-ae87-c02d7f33c123',
- info['uuid'])
-
- def test__parse_driver_info_good_file(self):
- # make sure we get back the expected things
- d_info = db_utils.get_test_ssh_info('file')
- tempdir = tempfile.mkdtemp()
- key_path = tempdir + '/foo'
- open(key_path, 'wt').close()
- d_info['ssh_key_filename'] = key_path
- node = obj_utils.get_test_node(
- self.context,
- driver='fake_ssh',
- driver_info=d_info)
- info = ssh._parse_driver_info(node)
- self.assertEqual('1.2.3.4', info['host'])
- self.assertEqual('admin', info['username'])
- self.assertEqual(key_path, info['key_filename'])
- self.assertEqual(22, info['port'])
- self.assertEqual('virsh', info['virt_type'])
- self.assertIsNotNone(info['cmd_set'])
- self.assertEqual('1be26c0b-03f2-4d2e-ae87-c02d7f33c123',
- info['uuid'])
-
- def test__parse_driver_info_good_file_with_passphrase(self):
- # make sure we get back the expected things
- d_info = db_utils.get_test_ssh_info('file_with_passphrase')
- tempdir = tempfile.mkdtemp()
- key_path = tempdir + '/foo'
- open(key_path, 'wt').close()
- d_info['ssh_key_filename'] = key_path
- node = obj_utils.get_test_node(
- self.context,
- driver='fake_ssh',
- driver_info=d_info)
- info = ssh._parse_driver_info(node)
- self.assertEqual('1.2.3.4', info['host'])
- self.assertEqual('admin', info['username'])
- self.assertEqual('fake', info['password'])
- self.assertEqual(key_path, info['key_filename'])
- self.assertEqual(22, info['port'])
- self.assertEqual('virsh', info['virt_type'])
- self.assertIsNotNone(info['cmd_set'])
- self.assertEqual('1be26c0b-03f2-4d2e-ae87-c02d7f33c123',
- info['uuid'])
-
- def test__parse_driver_info_good_key_with_passphrase(self):
- # make sure we get back the expected things
- node = obj_utils.get_test_node(
- self.context,
- driver='fake_ssh',
- driver_info=db_utils.get_test_ssh_info('key_with_passphrase'))
- info = ssh._parse_driver_info(node)
- self.assertEqual('1.2.3.4', info['host'])
- self.assertEqual('admin', info['username'])
- self.assertEqual('fake', info['password'])
- self.assertEqual('--BEGIN PRIVATE ...blah', info['key_contents'])
- self.assertEqual(22, info['port'])
- self.assertEqual('virsh', info['virt_type'])
- self.assertIsNotNone(info['cmd_set'])
- self.assertEqual('1be26c0b-03f2-4d2e-ae87-c02d7f33c123',
- info['uuid'])
-
- def test__parse_driver_info_bad_file(self):
- # A filename that doesn't exist errors.
- info = db_utils.get_test_ssh_info('file')
- node = obj_utils.get_test_node(
- self.context,
- driver='fake_ssh',
- driver_info=info)
- self.assertRaises(
- exception.InvalidParameterValue, ssh._parse_driver_info, node)
-
- def test__parse_driver_info_too_many(self):
- node = obj_utils.get_test_node(
- self.context,
- driver='fake_ssh',
- driver_info=db_utils.get_test_ssh_info('too_many'))
- self.assertRaises(
- exception.InvalidParameterValue, ssh._parse_driver_info, node)
-
- def test__parse_driver_info_missing_host(self):
- # make sure error is raised when info is missing
- info = db_utils.get_test_ssh_info()
- del info['ssh_address']
- node = obj_utils.get_test_node(self.context, driver_info=info)
- self.assertRaises(exception.MissingParameterValue,
- ssh._parse_driver_info,
- node)
-
- def test__parse_driver_info_missing_user(self):
- # make sure error is raised when info is missing
- info = db_utils.get_test_ssh_info()
- del info['ssh_username']
- node = obj_utils.get_test_node(self.context, driver_info=info)
- self.assertRaises(exception.MissingParameterValue,
- ssh._parse_driver_info,
- node)
-
- def test__parse_driver_info_invalid_creds(self):
- # make sure error is raised when info is missing
- info = db_utils.get_test_ssh_info('no-creds')
- node = obj_utils.get_test_node(self.context, driver_info=info)
- self.assertRaises(exception.InvalidParameterValue,
- ssh._parse_driver_info,
- node)
-
- def test__parse_driver_info_missing_virt_type(self):
- # make sure error is raised when info is missing
- info = db_utils.get_test_ssh_info()
- del info['ssh_virt_type']
- node = obj_utils.get_test_node(self.context, driver_info=info)
- self.assertRaises(exception.MissingParameterValue,
- ssh._parse_driver_info,
- node)
-
- def test__parse_driver_info_ssh_port_wrong_type(self):
- # make sure error is raised when ssh_port is not integer
- info = db_utils.get_test_ssh_info()
- info['ssh_port'] = 'wrong_port_value'
- node = obj_utils.get_test_node(self.context, driver_info=info)
- self.assertRaises(exception.InvalidParameterValue,
- ssh._parse_driver_info,
- node)
-
- def test__parse_driver_info_with_custom_libvirt_uri(self):
- CONF.set_override('libvirt_uri', 'qemu:///foo', 'ssh')
- expected_base_cmd = "LC_ALL=C /usr/bin/virsh --connect qemu:///foo"
-
- node = obj_utils.get_test_node(
- self.context,
- driver='fake_ssh',
- driver_info=db_utils.get_test_ssh_info())
- node['driver_info']['ssh_virt_type'] = 'virsh'
- info = ssh._parse_driver_info(node)
- self.assertEqual(expected_base_cmd, info['cmd_set']['base_cmd'])
-
- def test__get_boot_device_map_parallels(self):
- boot_map = ssh._get_boot_device_map('parallels')
- self.assertEqual('net0', boot_map[boot_devices.PXE])
-
- def test__get_boot_device_map_vbox(self):
- boot_map = ssh._get_boot_device_map('vbox')
- self.assertEqual('net', boot_map[boot_devices.PXE])
-
- def test__get_boot_device_map_xenserver(self):
- boot_map = ssh._get_boot_device_map('xenserver')
- self.assertEqual('n', boot_map[boot_devices.PXE])
-
- def test__get_boot_device_map_exception(self):
- self.assertRaises(exception.InvalidParameterValue,
- ssh._get_boot_device_map,
- 'this_doesn_t_exist')
-
-
-class SSHPrivateMethodsTestCase(db_base.DbTestCase):
-
- def setUp(self):
- super(SSHPrivateMethodsTestCase, self).setUp()
- self.node = obj_utils.get_test_node(
- self.context,
- driver='fake_ssh',
- driver_info=db_utils.get_test_ssh_info())
- self.sshclient = paramiko.SSHClient()
-
- @mock.patch.object(utils, 'ssh_connect', autospec=True)
- def test__get_connection_client(self, ssh_connect_mock):
- ssh_connect_mock.return_value = self.sshclient
- client = ssh._get_connection(self.node)
- self.assertEqual(self.sshclient, client)
- driver_info = ssh._parse_driver_info(self.node)
- ssh_connect_mock.assert_called_once_with(driver_info)
-
- @mock.patch.object(utils, 'ssh_connect', autospec=True)
- def test__get_connection_exception(self, ssh_connect_mock):
- ssh_connect_mock.side_effect = exception.SSHConnectFailed(host='fake')
- self.assertRaises(exception.SSHConnectFailed,
- ssh._get_connection,
- self.node)
- driver_info = ssh._parse_driver_info(self.node)
- ssh_connect_mock.assert_called_once_with(driver_info)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- def test__ssh_execute(self, exec_ssh_mock):
- ssh_cmd = "somecmd"
- expected = ['a', 'b', 'c']
- exec_ssh_mock.return_value = ('\n'.join(expected), '')
- lst = ssh._ssh_execute(self.sshclient, ssh_cmd)
- exec_ssh_mock.assert_called_once_with(self.sshclient, ssh_cmd)
- self.assertEqual(expected, lst)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- def test__ssh_execute_exception(self, exec_ssh_mock):
- ssh_cmd = "somecmd"
- exec_ssh_mock.side_effect = processutils.ProcessExecutionError
- self.assertRaises(exception.SSHCommandFailed,
- ssh._ssh_execute,
- self.sshclient,
- ssh_cmd)
- exec_ssh_mock.assert_called_once_with(self.sshclient, ssh_cmd)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- def test__get_power_status_on_unquoted(self, get_hosts_name_mock,
- exec_ssh_mock):
- info = ssh._parse_driver_info(self.node)
- exec_ssh_mock.return_value = (
- 'ExactNodeName', '')
- get_hosts_name_mock.return_value = "ExactNodeName"
-
- pstate = ssh._get_power_status(self.sshclient, info)
-
- ssh_cmd = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['list_running'])
- self.assertEqual(states.POWER_ON, pstate)
- exec_ssh_mock.assert_called_once_with(self.sshclient, ssh_cmd)
- get_hosts_name_mock.assert_called_once_with(self.sshclient, info)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- def test__get_power_status_on(self, get_hosts_name_mock, exec_ssh_mock):
- info = ssh._parse_driver_info(self.node)
- exec_ssh_mock.return_value = (
- '"NodeName" {b43c4982-110c-4c29-9325-d5f41b053513}', '')
- get_hosts_name_mock.return_value = "NodeName"
-
- pstate = ssh._get_power_status(self.sshclient, info)
-
- ssh_cmd = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['list_running'])
- self.assertEqual(states.POWER_ON, pstate)
- exec_ssh_mock.assert_called_once_with(self.sshclient, ssh_cmd)
- get_hosts_name_mock.assert_called_once_with(self.sshclient, info)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- def test__get_power_status_off(self, get_hosts_name_mock, exec_ssh_mock):
- info = ssh._parse_driver_info(self.node)
- exec_ssh_mock.return_value = (
- '"NodeName" {b43c4982-110c-4c29-9325-d5f41b053513}', '')
- get_hosts_name_mock.return_value = "NotNodeName"
-
- pstate = ssh._get_power_status(self.sshclient, info)
-
- ssh_cmd = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['list_running'])
- self.assertEqual(states.POWER_OFF, pstate)
- exec_ssh_mock.assert_called_once_with(self.sshclient, ssh_cmd)
- get_hosts_name_mock.assert_called_once_with(self.sshclient, info)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- def test__get_power_status_exception(self, exec_ssh_mock):
- info = ssh._parse_driver_info(self.node)
- exec_ssh_mock.side_effect = processutils.ProcessExecutionError
-
- self.assertRaises(exception.SSHCommandFailed,
- ssh._get_power_status,
- self.sshclient,
- info)
- ssh_cmd = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['list_all'])
- exec_ssh_mock.assert_called_once_with(
- self.sshclient, ssh_cmd)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- def test__get_power_status_correct_node(self, get_hosts_name_mock,
- exec_ssh_mock):
- # Bug: #1397834 test that get_power_status return status of
- # baremeta_1 (off) and not baremetal_11 (on)
- info = ssh._parse_driver_info(self.node)
- exec_ssh_mock.return_value = ('"baremetal_11"\n"seed"\n', '')
- get_hosts_name_mock.return_value = "baremetal_1"
-
- pstate = ssh._get_power_status(self.sshclient, info)
- self.assertEqual(states.POWER_OFF, pstate)
- ssh_cmd = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['list_running'])
- exec_ssh_mock.assert_called_once_with(self.sshclient, ssh_cmd)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- def test__get_hosts_name_for_node_match(self, exec_ssh_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
- ssh_cmd = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['list_all'])
-
- cmd_to_exec = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['get_node_macs'])
- cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', 'NodeName')
- exec_ssh_mock.side_effect = [('NodeName', ''),
- ('52:54:00:cf:2d:31', '')]
- expected = [mock.call(self.sshclient, ssh_cmd),
- mock.call(self.sshclient, cmd_to_exec)]
-
- found_name = ssh._get_hosts_name_for_node(self.sshclient, info)
-
- self.assertEqual('NodeName', found_name)
- self.assertEqual(expected, exec_ssh_mock.call_args_list)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- def test__get_hosts_name_for_node_no_match(self, exec_ssh_mock):
- self.config(group='ssh', get_vm_name_attempts=2)
- self.config(group='ssh', get_vm_name_retry_interval=0)
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "22:22:22:22:22:22"]
- exec_ssh_mock.side_effect = ([('NodeName', ''),
- ('52:54:00:cf:2d:31', '')] * 2)
-
- ssh_cmd = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['list_all'])
-
- cmd_to_exec = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['get_node_macs'])
-
- cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', 'NodeName')
- expected = [mock.call(self.sshclient, ssh_cmd),
- mock.call(self.sshclient, cmd_to_exec)] * 2
-
- self.assertRaises(exception.NodeNotFound,
- ssh._get_hosts_name_for_node, self.sshclient, info)
- self.assertEqual(expected, exec_ssh_mock.call_args_list)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- def test__get_hosts_name_for_node_match_after_retry(self, exec_ssh_mock):
- self.config(group='ssh', get_vm_name_attempts=2)
- self.config(group='ssh', get_vm_name_retry_interval=0)
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "22:22:22:22:22:22"]
- exec_ssh_mock.side_effect = [('NodeName', ''),
- ('', ''),
- ('NodeName', ''),
- ('11:11:11:11:11:11', '')]
-
- ssh_cmd = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['list_all'])
-
- cmd_to_exec = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['get_node_macs'])
-
- cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', 'NodeName')
- expected = [mock.call(self.sshclient, ssh_cmd),
- mock.call(self.sshclient, cmd_to_exec)] * 2
-
- found_name = ssh._get_hosts_name_for_node(self.sshclient, info)
-
- self.assertEqual('NodeName', found_name)
- self.assertEqual(expected, exec_ssh_mock.call_args_list)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- def test__get_hosts_name_for_node_exception(self, exec_ssh_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
- ssh_cmd = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['list_all'])
-
- cmd_to_exec = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['get_node_macs'])
- cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', 'NodeName')
-
- exec_ssh_mock.side_effect = [('NodeName', ''),
- processutils.ProcessExecutionError]
- expected = [mock.call(self.sshclient, ssh_cmd),
- mock.call(self.sshclient, cmd_to_exec)]
-
- self.assertRaises(exception.SSHCommandFailed,
- ssh._get_hosts_name_for_node,
- self.sshclient,
- info)
- self.assertEqual(expected, exec_ssh_mock.call_args_list)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- @mock.patch.object(ssh, '_get_power_status', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- def test__power_on_good(self, get_hosts_name_mock, get_power_status_mock,
- exec_ssh_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
-
- get_power_status_mock.side_effect = [states.POWER_OFF,
- states.POWER_ON]
- get_hosts_name_mock.return_value = "NodeName"
- expected = [mock.call(self.sshclient, info),
- mock.call(self.sshclient, info)]
-
- cmd_to_exec = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['start_cmd'])
- cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', 'NodeName')
- current_state = ssh._power_on(self.sshclient, info)
-
- self.assertEqual(states.POWER_ON, current_state)
- self.assertEqual(expected, get_power_status_mock.call_args_list)
- get_hosts_name_mock.assert_called_once_with(self.sshclient, info)
- exec_ssh_mock.assert_called_once_with(self.sshclient, cmd_to_exec)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- @mock.patch.object(ssh, '_get_power_status', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- def test__power_on_fail(self, get_hosts_name_mock, get_power_status_mock,
- exec_ssh_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
- get_power_status_mock.side_effect = ([states.POWER_OFF,
- states.POWER_OFF])
- get_hosts_name_mock.return_value = "NodeName"
- expected = [mock.call(self.sshclient, info),
- mock.call(self.sshclient, info)]
-
- cmd_to_exec = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['start_cmd'])
- cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', 'NodeName')
- current_state = ssh._power_on(self.sshclient, info)
-
- self.assertEqual(states.ERROR, current_state)
- self.assertEqual(expected, get_power_status_mock.call_args_list)
- get_hosts_name_mock.assert_called_once_with(self.sshclient, info)
- exec_ssh_mock.assert_called_once_with(self.sshclient, cmd_to_exec)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- @mock.patch.object(ssh, '_get_power_status', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- def test__power_on_exception(self, get_hosts_name_mock,
- get_power_status_mock, exec_ssh_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
-
- exec_ssh_mock.side_effect = processutils.ProcessExecutionError
- get_power_status_mock.side_effect = ([states.POWER_OFF,
- states.POWER_ON])
- get_hosts_name_mock.return_value = "NodeName"
-
- cmd_to_exec = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['start_cmd'])
- cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', 'NodeName')
-
- self.assertRaises(exception.SSHCommandFailed,
- ssh._power_on,
- self.sshclient,
- info)
- get_power_status_mock.assert_called_once_with(self.sshclient, info)
- get_hosts_name_mock.assert_called_once_with(self.sshclient, info)
- exec_ssh_mock.assert_called_once_with(self.sshclient, cmd_to_exec)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- @mock.patch.object(ssh, '_get_power_status', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- def test__power_off_good(self, get_hosts_name_mock,
- get_power_status_mock, exec_ssh_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
- get_power_status_mock.side_effect = [states.POWER_ON,
- states.POWER_OFF]
- get_hosts_name_mock.return_value = "NodeName"
- expected = [mock.call(self.sshclient, info),
- mock.call(self.sshclient, info)]
-
- cmd_to_exec = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['stop_cmd'])
- cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', 'NodeName')
- current_state = ssh._power_off(self.sshclient, info)
-
- self.assertEqual(states.POWER_OFF, current_state)
- self.assertEqual(expected, get_power_status_mock.call_args_list)
- get_hosts_name_mock.assert_called_once_with(self.sshclient, info)
- exec_ssh_mock.assert_called_once_with(self.sshclient, cmd_to_exec)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- @mock.patch.object(ssh, '_get_power_status', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- def test__power_off_fail(self, get_hosts_name_mock,
- get_power_status_mock, exec_ssh_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
- get_power_status_mock.side_effect = [states.POWER_ON,
- states.POWER_ON]
- get_hosts_name_mock.return_value = "NodeName"
- expected = [mock.call(self.sshclient, info),
- mock.call(self.sshclient, info)]
-
- cmd_to_exec = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['stop_cmd'])
- cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', 'NodeName')
- current_state = ssh._power_off(self.sshclient, info)
-
- self.assertEqual(states.ERROR, current_state)
- self.assertEqual(expected, get_power_status_mock.call_args_list)
- get_hosts_name_mock.assert_called_once_with(self.sshclient, info)
- exec_ssh_mock.assert_called_once_with(self.sshclient, cmd_to_exec)
-
- @mock.patch.object(processutils, 'ssh_execute', autospec=True)
- @mock.patch.object(ssh, '_get_power_status', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- def test__power_off_exception(self, get_hosts_name_mock,
- get_power_status_mock, exec_ssh_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
- exec_ssh_mock.side_effect = processutils.ProcessExecutionError
- get_power_status_mock.side_effect = [states.POWER_ON,
- states.POWER_OFF]
- get_hosts_name_mock.return_value = "NodeName"
-
- cmd_to_exec = "%s %s" % (info['cmd_set']['base_cmd'],
- info['cmd_set']['stop_cmd'])
- cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', 'NodeName')
-
- self.assertRaises(exception.SSHCommandFailed, ssh._power_off,
- self.sshclient, info)
- get_power_status_mock.assert_called_once_with(self.sshclient, info)
- get_hosts_name_mock.assert_called_once_with(self.sshclient, info)
- exec_ssh_mock.assert_called_once_with(self.sshclient, cmd_to_exec)
-
-
-class SSHDriverTestCase(db_base.DbTestCase):
-
- def setUp(self):
- super(SSHDriverTestCase, self).setUp()
- mgr_utils.mock_the_extension_manager(driver="fake_ssh")
- self.driver = driver_factory.get_driver("fake_ssh")
- self.node = obj_utils.create_test_node(
- self.context, driver='fake_ssh',
- driver_info=db_utils.get_test_ssh_info())
- self.port = obj_utils.create_test_port(self.context,
- node_id=self.node.id)
- self.sshclient = paramiko.SSHClient()
-
- @mock.patch.object(utils, 'ssh_connect', autospec=True)
- def test__validate_info_ssh_connect_failed(self, ssh_connect_mock):
- ssh_connect_mock.side_effect = exception.SSHConnectFailed(host='fake')
- with task_manager.acquire(self.context, self.node.uuid,
- shared=False) as task:
- self.assertRaises(exception.InvalidParameterValue,
- task.driver.power.validate, task)
- driver_info = ssh._parse_driver_info(task.node)
- ssh_connect_mock.assert_called_once_with(driver_info)
-
- def test_get_properties(self):
- expected = ssh.COMMON_PROPERTIES
- expected2 = list(ssh.COMMON_PROPERTIES) + list(ssh.CONSOLE_PROPERTIES)
- with task_manager.acquire(self.context, self.node.uuid,
- shared=True) as task:
- self.assertEqual(expected, task.driver.power.get_properties())
- self.assertEqual(expected, task.driver.management.get_properties())
- self.assertEqual(
- sorted(expected2),
- sorted(task.driver.console.get_properties().keys()))
- self.assertEqual(
- sorted(expected2),
- sorted(task.driver.get_properties().keys()))
-
- def test_validate_fail_no_port(self):
- new_node = obj_utils.create_test_node(
- self.context,
- uuid='aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
- driver='fake_ssh',
- driver_info=db_utils.get_test_ssh_info())
- with task_manager.acquire(self.context, new_node.uuid,
- shared=True) as task:
- self.assertRaises(exception.MissingParameterValue,
- task.driver.power.validate,
- task)
-
- @mock.patch.object(driver_utils, 'get_node_mac_addresses', autospec=True)
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_power_on', autospec=True)
- def test_reboot_good(self, power_on_mock, get_conn_mock,
- get_mac_addr_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
- get_mac_addr_mock.return_value = info['macs']
- get_conn_mock.return_value = self.sshclient
- power_on_mock.return_value = states.POWER_ON
- with mock.patch.object(ssh, '_parse_driver_info',
- autospec=True) as parse_drv_info_mock:
- parse_drv_info_mock.return_value = info
- with task_manager.acquire(self.context, info['uuid'],
- shared=False) as task:
- task.driver.power.reboot(task)
-
- parse_drv_info_mock.assert_called_once_with(task.node)
- get_mac_addr_mock.assert_called_once_with(mock.ANY)
- get_conn_mock.assert_called_once_with(task.node)
- power_on_mock.assert_called_once_with(self.sshclient, info)
-
- @mock.patch.object(driver_utils, 'get_node_mac_addresses', autospec=True)
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_power_on', autospec=True)
- def test_reboot_fail(self, power_on_mock, get_conn_mock,
- get_mac_addr_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
- get_mac_addr_mock.return_value = info['macs']
- get_conn_mock.return_value = self.sshclient
- power_on_mock.return_value = states.POWER_OFF
- with mock.patch.object(ssh, '_parse_driver_info',
- autospec=True) as parse_drv_info_mock:
- parse_drv_info_mock.return_value = info
- with task_manager.acquire(self.context, info['uuid'],
- shared=False) as task:
- self.assertRaises(exception.PowerStateFailure,
- task.driver.power.reboot, task)
- parse_drv_info_mock.assert_called_once_with(task.node)
- get_mac_addr_mock.assert_called_once_with(mock.ANY)
- get_conn_mock.assert_called_once_with(task.node)
- power_on_mock.assert_called_once_with(self.sshclient, info)
-
- @mock.patch.object(driver_utils, 'get_node_mac_addresses', autospec=True)
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- def test_set_power_state_bad_state(self, get_conn_mock,
- get_mac_addr_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
- get_mac_addr_mock.return_value = info['macs']
- get_conn_mock.return_value = self.sshclient
- with mock.patch.object(ssh, '_parse_driver_info',
- autospec=True) as parse_drv_info_mock:
- parse_drv_info_mock.return_value = info
- with task_manager.acquire(self.context, info['uuid'],
- shared=False) as task:
- self.assertRaises(
- exception.InvalidParameterValue,
- task.driver.power.set_power_state,
- task,
- "BAD_PSTATE")
-
- parse_drv_info_mock.assert_called_once_with(task.node)
- get_mac_addr_mock.assert_called_once_with(mock.ANY)
- get_conn_mock.assert_called_once_with(task.node)
-
- @mock.patch.object(driver_utils, 'get_node_mac_addresses', autospec=True)
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_power_on', autospec=True)
- def test_set_power_state_on_good(self, power_on_mock, get_conn_mock,
- get_mac_addr_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
- get_mac_addr_mock.return_value = info['macs']
- get_conn_mock.return_value = self.sshclient
- power_on_mock.return_value = states.POWER_ON
- with mock.patch.object(ssh, '_parse_driver_info',
- autospec=True) as parse_drv_info_mock:
- parse_drv_info_mock.return_value = info
- with task_manager.acquire(self.context, info['uuid'],
- shared=False) as task:
- task.driver.power.set_power_state(task, states.POWER_ON)
-
- parse_drv_info_mock.assert_called_once_with(task.node)
- get_mac_addr_mock.assert_called_once_with(mock.ANY)
- get_conn_mock.assert_called_once_with(task.node)
- power_on_mock.assert_called_once_with(self.sshclient, info)
-
- @mock.patch.object(driver_utils, 'get_node_mac_addresses', autospec=True)
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_power_on', autospec=True)
- def test_set_power_state_on_fail(self, power_on_mock, get_conn_mock,
- get_mac_addr_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
- get_mac_addr_mock.return_value = info['macs']
- get_conn_mock.return_value = self.sshclient
- power_on_mock.return_value = states.POWER_OFF
- with mock.patch.object(ssh, '_parse_driver_info',
- autospec=True) as parse_drv_info_mock:
- parse_drv_info_mock.return_value = info
- with task_manager.acquire(self.context, info['uuid'],
- shared=False) as task:
- self.assertRaises(
- exception.PowerStateFailure,
- task.driver.power.set_power_state,
- task,
- states.POWER_ON)
-
- parse_drv_info_mock.assert_called_once_with(task.node)
- get_mac_addr_mock.assert_called_once_with(mock.ANY)
- get_conn_mock.assert_called_once_with(task.node)
- power_on_mock.assert_called_once_with(self.sshclient, info)
-
- @mock.patch.object(driver_utils, 'get_node_mac_addresses', autospec=True)
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_power_off', autospec=True)
- def test_set_power_state_off_good(self, power_off_mock, get_conn_mock,
- get_mac_addr_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
- get_mac_addr_mock.return_value = info['macs']
- get_conn_mock.return_value = self.sshclient
- power_off_mock.return_value = states.POWER_OFF
- with mock.patch.object(ssh, '_parse_driver_info',
- autospec=True) as parse_drv_info_mock:
- parse_drv_info_mock.return_value = info
- with task_manager.acquire(self.context, info['uuid'],
- shared=False) as task:
- task.driver.power.set_power_state(task, states.POWER_OFF)
-
- parse_drv_info_mock.assert_called_once_with(task.node)
- get_mac_addr_mock.assert_called_once_with(mock.ANY)
- get_conn_mock.assert_called_once_with(task.node)
- power_off_mock.assert_called_once_with(self.sshclient, info)
-
- @mock.patch.object(driver_utils, 'get_node_mac_addresses', autospec=True)
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_power_off', autospec=True)
- def test_set_power_state_off_fail(self, power_off_mock, get_conn_mock,
- get_mac_addr_mock):
- info = ssh._parse_driver_info(self.node)
- info['macs'] = ["11:11:11:11:11:11", "52:54:00:cf:2d:31"]
- get_mac_addr_mock.return_value = info['macs']
- get_conn_mock.return_value = self.sshclient
- power_off_mock.return_value = states.POWER_ON
- with mock.patch.object(ssh, '_parse_driver_info',
- autospec=True) as parse_drv_info_mock:
- parse_drv_info_mock.return_value = info
- with task_manager.acquire(self.context, info['uuid'],
- shared=False) as task:
- self.assertRaises(
- exception.PowerStateFailure,
- task.driver.power.set_power_state,
- task,
- states.POWER_OFF)
-
- parse_drv_info_mock.assert_called_once_with(task.node)
- get_mac_addr_mock.assert_called_once_with(mock.ANY)
- get_conn_mock.assert_called_once_with(task.node)
- power_off_mock.assert_called_once_with(self.sshclient, info)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- def test_management_interface_set_boot_device_vbox_ok(self, mock_exc,
- mock_h,
- mock_get_conn):
- fake_name = 'fake-name'
- mock_h.return_value = fake_name
- mock_get_conn.return_value = self.sshclient
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'vbox'
- self.driver.management.set_boot_device(task, boot_devices.PXE)
- expected_cmd = ('LC_ALL=C /usr/bin/VBoxManage modifyvm %s '
- '--boot1 net') % fake_name
- mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
-
- @mock.patch.object(ssh, '_get_power_status', autospec=True)
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- def test_management_interface_set_boot_device_vbox_with_power_on(
- self, mock_exc, mock_h, mock_get_conn, mock_get_power):
- fake_name = 'fake-name'
- mock_h.return_value = fake_name
- mock_get_conn.return_value = self.sshclient
- # NOTE(jroll) _power_off calls _get_power_state twice
- mock_get_power.side_effect = [
- states.POWER_ON, states.POWER_ON, states.POWER_OFF
- ]
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'vbox'
- task.node['driver_info']['vbox_use_headless'] = True
- self.driver.management.set_boot_device(task, boot_devices.PXE)
-
- expected_cmds = [
- mock.call(mock.ANY,
- 'LC_ALL=C /usr/bin/VBoxManage '
- 'controlvm %s poweroff' % fake_name),
- mock.call(mock.ANY,
- 'LC_ALL=C /usr/bin/VBoxManage '
- 'modifyvm %s --boot1 net' % fake_name)
- ]
- self.assertEqual(expected_cmds, mock_exc.call_args_list)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- def test_management_interface_set_boot_device_parallels_ok(self, mock_exc,
- mock_h,
- mock_get_conn):
- fake_name = 'fake-name'
- mock_h.return_value = fake_name
- mock_get_conn.return_value = self.sshclient
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'parallels'
- self.driver.management.set_boot_device(task, boot_devices.PXE)
- expected_cmd = ('LC_ALL=C /usr/bin/prlctl set %s '
- '--device-bootorder "net0"') % fake_name
- mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- def test_management_interface_set_boot_device_virsh_ok(self, mock_exc,
- mock_h,
- mock_get_conn):
- fake_name = 'fake-name'
- mock_h.return_value = fake_name
- mock_get_conn.return_value = self.sshclient
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'virsh'
- self.driver.management.set_boot_device(task, boot_devices.PXE)
- expected_cmd = ('EDITOR="sed -i \'/<boot \\(dev\\|order\\)=*\\>'
- '/d;/<\\/os>/i\\<boot dev=\\"network\\"/>\'" '
- 'LC_ALL=C /usr/bin/virsh --connect qemu:///system '
- 'edit %s') % fake_name
- mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- def test_management_interface_set_boot_device_xenserver_ok(self,
- mock_exc,
- mock_h,
- mock_get_conn):
- fake_name = 'fake-name'
- mock_h.return_value = fake_name
- mock_get_conn.return_value = self.sshclient
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'xenserver'
- self.driver.management.set_boot_device(task, boot_devices.PXE)
- expected_cmd = ("LC_ALL=C /opt/xensource/bin/xe vm-param-set uuid=%s "
- "HVM-boot-params:order='n'") % fake_name
- mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
-
- def test_set_boot_device_bad_device(self):
- with task_manager.acquire(self.context, self.node.uuid) as task:
- self.assertRaises(exception.InvalidParameterValue,
- self.driver.management.set_boot_device,
- task, 'invalid-device')
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- def test_set_boot_device_not_supported(self, mock_h, mock_get_conn):
- mock_h.return_value = 'NodeName'
- mock_get_conn.return_value = self.sshclient
- with task_manager.acquire(self.context, self.node.uuid) as task:
- # vmware does not support set_boot_device()
- task.node['driver_info']['ssh_virt_type'] = 'vmware'
- self.assertRaises(NotImplementedError,
- self.driver.management.set_boot_device,
- task, boot_devices.PXE)
-
- def test_management_interface_get_supported_boot_devices(self):
- with task_manager.acquire(self.context, self.node.uuid) as task:
- expected = [boot_devices.PXE, boot_devices.DISK,
- boot_devices.CDROM]
- self.assertEqual(sorted(expected), sorted(task.driver.management.
- get_supported_boot_devices(task)))
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- def test_management_interface_get_boot_device_vbox(self, mock_exc,
- mock_h,
- mock_get_conn):
- fake_name = 'fake-name'
- mock_h.return_value = fake_name
- mock_exc.return_value = ('net', '')
- mock_get_conn.return_value = self.sshclient
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'vbox'
- result = self.driver.management.get_boot_device(task)
- self.assertEqual(boot_devices.PXE, result['boot_device'])
- expected_cmd = ('LC_ALL=C /usr/bin/VBoxManage showvminfo '
- '--machinereadable %s '
- '| awk -F \'"\' \'/boot1/{print $2}\'') % fake_name
- mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- def test_management_interface_get_boot_device_parallels(self, mock_exc,
- mock_h,
- mock_get_conn):
- fake_name = 'fake-name'
- mock_h.return_value = fake_name
- mock_exc.return_value = ('net0', '')
- mock_get_conn.return_value = self.sshclient
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'parallels'
- result = self.driver.management.get_boot_device(task)
- self.assertEqual(boot_devices.PXE, result['boot_device'])
- expected_cmd = ('LC_ALL=C /usr/bin/prlctl list -i %s '
- '| awk \'/^Boot order:/ {print $3}\'') % fake_name
- mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- def test_management_interface_get_boot_device_virsh(self, mock_exc,
- mock_h,
- mock_get_conn):
- fake_name = 'fake-name'
- mock_h.return_value = fake_name
- mock_exc.return_value = ('network', '')
- mock_get_conn.return_value = self.sshclient
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'virsh'
- result = self.driver.management.get_boot_device(task)
- self.assertEqual(boot_devices.PXE, result['boot_device'])
- expected_cmd = ('LC_ALL=C /usr/bin/virsh --connect '
- 'qemu:///system dumpxml %s | awk \'/boot dev=/ '
- '{ gsub( ".*dev=" Q, "" ); gsub( Q ".*", "" ); '
- 'print; }\' Q="\'" RS="[<>]" | head -1') % fake_name
- mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- def test_management_interface_get_boot_device_xenserver(self, mock_exc,
- mock_h,
- mock_get_conn):
- fake_name = 'fake-name'
- mock_h.return_value = fake_name
- mock_exc.return_value = ('n', '')
- mock_get_conn.return_value = self.sshclient
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'xenserver'
- result = self.driver.management.get_boot_device(task)
- self.assertEqual(boot_devices.PXE, result['boot_device'])
- expected_cmd = ('LC_ALL=C /opt/xensource/bin/xe vm-param-get '
- 'uuid=%s --param-name=HVM-boot-params '
- 'param-key=order | cut -b 1') % fake_name
- mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- def test_get_boot_device_not_supported(self, mock_h, mock_get_conn):
- mock_h.return_value = 'NodeName'
- mock_get_conn.return_value = self.sshclient
- with task_manager.acquire(self.context, self.node.uuid) as task:
- # vmware does not support get_boot_device()
- task.node['driver_info']['ssh_virt_type'] = 'vmware'
- expected = {'boot_device': None, 'persistent': None}
- self.assertEqual(expected,
- self.driver.management.get_boot_device(task))
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- def test_get_power_state_vmware(self, mock_exc, mock_h, mock_get_conn):
- # To see replacing {_NodeName_} in vmware's list_running
- nodename = 'fakevm'
- mock_h.return_value = nodename
- mock_get_conn.return_value = self.sshclient
- # list_running quotes names
- mock_exc.return_value = ('"%s"' % nodename, '')
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'vmware'
- power_state = self.driver.power.get_power_state(task)
- self.assertEqual(states.POWER_ON, power_state)
- expected_cmd = ("LC_ALL=C /bin/vim-cmd vmsvc/power.getstate "
- "%(node)s | grep 'Powered on' >/dev/null && "
- "echo '\"%(node)s\"' || true") % {'node': nodename}
- mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- def test_get_power_state_xenserver(self, mock_exc, mock_h, mock_get_conn):
- # To see replacing {_NodeName_} in xenserver's list_running
- nodename = 'fakevm'
- mock_h.return_value = nodename
- mock_get_conn.return_value = self.sshclient
- mock_exc.return_value = (nodename, '')
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'xenserver'
- power_state = self.driver.power.get_power_state(task)
- self.assertEqual(states.POWER_ON, power_state)
- expected_cmd = ("LC_ALL=C /opt/xensource/bin/xe "
- "vm-list power-state=running --minimal | tr ',' '\n'")
- mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- @mock.patch.object(ssh, '_get_power_status', autospec=True)
- def test_start_command_xenserver(self, mock_power, mock_exc, mock_h,
- mock_get_conn):
- mock_power.side_effect = [states.POWER_OFF, states.POWER_ON]
- nodename = 'fakevm'
- mock_h.return_value = nodename
- mock_get_conn.return_value = self.sshclient
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'xenserver'
- self.driver.power.set_power_state(task, states.POWER_ON)
- expected_cmd = ("LC_ALL=C /opt/xensource/bin/xe "
- "vm-start uuid=fakevm && sleep 10s")
- mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- @mock.patch.object(ssh, '_get_power_status', autospec=True)
- def test_stop_command_xenserver(self, mock_power, mock_exc, mock_h,
- mock_get_conn):
- mock_power.side_effect = [states.POWER_ON, states.POWER_OFF]
- nodename = 'fakevm'
- mock_h.return_value = nodename
- mock_get_conn.return_value = self.sshclient
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'xenserver'
- self.driver.power.set_power_state(task, states.POWER_OFF)
- expected_cmd = ("LC_ALL=C /opt/xensource/bin/xe "
- "vm-shutdown uuid=fakevm force=true")
- mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- @mock.patch.object(ssh, '_get_power_status', autospec=True)
- def test_start_command_vbox(self, mock_power, mock_exc, mock_h,
- mock_get_conn):
- mock_power.side_effect = [states.POWER_OFF, states.POWER_ON]
- nodename = 'fakevm'
- mock_h.return_value = nodename
- mock_get_conn.return_value = self.sshclient
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'vbox'
- self.driver.power.set_power_state(task, states.POWER_ON)
- expected_cmd = 'LC_ALL=C /usr/bin/VBoxManage startvm fakevm'
- mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(ssh, '_ssh_execute', autospec=True)
- @mock.patch.object(ssh, '_get_power_status', autospec=True)
- def test_start_command_vbox_headless(self, mock_power, mock_exc, mock_h,
- mock_get_conn):
- mock_power.side_effect = [states.POWER_OFF, states.POWER_ON]
- nodename = 'fakevm'
- mock_h.return_value = nodename
- mock_get_conn.return_value = self.sshclient
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.node['driver_info']['ssh_virt_type'] = 'vbox'
- task.node['driver_info']['vbox_use_headless'] = True
- self.driver.power.set_power_state(task, states.POWER_ON)
- expected_cmd = ('LC_ALL=C /usr/bin/VBoxManage '
- 'startvm fakevm --type headless')
- mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
-
- def test_management_interface_validate_good(self):
- with task_manager.acquire(self.context, self.node.uuid) as task:
- task.driver.management.validate(task)
-
- def test_management_interface_validate_fail(self):
- # Missing SSH driver_info information
- node = obj_utils.create_test_node(self.context,
- uuid=uuidutils.generate_uuid(),
- driver='fake_ssh')
- with task_manager.acquire(self.context, node.uuid) as task:
- self.assertRaises(exception.MissingParameterValue,
- task.driver.management.validate, task)
-
- def test_console_validate(self):
- with task_manager.acquire(
- self.context, self.node.uuid, shared=True) as task:
- task.node.driver_info['ssh_virt_type'] = 'virsh'
- task.node.driver_info['ssh_terminal_port'] = 123
- task.driver.console.validate(task)
-
- def test_console_validate_missing_port(self):
- with task_manager.acquire(
- self.context, self.node.uuid, shared=True) as task:
- task.node.driver_info['ssh_virt_type'] = 'virsh'
- task.node.driver_info.pop('ssh_terminal_port', None)
- self.assertRaises(exception.MissingParameterValue,
- task.driver.console.validate, task)
-
- def test_console_validate_not_virsh(self):
- with task_manager.acquire(
- self.context, self.node.uuid, shared=True) as task:
- task.node.driver_info = db_utils.get_test_ssh_info(
- virt_type='vbox')
- self.assertRaisesRegex(exception.InvalidParameterValue,
- 'not supported for non-virsh types',
- task.driver.console.validate, task)
-
- def test_console_validate_invalid_port(self):
- with task_manager.acquire(
- self.context, self.node.uuid, shared=True) as task:
- task.node.driver_info['ssh_terminal_port'] = ''
- self.assertRaisesRegex(exception.InvalidParameterValue,
- 'is not a valid integer',
- task.driver.console.validate, task)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(console_utils, 'start_shellinabox_console',
- autospec=True)
- def test_start_console(self, mock_exec,
- get_hosts_name_mock, mock_get_conn):
- info = ssh._parse_driver_info(self.node)
- mock_exec.return_value = None
- get_hosts_name_mock.return_value = "NodeName"
- mock_get_conn.return_value = self.sshclient
-
- with task_manager.acquire(self.context,
- self.node.uuid) as task:
- self.driver.console.start_console(task)
-
- mock_exec.assert_called_once_with(info['uuid'],
- info['terminal_port'],
- mock.ANY)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(console_utils, 'start_shellinabox_console',
- autospec=True)
- def test_start_console_fail(self, mock_exec,
- get_hosts_name_mock, mock_get_conn):
- get_hosts_name_mock.return_value = "NodeName"
- mock_get_conn.return_value = self.sshclient
- mock_exec.side_effect = exception.ConsoleSubprocessFailed(
- error='error')
-
- with task_manager.acquire(self.context,
- self.node.uuid) as task:
- self.assertRaises(exception.ConsoleSubprocessFailed,
- self.driver.console.start_console,
- task)
- mock_exec.assert_called_once_with(self.node.uuid, mock.ANY, mock.ANY)
-
- @mock.patch.object(ssh, '_get_connection', autospec=True)
- @mock.patch.object(ssh, '_get_hosts_name_for_node', autospec=True)
- @mock.patch.object(console_utils, 'start_shellinabox_console',
- autospec=True)
- def test_start_console_fail_nodir(self, mock_exec,
- get_hosts_name_mock, mock_get_conn):
- get_hosts_name_mock.return_value = "NodeName"
- mock_get_conn.return_value = self.sshclient
- mock_exec.side_effect = exception.ConsoleError()
-
- with task_manager.acquire(self.context,
- self.node.uuid) as task:
- self.assertRaises(exception.ConsoleError,
- self.driver.console.start_console,
- task)
- mock_exec.assert_called_once_with(self.node.uuid, mock.ANY, mock.ANY)
-
- @mock.patch.object(console_utils, 'stop_shellinabox_console',
- autospec=True)
- def test_stop_console(self, mock_exec):
- mock_exec.return_value = None
-
- with task_manager.acquire(self.context,
- self.node.uuid) as task:
- self.driver.console.stop_console(task)
-
- mock_exec.assert_called_once_with(self.node.uuid)
-
- @mock.patch.object(console_utils, 'stop_shellinabox_console',
- autospec=True)
- def test_stop_console_fail(self, mock_stop):
- mock_stop.side_effect = exception.ConsoleError()
-
- with task_manager.acquire(self.context,
- self.node.uuid) as task:
- self.assertRaises(exception.ConsoleError,
- self.driver.console.stop_console,
- task)
-
- mock_stop.assert_called_once_with(self.node.uuid)
-
- @mock.patch.object(console_utils, 'get_shellinabox_console_url',
- autospec=True)
- def test_get_console(self, mock_exec):
- url = 'http://localhost:4201'
- mock_exec.return_value = url
- expected = {'type': 'shellinabox', 'url': url}
-
- with task_manager.acquire(self.context,
- self.node.uuid) as task:
- task.node.driver_info['ssh_terminal_port'] = 6900
- console_info = self.driver.console.get_console(task)
-
- self.assertEqual(expected, console_info)
- mock_exec.assert_called_once_with(6900)
diff --git a/ironic/tests/unit/drivers/test_pxe.py b/ironic/tests/unit/drivers/test_pxe.py
index 4471cf002..fb5d1a194 100644
--- a/ironic/tests/unit/drivers/test_pxe.py
+++ b/ironic/tests/unit/drivers/test_pxe.py
@@ -35,7 +35,6 @@ from ironic.drivers.modules.irmc import power as irmc_power
from ironic.drivers.modules import iscsi_deploy
from ironic.drivers.modules import pxe as pxe_module
from ironic.drivers.modules import snmp
-from ironic.drivers.modules import ssh
from ironic.drivers.modules.ucs import management as ucs_management
from ironic.drivers.modules.ucs import power as ucs_power
from ironic.drivers import pxe
@@ -43,16 +42,6 @@ from ironic.drivers import pxe
class PXEDriversTestCase(testtools.TestCase):
- def test_pxe_ssh_driver(self):
- driver = pxe.PXEAndSSHDriver()
-
- self.assertIsInstance(driver.power, ssh.SSHPower)
- self.assertIsInstance(driver.boot, pxe_module.PXEBoot)
- self.assertIsInstance(driver.deploy, iscsi_deploy.ISCSIDeploy)
- self.assertIsInstance(driver.management, ssh.SSHManagement)
- self.assertIsNone(driver.inspect)
- self.assertIsInstance(driver.raid, agent.AgentRAID)
-
@mock.patch.object(pxe.importutils, 'try_import', spec_set=True,
autospec=True)
def test_pxe_ilo_driver(self, try_import_mock):
diff --git a/releasenotes/notes/no-ssh-drivers-6ee5ff4c3ecdd3fb.yaml b/releasenotes/notes/no-ssh-drivers-6ee5ff4c3ecdd3fb.yaml
new file mode 100644
index 000000000..ac8cbba92
--- /dev/null
+++ b/releasenotes/notes/no-ssh-drivers-6ee5ff4c3ecdd3fb.yaml
@@ -0,0 +1,9 @@
+---
+upgrade:
+ - |
+ SSH-based power and management driver interfaces were removed from ironic.
+ The drivers ``pxe_ssh``, ``agent_ssh`` and ``fake_ssh`` are no longer
+ available.
+ Operators are required to ensure that these drivers are not used
+ or enabled (in ``[DEFAULT]enabled_drivers`` configuration file option)
+ in their ironic installation before upgrade.
diff --git a/requirements.txt b/requirements.txt
index 6e82d0fce..908e99e60 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,7 +7,6 @@ alembic>=0.8.10 # MIT
automaton>=0.5.0 # Apache-2.0
eventlet!=0.18.3,!=0.20.1,<0.21.0,>=0.18.2 # MIT
WebOb>=1.7.1 # MIT
-paramiko>=2.0 # LGPLv2.1+
python-cinderclient>=3.1.0 # Apache-2.0
python-neutronclient>=6.3.0 # Apache-2.0
python-glanceclient>=2.7.0 # Apache-2.0
diff --git a/setup.cfg b/setup.cfg
index f4419fc53..4c4e7a40a 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -50,7 +50,6 @@ ironic.drivers =
agent_ipmitool_socat = ironic.drivers.ipmi:AgentAndIPMIToolAndSocatDriver
agent_irmc = ironic.drivers.irmc:IRMCVirtualMediaAgentDriver
agent_pxe_oneview = ironic.drivers.oneview:AgentPXEOneViewDriver
- agent_ssh = ironic.drivers.agent:AgentAndSSHDriver
agent_ucs = ironic.drivers.agent:AgentAndUcsDriver
fake = ironic.drivers.fake:FakeDriver
fake_soft_power = ironic.drivers.fake:FakeSoftPowerDriver
@@ -58,7 +57,6 @@ ironic.drivers =
fake_inspector = ironic.drivers.fake:FakeIPMIToolInspectorDriver
fake_ipmitool = ironic.drivers.fake:FakeIPMIToolDriver
fake_ipmitool_socat = ironic.drivers.fake:FakeIPMIToolSocatDriver
- fake_ssh = ironic.drivers.fake:FakeSSHDriver
fake_pxe = ironic.drivers.fake:FakePXEDriver
fake_ilo = ironic.drivers.fake:FakeIloDriver
fake_drac = ironic.drivers.fake:FakeDracDriver
@@ -72,7 +70,6 @@ ironic.drivers =
iscsi_pxe_oneview = ironic.drivers.oneview:ISCSIPXEOneViewDriver
pxe_ipmitool = ironic.drivers.ipmi:PXEAndIPMIToolDriver
pxe_ipmitool_socat = ironic.drivers.ipmi:PXEAndIPMIToolAndSocatDriver
- pxe_ssh = ironic.drivers.pxe:PXEAndSSHDriver
pxe_ilo = ironic.drivers.pxe:PXEAndIloDriver
pxe_drac = ironic.drivers.drac:PXEDracDriver
pxe_drac_inspector = ironic.drivers.drac:PXEDracInspectorDriver
diff --git a/vagrant.yaml b/vagrant.yaml
index 055a4a9dc..7feab7ad7 100644
--- a/vagrant.yaml
+++ b/vagrant.yaml
@@ -116,7 +116,7 @@
}
- {
section: 'DEFAULT',
- option: 'enabled_drivers', value: 'pxe_ssh, agent_ssh, fake'
+ option: 'enabled_drivers', value: 'pxe_ipmitool, agent_ipmitool, fake'
# All other testing drivers require add'l packages
# and should be enabled locally, if desired
}