def test_get_hostname_with_no_cached(self): ssh_client = self.mock_ssh_client() hostname = sh.get_hostname(ssh_client=ssh_client, cached=False) self.assertEqual('mocked-hostname', hostname) self.assertIsNot(hostname, sh.get_hostname(ssh_client=ssh_client, cached=False))
def _add_node(self, addresses: typing.List[netaddr.IPAddress], hostname: str = None, ssh_client: typing.Optional[ssh.SSHClientFixture] = None): if ssh_client is None: ssh_client = self._ssh_connect(addresses=addresses) addresses.extend(self._list_addresses_from_host(ssh_client=ssh_client)) addresses = tobiko.select(remove_duplications(addresses)) hostname = hostname or sh.get_hostname(ssh_client=ssh_client) name = node_name_from_hostname(hostname) try: node = self._names[name] except KeyError: LOG.debug("Add topology node:\n" f" - name: {name}\n" f" - hostname: {hostname}\n" f" - login: {ssh_client.login}\n" f" - addresses: {addresses}\n") self._names[name] = node = self.create_node(name=name, hostname=hostname, ssh_client=ssh_client, addresses=addresses) for address in addresses: address_node = self._addresses.setdefault(address, node) if address_node is not node: LOG.error(f"Address '{address}' of node '{name}' is already " f"used by node '{address_node.name}'") return node
def test_wait_with_timeout(self): # assume there are always to be running processes on host process = sh.list_processes(pid=1, **self.parameters).unique ex = self.assertRaises(sh.PsWaitTimeout, process.wait, timeout=3.) self.assertEqual(3., ex.timeout) self.assertEqual(sh.get_hostname(ssh_client=self.ssh_client), ex.hostname)
def test_hostname(self, expect_hostname=None, **execute_params): hostname = sh.get_hostname(**execute_params) self.assertIsInstance(hostname, six.string_types) if expect_hostname: self.assertEqual(expect_hostname, hostname) else: self.assertNotEqual('', hostname)
def test_undercloud_group(self): ssh_client = tripleo.undercloud_ssh_client() name = sh.get_hostname(ssh_client=ssh_client).split('.')[0] node = self.topology.get_node(name) self.assertIs(node.ssh_client, ssh_client) self.assertEqual(name, node.name) nodes = self.topology.get_group('undercloud') self.assertEqual([node], nodes)
def test_hostnames(self): hostnames = dict() for node in self.topology.nodes: hostname = sh.get_hostname(ssh_client=node.ssh_client) self.assertTrue(hostname.startswith(node.name)) other = hostnames.setdefault(hostname, node) if node is not other: tobiko.fail(f"Nodes {node.name} and {other.name} have the " f"same hostname: {hostname}")
def test_wait_for_processes_timeout(self): # assume there are always to be running processes on host ex = self.assertRaises(sh.PsWaitTimeout, sh.wait_for_processes, pid=1, timeout=3., **self.parameters) self.assertEqual(3., ex.timeout) self.assertEqual(sh.get_hostname(ssh_client=self.ssh_client), ex.hostname)
def test_undercloud_group(self): ssh_client = undercloud.undercloud_ssh_client() name = sh.get_hostname(ssh_client=ssh_client).split('.')[0] node = self.topology.get_node(name) self.assertIs(node.ssh_client, ssh_client) self.assertEqual(name, node.name) nodes = self.topology.get_group('undercloud') self.assertEqual([node], nodes) host_config = undercloud.undercloud_host_config() self.assertEqual(host_config.hostname, str(node.public_ip))
def power_on_overcloud_node(self): server = self.overcloud_server if server is None: raise TypeError(f"Node {self.name} is not and Overcloud server") self.ssh_client.close() LOG.debug(f"Ensuring overcloud node {self.name} power is on...") _overcloud.power_on_overcloud_node(server) hostname = sh.get_hostname(ssh_client=self.ssh_client) LOG.debug(f"Overcloud node {self.name} power is on (" f"hostname={hostname})")
def add_host(self, ssh_client: ssh.SSHClientType, hostname: str = None): if self.diggers is None: self.diggers = collections.OrderedDict() if hostname is None: hostname = sh.get_hostname(ssh_client=ssh_client) digger = self.diggers.get(hostname) if digger is None: self.diggers[hostname] = digger = self.file_digger_class( filename=self.filename, ssh_client=ssh_client, pattern=self.pattern, **self.execute_params) return digger
def test_overcloud_group(self): for server in tripleo.list_overcloud_nodes(): ssh_client = tripleo.overcloud_ssh_client(server.name) name = sh.get_hostname(ssh_client=ssh_client).split('.')[0] node = self.topology.get_node(name) self.assertIs(node.ssh_client, ssh_client) self.assertEqual(name, node.name) groups = ['overcloud'] group = name.split('-', 1)[0] if group != name: groups.append(group) for group in groups: nodes = self.topology.get_group(group) self.assertIn(node, nodes) self.assertIn(group, node.groups) host_config = tripleo.overcloud_host_config(name) self.assertEqual(host_config.hostname, str(node.public_ip))
def test_servers_creation(stack=TestServerCreationStack, number_of_servers=2) -> \ tobiko.Selection[_nova.ServerStackFixture]: initial_servers_ids = {server.id for server in nova.list_servers()} pid = os.getpid() fixture_obj = tobiko.get_fixture_class(stack) # Get list of server stack instances fixtures: tobiko.Selection[_nova.ServerStackFixture] = tobiko.select( tobiko.get_fixture(fixture_obj, fixture_id=f'{pid}-{i}') for i in range(number_of_servers or 1)) test_case = tobiko.get_test_case() # Check fixtures types for fixture in fixtures: test_case.assertIsInstance(fixture, _nova.ServerStackFixture) # Delete all servers stacks for fixture in fixtures: tobiko.cleanup_fixture(fixture) # Create all servers stacks for fixture in fixtures: tobiko.use_fixture(fixture) # Check every server ID is unique and new server_ids = {fixture.server_id for fixture in fixtures} test_case.assertEqual(number_of_servers or 1, len(server_ids)) test_case.assertFalse(server_ids & initial_servers_ids) # sleep for 20 sec , ensure no race condition with ssh time.sleep(20) # Test SSH connectivity to floating IP address for fixture in fixtures: test_case.assertTrue(sh.get_hostname(ssh_client=fixture.ssh_client)) # Test pinging to floating IP address ping.assert_reachable_hosts(fixture.floating_ip_address for fixture in fixtures) return fixtures
def add_node(self, hostname: typing.Optional[str] = None, address: typing.Optional[str] = None, group: typing.Optional[str] = None, ssh_client: typing.Optional[ssh.SSHClientFixture] = None) \ -> OpenStackTopologyNode: if ssh_client is not None: # detect all global addresses from remote server try: hostname = sh.get_hostname(ssh_client=ssh_client) except Exception: LOG.exception("Unable to get node hostname from " f"{ssh_client}") ssh_client = None name = hostname and node_name_from_hostname(hostname) or None addresses: typing.List[netaddr.IPAddress] = [] if address: # add manually configure addresses first addresses.extend(self._list_addresses(address)) if hostname: # detect more addresses from the hostname addresses.extend(self._list_addresses(hostname)) addresses = tobiko.select(remove_duplications(addresses)) try: node = self.get_node(name=name, address=addresses) except _exception.NoSuchOpenStackTopologyNode: node = None node = node or self._add_node( addresses=addresses, hostname=hostname, ssh_client=ssh_client) if group: # Add group anyway even if the node hasn't been added group_nodes = self.add_group(group=group) if node and node not in group_nodes: group_nodes.append(node) node.add_group(group=group) return node
def _add_node(self, ips, hostname=None, ssh_client=None): public_ip = self._public_ip(ips, ssh_client=ssh_client) if public_ip is None: LOG.debug("Unable to SSH connect to any node IP address: %s" ','.join(str(ip_address) for ip_address in ips)) return None # I need to get a name for the new node ssh_client = ssh_client or self._ssh_client(public_ip) hostname = hostname or sh.get_hostname(ssh_client=ssh_client) name = node_name_from_hostname(hostname) try: node = self._nodes_by_name[name] except KeyError: self._nodes_by_name[name] = node = self.create_node( name=name, public_ip=public_ip, ssh_client=ssh_client) other = self._nodes_by_ips.setdefault(public_ip, node) if node is not other: LOG.error("Two nodes have the same IP address (%s): %r, %r", public_ip, node.name, other.name) return node
def wait_for_cloud_init_status( *expected_states: str, transient_states: typing.Optional[typing.Container[str]] = None, ssh_client: typing.Optional[ssh.SSHClientFixture] = None, timeout: tobiko.Seconds = None, sleep_interval: tobiko.Seconds = None) \ -> str: hostname = sh.get_hostname(ssh_client=ssh_client, timeout=timeout) if transient_states is None: transient_states = list() for status in expected_states: transient_states += CLOUD_INIT_TRANSIENT_STATES.get(status, []) def _read_file(filename: str, tail=False) -> str: return read_file(filename=filename, ssh_client=ssh_client, timeout=timeout, tail=tail) actual_status: typing.Optional[str] for attempt in tobiko.retry(timeout=timeout, interval=sleep_interval, default_timeout=1200., default_interval=5.): try: actual_status = get_cloud_init_status(ssh_client=ssh_client, timeout=attempt.time_left) except sh.ShellCommandFailed: LOG.exception('Unable to get cloud-init status') actual_status = None else: if actual_status in expected_states: break if attempt.is_last: raise WaitForCloudInitTimeoutError( timeout=attempt.timeout, hostname=hostname, actual_status=actual_status, expected_states=expected_states, log_file=_read_file(CLOUD_INIT_LOG_FILE), output_file=_read_file(CLOUD_INIT_OUTPUT_FILE)) elif actual_status in transient_states: last_log_lines = _read_file(CLOUD_INIT_LOG_FILE, tail=True) LOG.debug(f"Waiting cloud-init status on host '{hostname}' to " f"switch from '{actual_status}' to any of expected " f"states ({', '.join(expected_states)}):\n\n" f"--- {CLOUD_INIT_LOG_FILE} ---\n" f"{last_log_lines}\n\n") else: raise InvalidCloudInitStatusError( hostname=hostname, actual_status=actual_status, expected_states=expected_states, log_file=_read_file(CLOUD_INIT_LOG_FILE), output_file=_read_file(CLOUD_INIT_OUTPUT_FILE)) else: raise RuntimeError('Broken retry loop') return actual_status
def test_get_hostname_with_no_ssh_client(self): hostname = sh.get_hostname(ssh_client=False) self.assertEqual(socket.gethostname(), hostname)
def test_get_hostname_with_ssh_client(self): ssh_client = self.mock_ssh_client() hostname = sh.get_hostname(ssh_client=ssh_client) self.assertEqual('mocked-hostname', hostname) self.assertIs(hostname, sh.get_hostname(ssh_client=ssh_client))
def test_ssh_client(self): for node in self.topology.nodes: self.assertIsNotNone(node.ssh_client) hostname = sh.get_hostname( ssh_client=node.ssh_client).split('.')[0] self.assertEqual(node.name, hostname)
def test_get_hostname_with_ssh_proxy(self): ssh_client = self.mock_ssh_client() self.patch(ssh, 'ssh_client_fixture', return_value=ssh_client) hostname = sh.get_hostname(ssh_client=None) self.assertEqual('mocked-hostname', hostname)
def test_ssh_traffic(self): """SSH every member server to get its hostname using a load balancer """ username: typing.Optional[str] = None password: typing.Optional[str] = None missing_replies = set() for member_server in [ self.listener_stack.server_stack, self.listener_stack.other_server_stack ]: ssh_client = member_server.ssh_client hostname = sh.get_hostname(ssh_client=ssh_client) missing_replies.add(hostname) if username is None: username = member_server.username else: self.assertEqual( username, member_server.username, "Not all member servers have the same " "username to login with") if password is None: password = member_server.password else: self.assertEqual( password, member_server.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( host=self.loadbalancer_stack.floating_ip_address, port=self.listener_stack.lb_port, username=username, password=password) replies = [] for attempt in tobiko.retry(timeout=120.): LOG.debug(f"SSH to member server by using the load balancer " f"(login='******', attempt={attempt})...") with ssh_client: # disconnect after every loop hostname = sh.ssh_hostname(ssh_client=ssh_client) try: missing_replies.remove(hostname) except KeyError: 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): {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 else: raise RuntimeError('Broken retry loop')
def hostname(self) -> str: return sh.get_hostname(ssh_client=self.ssh_client)
def test_ssh(self): """Test SSH connectivity to floating IP address""" hostname = sh.get_hostname(ssh_client=self.stack.ssh_client) self.assertEqual(self.stack.server_name.lower(), hostname)