[VM] refactor wait_for_ping

Old error message was awful in case of ip is icmp down.

In this patch:
 * Method `wait_for` is replaced by `wait_for_statuses`, since `wait_for` is
   deprecated and will be removed in near future;
 * Representation of ready statuses for TimeoutException is changed(
   example: `to become set(['ok', 'success']) -> `to become ('ok', 'success')`)
 * All logic related to `host` is moved to separate class, since it is just
   a helper and doesn't relate to VMUtils class and scenarios.

Error message before this patch:
   Rally tired waiting for IPAddress IPAddress('172.24.4.16'):<no id> to become ICMP UP current status NONE

After:
   Rally tired waiting for Host ip:172.24.4.16 to become ('ICMP UP') current status ICMP DOWN

Change-Id: I4d950bfd097731611188dc7f302fedbb83669a39
This commit is contained in:
Andrey Kurilin 2015-12-04 10:55:06 +02:00
parent 1863ac6a69
commit d90ab5e8b5
2 changed files with 115 additions and 92 deletions

View File

@ -32,9 +32,6 @@ from rally.task import validation
LOG = logging.getLogger(__name__)
ICMP_UP_STATUS = "ICMP UP"
ICMP_DOWN_STATUS = "ICMP DOWN"
VM_BENCHMARK_OPTS = [
cfg.FloatOpt("vm_ping_poll_interval", default=1.0,
help="Interval between checks when waiting for a VM to "
@ -47,6 +44,49 @@ benchmark_group = cfg.OptGroup(name="benchmark", title="benchmark options")
CONF.register_opts(VM_BENCHMARK_OPTS, group=benchmark_group)
class Host(object):
ICMP_UP_STATUS = "ICMP UP"
ICMP_DOWN_STATUS = "ICMP DOWN"
name = "ip"
def __init__(self, ip):
self.ip = netaddr.IPAddress(ip)
self.status = self.ICMP_DOWN_STATUS
@property
def id(self):
return self.ip.format()
@classmethod
def update_status(cls, server):
"""Check ip address is pingable and update status."""
ping = "ping" if server.ip.version == 4 else "ping6"
if sys.platform.startswith("linux"):
cmd = [ping, "-c1", "-w1", server.ip.format()]
else:
cmd = [ping, "-c1", server.ip.format()]
proc = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
proc.wait()
LOG.debug("Host %s is ICMP %s"
% (server.ip.format(), proc.returncode and "down" or "up"))
if proc.returncode == 0:
server.status = cls.ICMP_UP_STATUS
else:
server.status = cls.ICMP_DOWN_STATUS
return server
def __eq__(self, other):
if not isinstance(other, Host):
raise TypeError("%s should be an instance of %s" % (
other, Host.__class__.__name__))
return self.ip == other.ip and self.status == other.status
class VMScenario(nova_utils.NovaScenario, cinder_utils.CinderScenario):
"""Base class for VM scenarios with basic atomic actions.
@ -158,10 +198,11 @@ class VMScenario(nova_utils.NovaScenario, cinder_utils.CinderScenario):
@atomic.action_timer("vm.wait_for_ping")
def _wait_for_ping(self, server_ip):
server_ip = netaddr.IPAddress(server_ip)
utils.wait_for(
server_ip,
is_ready=utils.resource_is(ICMP_UP_STATUS, self._ping_ip_address),
server = Host(server_ip)
utils.wait_for_status(
server,
ready_statuses=[Host.ICMP_UP_STATUS],
update_resource=Host.update_status,
timeout=CONF.benchmark.vm_ping_timeout,
check_interval=CONF.benchmark.vm_ping_poll_interval
)
@ -191,23 +232,3 @@ class VMScenario(nova_utils.NovaScenario, cinder_utils.CinderScenario):
pkey=pkey, password=password)
self._wait_for_ssh(ssh)
return self._run_command_over_ssh(ssh, command)
@staticmethod
def _ping_ip_address(host):
"""Check ip address that it is pingable.
:param host: instance of `netaddr.IPAddress`
"""
ping = "ping" if host.version == 4 else "ping6"
if sys.platform.startswith("linux"):
cmd = [ping, "-c1", "-w1", str(host)]
else:
cmd = [ping, "-c1", str(host)]
proc = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
proc.wait()
LOG.debug("Host %s is ICMP %s"
% (host, proc.returncode and "down" or "up"))
return ICMP_UP_STATUS if (proc.returncode == 0) else ICMP_DOWN_STATUS

View File

@ -112,13 +112,12 @@ class VMScenarioTestCase(test.ScenarioTestCase):
vm_scenario = utils.VMScenario(self.context)
vm_scenario._ping_ip_address = mock.Mock(return_value=True)
vm_scenario._wait_for_ping(netaddr.IPAddress("1.2.3.4"))
self.mock_wait_for.mock.assert_called_once_with(
netaddr.IPAddress("1.2.3.4"),
is_ready=self.mock_resource_is.mock.return_value,
self.mock_wait_for_status.mock.assert_called_once_with(
utils.Host("1.2.3.4"),
ready_statuses=[utils.Host.ICMP_UP_STATUS],
update_resource=utils.Host.update_status,
timeout=CONF.benchmark.vm_ping_timeout,
check_interval=CONF.benchmark.vm_ping_poll_interval)
self.mock_resource_is.mock.assert_called_once_with(
"ICMP UP", vm_scenario._ping_ip_address)
@mock.patch(VMTASKS_UTILS + ".VMScenario._run_command_over_ssh")
@mock.patch("rally.common.sshutils.SSH")
@ -137,66 +136,6 @@ class VMScenarioTestCase(test.ScenarioTestCase):
mock_sshutils_ssh.return_value,
{"script_file": "foo", "interpreter": "bar"})
@mock.patch(VMTASKS_UTILS + ".sys")
@mock.patch("subprocess.Popen")
def test__ping_ip_address_linux(self, mock_popen, mock_sys):
mock_popen.return_value.returncode = 0
mock_sys.platform = "linux2"
vm_scenario = utils.VMScenario(self.context)
host_ip = netaddr.IPAddress("1.2.3.4")
self.assertTrue(vm_scenario._ping_ip_address(host_ip))
mock_popen.assert_called_once_with(
["ping", "-c1", "-w1", str(host_ip)],
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
mock_popen.return_value.wait.assert_called_once_with()
@mock.patch(VMTASKS_UTILS + ".sys")
@mock.patch("subprocess.Popen")
def test__ping_ip_address_linux_ipv6(self, mock_popen, mock_sys):
mock_popen.return_value.returncode = 0
mock_sys.platform = "linux2"
vm_scenario = utils.VMScenario(self.context)
host_ip = netaddr.IPAddress("1ce:c01d:bee2:15:a5:900d:a5:11fe")
self.assertTrue(vm_scenario._ping_ip_address(host_ip))
mock_popen.assert_called_once_with(
["ping6", "-c1", "-w1", str(host_ip)],
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
mock_popen.return_value.wait.assert_called_once_with()
@mock.patch(VMTASKS_UTILS + ".sys")
@mock.patch("subprocess.Popen")
def test__ping_ip_address_other_os(self, mock_popen, mock_sys):
mock_popen.return_value.returncode = 0
mock_sys.platform = "freebsd10"
vm_scenario = utils.VMScenario(self.context)
host_ip = netaddr.IPAddress("1.2.3.4")
self.assertTrue(vm_scenario._ping_ip_address(host_ip))
mock_popen.assert_called_once_with(
["ping", "-c1", str(host_ip)],
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
mock_popen.return_value.wait.assert_called_once_with()
@mock.patch(VMTASKS_UTILS + ".sys")
@mock.patch("subprocess.Popen")
def test__ping_ip_address_other_os_ipv6(self, mock_popen, mock_sys):
mock_popen.return_value.returncode = 0
mock_sys.platform = "freebsd10"
vm_scenario = utils.VMScenario(self.context)
host_ip = netaddr.IPAddress("1ce:c01d:bee2:15:a5:900d:a5:11fe")
self.assertTrue(vm_scenario._ping_ip_address(host_ip))
mock_popen.assert_called_once_with(
["ping6", "-c1", str(host_ip)],
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
mock_popen.return_value.wait.assert_called_once_with()
def get_scenario(self):
server = mock.Mock(
networks={"foo_net": "foo_data"},
@ -308,3 +247,66 @@ class VMScenarioTestCase(test.ScenarioTestCase):
mock_wrap.assert_called_once_with(scenario.clients, scenario)
mock_wrap.return_value.delete_floating_ip.assert_called_once_with(
"foo_id", wait=True)
class HostTestCase(test.TestCase):
@mock.patch(VMTASKS_UTILS + ".sys")
@mock.patch("subprocess.Popen")
def test__ping_ip_address_linux(self, mock_popen, mock_sys):
mock_popen.return_value.returncode = 0
mock_sys.platform = "linux2"
host = utils.Host("1.2.3.4")
self.assertEqual(utils.Host.ICMP_UP_STATUS,
utils.Host.update_status(host).status)
mock_popen.assert_called_once_with(
["ping", "-c1", "-w1", str(host.ip)],
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
mock_popen.return_value.wait.assert_called_once_with()
@mock.patch(VMTASKS_UTILS + ".sys")
@mock.patch("subprocess.Popen")
def test__ping_ip_address_linux_ipv6(self, mock_popen, mock_sys):
mock_popen.return_value.returncode = 0
mock_sys.platform = "linux2"
host = utils.Host("1ce:c01d:bee2:15:a5:900d:a5:11fe")
self.assertEqual(utils.Host.ICMP_UP_STATUS,
utils.Host.update_status(host).status)
mock_popen.assert_called_once_with(
["ping6", "-c1", "-w1", str(host.ip)],
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
mock_popen.return_value.wait.assert_called_once_with()
@mock.patch(VMTASKS_UTILS + ".sys")
@mock.patch("subprocess.Popen")
def test__ping_ip_address_other_os(self, mock_popen, mock_sys):
mock_popen.return_value.returncode = 0
mock_sys.platform = "freebsd10"
host = utils.Host("1.2.3.4")
self.assertEqual(utils.Host.ICMP_UP_STATUS,
utils.Host.update_status(host).status)
mock_popen.assert_called_once_with(
["ping", "-c1", str(host.ip)],
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
mock_popen.return_value.wait.assert_called_once_with()
@mock.patch(VMTASKS_UTILS + ".sys")
@mock.patch("subprocess.Popen")
def test__ping_ip_address_other_os_ipv6(self, mock_popen, mock_sys):
mock_popen.return_value.returncode = 0
mock_sys.platform = "freebsd10"
host = utils.Host("1ce:c01d:bee2:15:a5:900d:a5:11fe")
self.assertEqual(utils.Host.ICMP_UP_STATUS,
utils.Host.update_status(host).status)
mock_popen.assert_called_once_with(
["ping6", "-c1", str(host.ip)],
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
mock_popen.return_value.wait.assert_called_once_with()