Consolidate the ssh code

The entire mechanism for ssh validation is a mess. The fact that there
is a parameter which is server_or_ip, so you never know if it's an
object or an address, and that every one of 7 layers need to handle
either case, makes doing any enhancements here for failure detection
impossible.

This change implements a get_server_ip method that gets the fixed or
floating IP address before passing it to the remote client.

Change-Id: I76d818bf9e1bd26b1e499464fc9213764afee279
This commit is contained in:
Sean Dague 2016-01-06 14:33:28 -05:00 committed by Joseph Lanoux
parent 5576f740b2
commit 20e9861d51
10 changed files with 56 additions and 71 deletions

View File

@ -23,6 +23,7 @@ from tempest.common import compute
from tempest.common.utils import data_utils
from tempest.common import waiters
from tempest import config
from tempest import exceptions
import tempest.test
CONF = config.CONF
@ -356,16 +357,19 @@ class BaseV2ComputeTest(api_version_utils.BaseMicroversionTest,
def get_server_ip(cls, server):
"""Get the server fixed or floating IP.
For the floating IP, the address created by the validation resources
is returned.
For the fixed IP, the server is returned and the current mechanism of
address extraction in the remote_client is followed.
Based on the configuration we're in, return a correct ip
address for validating that a guest is up.
"""
if CONF.validation.connect_method == 'floating':
ip_or_server = cls.validation_resources['floating_ip']['ip']
return cls.validation_resources['floating_ip']['ip']
elif CONF.validation.connect_method == 'fixed':
ip_or_server = server
return ip_or_server
addresses = server['addresses'][CONF.validation.network_for_ssh]
for address in addresses:
if address['version'] == CONF.validation.ip_version_for_ssh:
return address['addr']
raise exceptions.ServerUnreachable()
else:
raise exceptions.InvalidConfiguration()
class BaseV2ComputeAdminTest(BaseV2ComputeTest):

View File

@ -15,7 +15,6 @@ import re
import time
from oslo_log import log as logging
import six
from tempest_lib.common import ssh
from tempest import config
@ -28,22 +27,10 @@ LOG = logging.getLogger(__name__)
class RemoteClient(object):
# NOTE(afazekas): It should always get an address instead of server
def __init__(self, server, username, password=None, pkey=None):
def __init__(self, ip_address, username, password=None, pkey=None):
ssh_timeout = CONF.validation.ssh_timeout
network = CONF.validation.network_for_ssh
ip_version = CONF.validation.ip_version_for_ssh
connect_timeout = CONF.validation.connect_timeout
if isinstance(server, six.string_types):
ip_address = server
else:
addresses = server['addresses'][network]
for address in addresses:
if address['version'] == ip_version:
ip_address = address['addr']
break
else:
raise exceptions.ServerUnreachable()
self.ssh_client = ssh.Client(ip_address, username, password,
ssh_timeout, pkey=pkey,
channel_timeout=connect_timeout)

View File

@ -352,25 +352,15 @@ class ScenarioTest(tempest.test.BaseTestCase):
return secgroup
def get_remote_client(self, server_or_ip, username=None, private_key=None):
def get_remote_client(self, ip_address, username=None, private_key=None):
"""Get a SSH client to a remote server
@param server_or_ip a server object as returned by Tempest compute
client or an IP address to connect to
@param ip_address the server floating or fixed IP address to use
for ssh validation
@param username name of the Linux account on the remote server
@param private_key the SSH private key to use
@return a RemoteClient object
"""
if isinstance(server_or_ip, six.string_types):
ip = server_or_ip
else:
addrs = server_or_ip['addresses'][CONF.validation.network_for_ssh]
try:
ip = (addr['addr'] for addr in addrs if
netaddr.valid_ipv4(addr['addr'])).next()
except StopIteration:
raise lib_exc.NotFound("No IPv4 addresses to use for SSH to "
"remote server.")
if username is None:
username = CONF.validation.image_ssh_user
@ -383,14 +373,15 @@ class ScenarioTest(tempest.test.BaseTestCase):
else:
password = CONF.validation.image_ssh_password
private_key = None
linux_client = remote_client.RemoteClient(ip, username,
linux_client = remote_client.RemoteClient(ip_address, username,
pkey=private_key,
password=password)
try:
linux_client.validate_authentication()
except Exception as e:
message = ('Initializing SSH connection to %(ip)s failed. '
'Error: %(error)s' % {'ip': ip, 'error': e})
'Error: %(error)s' % {'ip_address': ip_address,
'error': e})
caller = misc_utils.find_test_caller()
if caller:
message = '(%s) %s' % (caller, message)
@ -628,9 +619,9 @@ class ScenarioTest(tempest.test.BaseTestCase):
floating_ip['ip'], thing['id'])
return floating_ip
def create_timestamp(self, server_or_ip, dev_name=None, mount_path='/mnt',
def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
private_key=None):
ssh_client = self.get_remote_client(server_or_ip,
ssh_client = self.get_remote_client(ip_address,
private_key=private_key)
if dev_name is not None:
ssh_client.make_fs(dev_name)
@ -643,9 +634,9 @@ class ScenarioTest(tempest.test.BaseTestCase):
ssh_client.umount(mount_path)
return timestamp
def get_timestamp(self, server_or_ip, dev_name=None, mount_path='/mnt',
def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
private_key=None):
ssh_client = self.get_remote_client(server_or_ip,
ssh_client = self.get_remote_client(ip_address,
private_key=private_key)
if dev_name is not None:
ssh_client.mount(dev_name, mount_path)
@ -655,12 +646,25 @@ class ScenarioTest(tempest.test.BaseTestCase):
ssh_client.umount(mount_path)
return timestamp
def get_server_or_ip(self, server):
def get_server_ip(self, server):
"""Get the server fixed or floating IP.
Based on the configuration we're in, return a correct ip
address for validating that a guest is up.
"""
if CONF.validation.connect_method == 'floating':
ip = self.create_floating_ip(server)['ip']
# The tests calling this method don't have a floating IP
# and can't make use of the validattion resources. So the
# method is creating the floating IP there.
return self.create_floating_ip(server)['ip']
elif CONF.validation.connect_method == 'fixed':
addresses = server['addresses'][CONF.validation.network_for_ssh]
for address in addresses:
if address['version'] == CONF.validation.ip_version_for_ssh:
return address['addr']
raise exceptions.ServerUnreachable()
else:
ip = server
return ip
raise exceptions.InvalidConfiguration()
class NetworkScenarioTest(ScenarioTest):
@ -1316,13 +1320,6 @@ class BaremetalScenarioTest(ScenarioTest):
def add_keypair(self):
self.keypair = self.create_keypair()
def verify_connectivity(self, ip=None):
if ip:
dest = self.get_remote_client(ip)
else:
dest = self.get_remote_client(self.instance)
dest.validate_authentication()
def boot_instance(self):
self.instance = self.create_server(
key_name=self.keypair['name'])

View File

@ -112,12 +112,9 @@ class BaremetalBasicOps(manager.BaremetalScenarioTest):
self.add_keypair()
self.boot_instance()
self.validate_ports()
self.verify_connectivity()
if CONF.validation.connect_method == 'floating':
floating_ip = self.create_floating_ip(self.instance)['ip']
self.verify_connectivity(ip=floating_ip)
vm_client = self.get_remote_client(self.instance)
ip_address = self.get_server_ip(self.instance)
self.get_remote_client(ip_address).validate_authentication()
vm_client = self.get_remote_client(ip_address)
# We expect the ephemeral partition to be mounted on /mnt and to have
# the same size as our flavor definition.
@ -126,6 +123,6 @@ class BaremetalBasicOps(manager.BaremetalScenarioTest):
self.verify_partition(vm_client, 'ephemeral0', '/mnt', eph_size)
# Create the test file
self.create_timestamp(
floating_ip, private_key=self.keypair['private_key'])
ip_address, private_key=self.keypair['private_key'])
self.terminate_instance()

View File

@ -124,7 +124,7 @@ class TestGettingAddress(manager.NetworkScenarioTest):
fip = self.create_floating_ip(thing=srv)
ips = self.define_server_ips(srv=srv)
ssh = self.get_remote_client(
server_or_ip=fip.floating_ip_address,
ip_address=fip.floating_ip_address,
username=username)
return ssh, ips, srv["id"]

View File

@ -75,7 +75,7 @@ class TestServerBasicOps(manager.ScenarioTest):
self.fip = self.create_floating_ip(self.instance)['ip']
# Check ssh
self.ssh_client = self.get_remote_client(
server_or_ip=self.fip,
ip_address=self.fip,
username=self.image_utils.ssh_user(self.image_ref),
private_key=keypair['private_key'])

View File

@ -80,7 +80,7 @@ class TestShelveInstance(manager.ScenarioTest):
security_groups=security_groups,
wait_until='ACTIVE')
instance_ip = self.get_server_or_ip(server)
instance_ip = self.get_server_ip(server)
timestamp = self.create_timestamp(instance_ip,
private_key=keypair['private_key'])

