Merge "Adds scenario for DNS-nameserver configuration"
This commit is contained in:
commit
20f3743b43
|
@ -920,6 +920,11 @@
|
|||
# operations testing. (integer value)
|
||||
#large_ops_number = 0
|
||||
|
||||
# DHCP client used by images to renew DCHP lease. If left empty,
|
||||
# update operation will be skipped. Supported clients: "udhcpc",
|
||||
# "dhclient" (string value)
|
||||
#dhcp_client = udhcpc
|
||||
|
||||
|
||||
[service_available]
|
||||
|
||||
|
|
|
@ -97,6 +97,10 @@ class RemoteClient():
|
|||
cmd = "/bin/ip addr | awk '/ether/ {print $2}'"
|
||||
return self.exec_command(cmd)
|
||||
|
||||
def get_nic_name(self, address):
|
||||
cmd = "/bin/ip -o addr | awk '/%s/ {print $2}'" % address
|
||||
return self.exec_command(cmd)
|
||||
|
||||
def get_ip_list(self):
|
||||
cmd = "/bin/ip address"
|
||||
return self.exec_command(cmd)
|
||||
|
@ -116,3 +120,47 @@ class RemoteClient():
|
|||
# Get pid(s) of a process/program
|
||||
cmd = "ps -ef | grep %s | grep -v 'grep' | awk {'print $1'}" % pr_name
|
||||
return self.exec_command(cmd).split('\n')
|
||||
|
||||
def get_dns_servers(self):
|
||||
cmd = 'cat /etc/resolv.conf'
|
||||
resolve_file = self.exec_command(cmd).strip().split('\n')
|
||||
entries = (l.split() for l in resolve_file)
|
||||
dns_servers = [l[1] for l in entries
|
||||
if len(l) and l[0] == 'nameserver']
|
||||
return dns_servers
|
||||
|
||||
def send_signal(self, pid, signum):
|
||||
cmd = 'sudo /bin/kill -{sig} {pid}'.format(pid=pid, sig=signum)
|
||||
return self.exec_command(cmd)
|
||||
|
||||
def _renew_lease_udhcpc(self, fixed_ip=None):
|
||||
"""Renews DHCP lease via udhcpc client. """
|
||||
file_path = '/var/run/udhcpc.'
|
||||
nic_name = self.get_nic_name(fixed_ip)
|
||||
nic_name = nic_name.strip().lower()
|
||||
pid = self.exec_command('cat {path}{nic}.pid'.
|
||||
format(path=file_path, nic=nic_name))
|
||||
pid = pid.strip()
|
||||
self.send_signal(pid, 'USR1')
|
||||
|
||||
def _renew_lease_dhclient(self, fixed_ip=None):
|
||||
"""Renews DHCP lease via dhclient client. """
|
||||
cmd = "sudo /sbin/dhclient -r && /sbin/dhclient"
|
||||
self.exec_command(cmd)
|
||||
|
||||
def renew_lease(self, fixed_ip=None):
|
||||
"""Wrapper method for renewing DHCP lease via given client
|
||||
|
||||
Supporting:
|
||||
* udhcpc
|
||||
* dhclient
|
||||
"""
|
||||
# TODO(yfried): add support for dhcpcd
|
||||
suported_clients = ['udhcpc', 'dhclient']
|
||||
dhcp_client = CONF.scenario.dhcp_client
|
||||
if dhcp_client not in suported_clients:
|
||||
raise exceptions.InvalidConfiguration('%s DHCP client unsupported'
|
||||
% dhcp_client)
|
||||
if dhcp_client == 'udhcpc' and not fixed_ip:
|
||||
raise ValueError("need to set 'fixed_ip' for udhcpc client")
|
||||
return getattr(self, '_renew_lease_' + dhcp_client)(fixed_ip=fixed_ip)
|
|
@ -860,7 +860,14 @@ ScenarioGroup = [
|
|||
'large_ops_number',
|
||||
default=0,
|
||||
help="specifies how many resources to request at once. Used "
|
||||
"for large operations testing.")
|
||||
"for large operations testing."),
|
||||
# TODO(yfried): add support for dhcpcd
|
||||
cfg.StrOpt('dhcp_client',
|
||||
default='udhcpc',
|
||||
choices=["udhcpc", "dhclient"],
|
||||
help='DHCP client used by images to renew DCHP lease. '
|
||||
'If left empty, update operation will be skipped. '
|
||||
'Supported clients: "udhcpc", "dhclient"')
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -1012,12 +1012,16 @@ class NetworkScenarioTest(ScenarioTest):
|
|||
router.update(admin_state_up=admin_state_up)
|
||||
self.assertEqual(admin_state_up, router.admin_state_up)
|
||||
|
||||
def create_networks(self, client=None, tenant_id=None):
|
||||
def create_networks(self, client=None, tenant_id=None,
|
||||
dns_nameservers=None):
|
||||
"""Create a network with a subnet connected to a router.
|
||||
|
||||
The baremetal driver is a special case since all nodes are
|
||||
on the same shared network.
|
||||
|
||||
:param client: network client to create resources with.
|
||||
:param tenant_id: id of tenant to create resources in.
|
||||
:param dns_nameservers: list of dns servers to send to subnet.
|
||||
:returns: network, subnet, router
|
||||
"""
|
||||
if CONF.baremetal.driver_enabled:
|
||||
|
@ -1033,7 +1037,12 @@ class NetworkScenarioTest(ScenarioTest):
|
|||
else:
|
||||
network = self._create_network(client=client, tenant_id=tenant_id)
|
||||
router = self._get_router(client=client, tenant_id=tenant_id)
|
||||
subnet = self._create_subnet(network=network, client=client)
|
||||
|
||||
subnet_kwargs = dict(network=network, client=client)
|
||||
# use explicit check because empty list is a valid option
|
||||
if dns_nameservers is not None:
|
||||
subnet_kwargs['dns_nameservers'] = dns_nameservers
|
||||
subnet = self._create_subnet(**subnet_kwargs)
|
||||
subnet.add_to_router(router.id)
|
||||
return network, subnet, router
|
||||
|
||||
|
|
|
@ -100,10 +100,10 @@ class TestNetworkBasicOps(manager.NetworkScenarioTest):
|
|||
self.keypairs = {}
|
||||
self.servers = []
|
||||
|
||||
def _setup_network_and_servers(self):
|
||||
def _setup_network_and_servers(self, **kwargs):
|
||||
self.security_group = \
|
||||
self._create_security_group(tenant_id=self.tenant_id)
|
||||
self.network, self.subnet, self.router = self.create_networks()
|
||||
self.network, self.subnet, self.router = self.create_networks(**kwargs)
|
||||
self.check_networks()
|
||||
|
||||
name = data_utils.rand_name('server-smoke')
|
||||
|
@ -425,3 +425,62 @@ class TestNetworkBasicOps(manager.NetworkScenarioTest):
|
|||
self.check_public_network_connectivity(
|
||||
should_connect=True, msg="after updating "
|
||||
"admin_state_up of router to True")
|
||||
|
||||
def _check_dns_server(self, ssh_client, dns_servers):
|
||||
servers = ssh_client.get_dns_servers()
|
||||
self.assertEqual(set(dns_servers), set(servers),
|
||||
'Looking for servers: {trgt_serv}. '
|
||||
'Retrieved DNS nameservers: {act_serv} '
|
||||
'From host: {host}.'
|
||||
.format(host=ssh_client.ssh_client.host,
|
||||
act_serv=servers,
|
||||
trgt_serv=dns_servers))
|
||||
|
||||
@testtools.skipUnless(CONF.scenario.dhcp_client,
|
||||
"DHCP client is not available.")
|
||||
@test.attr(type='smoke')
|
||||
@test.services('compute', 'network')
|
||||
def test_subnet_details(self):
|
||||
"""Tests that subnet's extra configuration details are affecting
|
||||
the VMs
|
||||
|
||||
NOTE: Neutron subnets push data to servers via dhcp-agent, so any
|
||||
update in subnet requires server to actively renew its DHCP lease.
|
||||
|
||||
1. Configure subnet with dns nameserver
|
||||
2. retrieve the VM's configured dns and verify it matches the one
|
||||
configured for the subnet.
|
||||
3. update subnet's dns
|
||||
4. retrieve the VM's configured dns and verify it matches the new one
|
||||
configured for the subnet.
|
||||
|
||||
TODO(yfried): add host_routes
|
||||
|
||||
any resolution check would be testing either:
|
||||
* l3 forwarding (tested in test_network_basic_ops)
|
||||
* Name resolution of an external DNS nameserver - out of scope for
|
||||
Tempest
|
||||
"""
|
||||
# this test check only updates (no actual resolution) so using
|
||||
# arbitrary ip addresses as nameservers, instead of parsing CONF
|
||||
initial_dns_server = '1.2.3.4'
|
||||
alt_dns_server = '9.8.7.6'
|
||||
self._setup_network_and_servers(dns_nameservers=[initial_dns_server])
|
||||
self.check_public_network_connectivity(should_connect=True)
|
||||
|
||||
floating_ip, server = self.floating_ip_tuple
|
||||
ip_address = floating_ip.floating_ip_address
|
||||
private_key = self._get_server_key(server)
|
||||
ssh_client = self._ssh_to_server(ip_address, private_key)
|
||||
|
||||
self._check_dns_server(ssh_client, [initial_dns_server])
|
||||
|
||||
self.subnet.update(dns_nameservers=[alt_dns_server])
|
||||
# asserts that Neutron DB has updated the nameservers
|
||||
self.assertEqual([alt_dns_server], self.subnet.dns_nameservers,
|
||||
"Failed to update subnet's nameservers")
|
||||
|
||||
# server needs to renew its dhcp lease in order to get the new dns
|
||||
# definitions from subnet
|
||||
ssh_client.renew_lease(fixed_ip=floating_ip['fixed_ip_address'])
|
||||
self._check_dns_server(ssh_client, [alt_dns_server])
|
||||
|
|
|
@ -82,8 +82,10 @@ class DeletableSubnet(DeletableResource):
|
|||
self._router_ids = set()
|
||||
|
||||
def update(self, *args, **kwargs):
|
||||
result = self.client.update_subnet(subnet=self.id, *args, **kwargs)
|
||||
super(DeletableSubnet, self).update(**result['subnet'])
|
||||
result = self.client.update_subnet(self.id,
|
||||
*args,
|
||||
**kwargs)
|
||||
return super(DeletableSubnet, self).update(**result['subnet'])
|
||||
|
||||
def add_to_router(self, router_id):
|
||||
self._router_ids.add(router_id)
|
||||
|
|
Loading…
Reference in New Issue