From 3d9895cc0b6b9e41cdc5cc389d10504cd31ffa9d Mon Sep 17 00:00:00 2001
From: Pavlo Shchelokovskyy <pshchelokovskyy@mirantis.com>
Date: Fri, 7 Jul 2017 18:23:02 +0300
Subject: [PATCH] Remove SSH-based driver interfaces and drivers

SSH drivers are being unsupported for about a year now. All current
stable branches of ironic are officially supporting IPMI-capable HW
simulation via virtualbmc.
All ironic-related gate jobs have already been switched
to not use or enable those drivers.

This patch finally removes SSH-based power and managemtnt driver interfaces
and all classic drivers using those from ironic code and documentation.
Related exceptions and `ssh_connect` function, together with dependency
on `paramiko` package are removed as well.

Change-Id: Ieda7249b9cd78e3be1eff37804996295fc8d3969
Closes-Bug: #1570301
Depends-On: I9b60c9fa24652e9e64e787cd4e5b0152f51e7a28
---
 devstack/lib/ironic                           |   79 +-
 doc/source/admin/drivers.rst                  |    9 -
 doc/source/admin/drivers/ilo.rst              |    4 +-
 doc/source/admin/drivers/oneview.rst          |    2 +-
 doc/source/admin/drivers/xenserver.rst        |   41 -
 doc/source/admin/inspection.rst               |    2 -
 doc/source/admin/report.txt                   |    7 -
 doc/source/contributor/dev-quickstart.rst     |    5 +-
 .../ironic-multitenant-networking.rst         |    5 +-
 doc/source/install/get_started.rst            |    3 +-
 doc/source/install/standalone.rst             |    2 +-
 etc/ironic/ironic.conf.sample                 |   19 -
 ironic/common/exception.py                    |    8 -
 ironic/common/utils.py                        |   41 -
 ironic/conf/__init__.py                       |    2 -
 ironic/conf/opts.py                           |    2 -
 ironic/conf/ssh.py                            |   38 -
 ironic/drivers/agent.py                       |   27 -
 ironic/drivers/fake.py                        |   13 -
 ironic/drivers/modules/ssh.py                 |  902 ------------
 ironic/drivers/pxe.py                         |   27 -
 ironic/tests/unit/api/v1/test_nodes.py        |    4 +-
 ironic/tests/unit/conductor/test_manager.py   |   16 -
 ironic/tests/unit/db/utils.py                 |   28 -
 .../unit/drivers/modules/test_inspector.py    |    4 +-
 ironic/tests/unit/drivers/modules/test_ssh.py | 1247 -----------------
 ironic/tests/unit/drivers/test_pxe.py         |   11 -
 .../no-ssh-drivers-6ee5ff4c3ecdd3fb.yaml      |    9 +
 requirements.txt                              |    1 -
 setup.cfg                                     |    3 -
 vagrant.yaml                                  |    2 +-
 31 files changed, 25 insertions(+), 2538 deletions(-)
 delete mode 100644 doc/source/admin/drivers/xenserver.rst
 delete mode 100644 ironic/conf/ssh.py
 delete mode 100644 ironic/drivers/modules/ssh.py
 delete mode 100644 ironic/tests/unit/drivers/modules/test_ssh.py
 create mode 100644 releasenotes/notes/no-ssh-drivers-6ee5ff4c3ecdd3fb.yaml

diff --git a/devstack/lib/ironic b/devstack/lib/ironic
index e6e2645854..b9dfada646 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``,
@@ -1603,13 +1592,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 \
@@ -1913,54 +1895,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
@@ -2125,10 +2059,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
         sudo install -g $LIBVIRT_GROUP -o $STACK_USER -m 644 $FILES/${IRONIC_WHOLEDISK_IMAGE_NAME}.img $IRONIC_HTTP_DIR
     fi
@@ -2144,13 +2074,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 eef6e503ec..ac1d3a6544 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 295aa418ce..7e945b6843 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 07e2b1e6b8..3a9e0da443 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 e866059d34..0000000000
--- 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 f517b3476b..1611d60ae8 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 6160705793..fb5aa8ad8b 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 f9c0566dca..f9f48ca896 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 afbaa8ce86..df091c0b84 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 c394b297a9..3ab9d7b5e4 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 16c6bbc22e..7a12d159cd 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 e82e15fd5e..be3c1327a5 100644
--- a/etc/ironic/ironic.conf.sample
+++ b/etc/ironic/ironic.conf.sample
@@ -3520,25 +3520,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 745d01b1cd..f619b5b12a 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 c6085d74ed..963e1d2f86 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 d490ecb7e3..d6f85efce6 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 bf522c17b6..b8e2c9d033 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 4ae4aabc13..0000000000
--- 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 6a34723569..75502fd5dd 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 441ed4a16f..d43f83def9 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 5b4aa0627a..0000000000
--- 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 f21db501e4..3fff137e46 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 02c2be9ba2..9ded998ea4 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 dda03594cf..7873b4ff76 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 75f6469a11..7c5244d3e2 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 bcd197b4c8..73b1abcb07 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 008c0a8b07..0000000000
--- 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 4471cf0028..fb5d1a1943 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 0000000000..ac8cbba92f
--- /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 41494be9ce..30d5e67b6a 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 f04ebc0b8e..7b00393eeb 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 055a4a9dc6..7feab7ad77 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
           }