View File

@ -52,7 +52,7 @@ class TestSnapshotPattern(manager.ScenarioTest):
security_groups=[{'name': security_group['name']}],
wait_until='ACTIVE')
instance_ip = self.get_server_or_ip(server)
instance_ip = self.get_server_ip(server)
timestamp = self.create_timestamp(instance_ip,
private_key=keypair['private_key'])
@ -67,7 +67,7 @@ class TestSnapshotPattern(manager.ScenarioTest):
wait_until='ACTIVE')
# check the existence of the timestamp file in the second instance
server_from_snapshot_ip = self.get_server_or_ip(server_from_snapshot)
server_from_snapshot_ip = self.get_server_ip(server_from_snapshot)
timestamp2 = self.get_timestamp(server_from_snapshot_ip,
private_key=keypair['private_key'])
self.assertEqual(timestamp, timestamp2)

View File

@ -80,9 +80,9 @@ class TestStampPattern(manager.ScenarioTest):
self.assertEqual(snapshot_name, snapshot['display_name'])
return snapshot
def _wait_for_volume_available_on_the_system(self, server_or_ip,
def _wait_for_volume_available_on_the_system(self, ip_address,
private_key):
ssh = self.get_remote_client(server_or_ip, private_key=private_key)
ssh = self.get_remote_client(ip_address, private_key=private_key)
def _func():
part = ssh.get_partitions()
@ -113,7 +113,7 @@ class TestStampPattern(manager.ScenarioTest):
wait_until='ACTIVE')
# create and add floating IP to server1
ip_for_server = self.get_server_or_ip(server)
ip_for_server = self.get_server_ip(server)
self.nova_volume_attach(server, volume)
self._wait_for_volume_available_on_the_system(ip_for_server,
@ -140,7 +140,7 @@ class TestStampPattern(manager.ScenarioTest):
security_groups=security_group)
# create and add floating IP to server_from_snapshot
ip_for_snapshot = self.get_server_or_ip(server_from_snapshot)
ip_for_snapshot = self.get_server_ip(server_from_snapshot)
# attach volume2 to instance2
self.nova_volume_attach(server_from_snapshot, volume_from_snapshot)

View File

@ -114,7 +114,7 @@ class TestVolumeBootPattern(manager.ScenarioTest):
keypair, security_group)
# write content to volume on instance
ip_instance_1st = self.get_server_or_ip(instance_1st)
ip_instance_1st = self.get_server_ip(instance_1st)
timestamp = self.create_timestamp(ip_instance_1st,
private_key=keypair['private_key'])
@ -126,7 +126,7 @@ class TestVolumeBootPattern(manager.ScenarioTest):
keypair, security_group)
# check the content of written file
ip_instance_2nd = self.get_server_or_ip(instance_2nd)
ip_instance_2nd = self.get_server_ip(instance_2nd)
timestamp2 = self.get_timestamp(ip_instance_2nd,
private_key=keypair['private_key'])
self.assertEqual(timestamp, timestamp2)
@ -141,7 +141,7 @@ class TestVolumeBootPattern(manager.ScenarioTest):
keypair, security_group))
# check the content of written file
server_from_snapshot_ip = self.get_server_or_ip(server_from_snapshot)
server_from_snapshot_ip = self.get_server_ip(server_from_snapshot)
timestamp3 = self.get_timestamp(server_from_snapshot_ip,
private_key=keypair['private_key'])
self.assertEqual(timestamp, timestamp3)