Merge "Update Octavia OVN SSH traffic test"
This commit is contained in:
commit
c9c17c7d56
|
@ -14,6 +14,8 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import json
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -130,34 +132,68 @@ class OctaviaOVNProviderTrafficTest(testtools.TestCase):
|
||||||
loadbalancer_id=self.loadbalancer_stack.loadbalancer_id)
|
loadbalancer_id=self.loadbalancer_stack.loadbalancer_id)
|
||||||
|
|
||||||
def test_ssh_traffic(self):
|
def test_ssh_traffic(self):
|
||||||
LOG.info('Trying to ssh each member and get its hostname.')
|
"""SSH every member server to get its hostname using a load balancer
|
||||||
|
"""
|
||||||
username: typing.Optional[str] = None
|
username: typing.Optional[str] = None
|
||||||
expected = set()
|
password: typing.Optional[str] = None
|
||||||
|
missing_replies = set()
|
||||||
for member_stack in [self.member1_stack, self.member2_stack]:
|
for member_stack in [self.member1_stack, self.member2_stack]:
|
||||||
ssh_client = member_stack.server_stack.ssh_client
|
ssh_client = member_stack.server_stack.ssh_client
|
||||||
expected.add(sh.get_hostname(ssh_client=ssh_client))
|
hostname = sh.get_hostname(ssh_client=ssh_client)
|
||||||
|
missing_replies.add(hostname)
|
||||||
if username is None:
|
if username is None:
|
||||||
username = ssh_client.setup_connect_parameters()['username']
|
username = member_stack.server_stack.username
|
||||||
else:
|
else:
|
||||||
self.assertEqual(
|
self.assertEqual(username,
|
||||||
username,
|
member_stack.server_stack.username,
|
||||||
ssh_client.setup_connect_parameters()['username'],
|
"Not all member servers have the same "
|
||||||
"Member servers don't have the same "
|
"username to login with")
|
||||||
"username to login with")
|
if password is None:
|
||||||
|
password = member_stack.server_stack.password
|
||||||
|
else:
|
||||||
|
self.assertEqual(password,
|
||||||
|
member_stack.server_stack.password,
|
||||||
|
"Not all member servers have the same "
|
||||||
|
"password to login with")
|
||||||
|
|
||||||
|
# Get SSH client to the load balancer virtual IP
|
||||||
ssh_client = ssh.ssh_client(
|
ssh_client = ssh.ssh_client(
|
||||||
host=self.loadbalancer_stack.floating_ip_address,
|
host=self.loadbalancer_stack.floating_ip_address,
|
||||||
username=username)
|
port=self.listener_stack.lb_port,
|
||||||
|
username=username,
|
||||||
|
password=password)
|
||||||
|
|
||||||
actual = set()
|
replies = []
|
||||||
for attempt in tobiko.retry(timeout=120.):
|
for attempt in tobiko.retry(timeout=120.):
|
||||||
|
LOG.debug(f"SSH to member server by using the load balancer "
|
||||||
|
f"(login='{ssh_client.login}', attempt={attempt})...")
|
||||||
|
|
||||||
with ssh_client: # disconnect after every loop
|
with ssh_client: # disconnect after every loop
|
||||||
actual.add(sh.ssh_hostname(ssh_client=ssh_client))
|
hostname = sh.ssh_hostname(ssh_client=ssh_client)
|
||||||
unexpected = actual - expected
|
try:
|
||||||
if unexpected:
|
missing_replies.remove(hostname)
|
||||||
self.fail(f'Unexpected hostname: {unexpected}')
|
except KeyError:
|
||||||
elif expected == actual:
|
self.assertIn(hostname, replies,
|
||||||
|
f"Unexpected hostname reached: {hostname}")
|
||||||
|
replies.append(hostname)
|
||||||
|
if missing_replies:
|
||||||
|
LOG.debug('Reached member server(s):\n'
|
||||||
|
f'{pretty_replies(replies)}')
|
||||||
|
if attempt.is_last:
|
||||||
|
self.fail('Unreached member server(s): '
|
||||||
|
f'{missing_replies}')
|
||||||
|
else:
|
||||||
|
LOG.debug('Waiting for reaching remaining server(s)... '
|
||||||
|
f'{missing_replies}')
|
||||||
|
else:
|
||||||
|
LOG.debug('All member servers reached:\n'
|
||||||
|
f'{pretty_replies(replies)}')
|
||||||
break
|
break
|
||||||
elif attempt.is_last:
|
else:
|
||||||
self.fail(f'Unreached host(s): {expected - actual}')
|
raise RuntimeError('Broken retry loop')
|
||||||
|
|
||||||
|
|
||||||
|
def pretty_replies(replies: typing.Iterable[str]):
|
||||||
|
return json.dumps(collections.Counter(replies),
|
||||||
|
indent=4,
|
||||||
|
sort_keys=True)
|
||||||
|
|
Loading…
Reference in New Issue