diff options
author | Rex Lee <limingjiang@huawei.com> | 2017-07-28 08:29:29 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@opnfv.org> | 2017-07-28 08:29:29 +0000 |
commit | 355601ab1b2335550905574148b097292f214325 (patch) | |
tree | 083b4c2544edf1fc35912a369f7d46a3fa3e4a5c | |
parent | cf68baf48f43ebb70b1fb137fd4f1a5bbbc1e0df (diff) | |
parent | fd0a88140f7114ef90fabdfb5436cff42ec0cd2c (diff) |
Merge "Test Case: OPNFV_YARDSTICK_TC023: VM availability during live migration"
32 files changed, 1428 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore index a53b53390..d98b4a070 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ build htmlcov .agignore .coverage +*.retry Session*.vim .tags* .coverage.* diff --git a/ansible/inventory.ini b/ansible/inventory.ini index 440e625bd..79a6ee0aa 100644 --- a/ansible/inventory.ini +++ b/ansible/inventory.ini @@ -1,8 +1,11 @@ [controller] host1 ansible_host=10.1.0.50 ansible_user=root ansible_ssh_pass=root host2 ansible_host=10.1.0.51 ansible_user=root ansible_ssh_pass=root -host3 ansible_host=10.1.0.52 ansible_user=root ansible_ssh_pass=root [compute] host4 ansible_host=10.1.0.53 ansible_user=root ansible_ssh_pass=root host5 ansible_host=10.1.0.54 ansible_user=root ansible_ssh_pass=root + +[nodes:children] +controller +compute diff --git a/ansible/migrate_pinning_setup.yaml b/ansible/migrate_pinning_setup.yaml new file mode 100644 index 000000000..ee5eef3ff --- /dev/null +++ b/ansible/migrate_pinning_setup.yaml @@ -0,0 +1,49 @@ +--- +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +- hosts: localhost + roles: + - create_flavor + - role: set_flavor_property + key: "hw:cpu_policy" + value: "dedicated" + - role: set_flavor_property + key: "hw:numa_nodes" + value: "1" + +- hosts: nodes + roles: + - backup_nova_conf + - role: set_nova_conf + section: "DEFAULT" + key: "live_migration_flag" + value: "VIR_MIGRATE_UNDEFINE_SOURCE,VIR_MIGRATE_PEER2PEER,VIR_MIGRATE_LIVE,VIR_MIGRATE_TUNNELLED" + - role: set_nova_conf + section: "DEFAULT" + key: "vncserver_listen" + value: "0.0.0.0" + +- hosts: controller + roles: + - role: set_nova_conf + section: "DEFAULT" + key: "scheduler_default_filters" + value: "NUMATopologyFilter" + - role: restart_nova_service + service: "nova-scheduler" + +- hosts: compute + roles: + - role: set_nova_conf + section: "DEFAULT" + key: "vcpu_pin_set" + value: "{{ cpu_set }}" + - role: restart_nova_service + service: "nova-compute" diff --git a/ansible/migrate_pinning_teardown.yaml b/ansible/migrate_pinning_teardown.yaml new file mode 100644 index 000000000..13dd6113c --- /dev/null +++ b/ansible/migrate_pinning_teardown.yaml @@ -0,0 +1,31 @@ +--- +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +- hosts: localhost + roles: + - delete_flavor + +- hosts: nodes + roles: + - recover_nova_conf + +- hosts: controller + roles: + - role: restart_nova_service + service: "nova-scheduler" + - role: restart_nova_service + service: "nova-api" + - role: restart_nova_service + service: "nova-conductor" + +- hosts: compute + roles: + - role: restart_nova_service + service: "nova-compute" diff --git a/ansible/roles/backup_nova_conf/tasks/main.yaml b/ansible/roles/backup_nova_conf/tasks/main.yaml new file mode 100644 index 000000000..ca95bac59 --- /dev/null +++ b/ansible/roles/backup_nova_conf/tasks/main.yaml @@ -0,0 +1,18 @@ +--- +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +- name: backup nova.conf file + copy: + src: /etc/nova/nova.conf + dest: /tmp/nova.conf + owner: nova + group: nova + remote_src: True + become: true diff --git a/ansible/roles/create_flavor/tasks/main.yaml b/ansible/roles/create_flavor/tasks/main.yaml new file mode 100644 index 000000000..9b776c694 --- /dev/null +++ b/ansible/roles/create_flavor/tasks/main.yaml @@ -0,0 +1,16 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +- name: create flavor {{ flavor }} + os_nova_flavor: + cloud: opnfv + state: present + name: "{{ flavor }}" + ram: "{{ ram }}" + vcpus: "{{ vcpus }}" + disk: "{{ disk }}" diff --git a/ansible/roles/delete_flavor/tasks/main.yaml b/ansible/roles/delete_flavor/tasks/main.yaml new file mode 100644 index 000000000..dc9fc88ce --- /dev/null +++ b/ansible/roles/delete_flavor/tasks/main.yaml @@ -0,0 +1,13 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +- name: delete flavor {{ flavor }} + os_nova_flavor: + cloud: opnfv + state: absent + name: "{{ flavor }}" diff --git a/ansible/roles/recover_nova_conf/tasks/main.yaml b/ansible/roles/recover_nova_conf/tasks/main.yaml new file mode 100644 index 000000000..44919d2ae --- /dev/null +++ b/ansible/roles/recover_nova_conf/tasks/main.yaml @@ -0,0 +1,18 @@ +--- +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +- name: recover nova.conf file + copy: + src: /tmp/nova.conf + dest: /etc/nova/nova.conf + owner: nova + group: nova + remote_src: True + become: true diff --git a/ansible/roles/restart_nova_service/tasks/main.yaml b/ansible/roles/restart_nova_service/tasks/main.yaml new file mode 100644 index 000000000..2bdce652d --- /dev/null +++ b/ansible/roles/restart_nova_service/tasks/main.yaml @@ -0,0 +1,23 @@ +--- +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +- name: restart "{{ service }}" service + service: + name: "{{ service }}" + state: restarted + become: true + when: ansible_os_family == "Debian" + +- name: restart "openstack-{{ service }}" service + service: + name: "openstack-{{ service }}" + state: restarted + become: true + when: ansible_os_family == "RedHat" diff --git a/ansible/roles/set_flavor_property/tasks/main.yaml b/ansible/roles/set_flavor_property/tasks/main.yaml new file mode 100644 index 000000000..f98988783 --- /dev/null +++ b/ansible/roles/set_flavor_property/tasks/main.yaml @@ -0,0 +1,14 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +- name: set flavor "{{ flavor }}" property {{ key }} = {{ value }} + shell: + source /etc/yardstick/openstack.creds; + openstack flavor set --property {{ key }}={{ value }} {{ flavor }}; + args: + executable: /bin/bash diff --git a/ansible/roles/set_nova_conf/tasks/main.yaml b/ansible/roles/set_nova_conf/tasks/main.yaml new file mode 100644 index 000000000..ae665c5d0 --- /dev/null +++ b/ansible/roles/set_nova_conf/tasks/main.yaml @@ -0,0 +1,17 @@ +--- +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +- name: set "{{ key }}" value + ini_file: + dest: /etc/nova/nova.conf + section: "{{ section }}" + option: "{{ key }}" + value: "{{ value }}" + become: true diff --git a/etc/yardstick/nodes/compass_sclab_virtual/pod.yaml b/etc/yardstick/nodes/compass_sclab_virtual/pod.yaml index 5c5574005..e306d0d94 100644 --- a/etc/yardstick/nodes/compass_sclab_virtual/pod.yaml +++ b/etc/yardstick/nodes/compass_sclab_virtual/pod.yaml @@ -20,30 +20,35 @@ nodes: - name: node1 + host_name: host1 role: Controller ip: 10.1.0.50 user: root password: root - name: node2 + host_name: host2 role: Controller ip: 10.1.0.51 user: root password: root - name: node3 + host_name: host3 role: Controller ip: 10.1.0.52 user: root password: root - name: node4 + host_name: host4 role: Compute ip: 10.1.0.53 user: root password: root - name: node5 + host_name: host5 role: Compute ip: 10.1.0.54 user: root diff --git a/requirements.txt b/requirements.txt index 3a4cbce0c..2bcc4dfa7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -59,6 +59,7 @@ oslo.utils==3.22.0 paramiko==2.1.1 pbr==1.10.0 pep8==1.7.0 +ping==0.2; python_version <= '2.7' pika==0.10.0 positional==1.1.1 prettytable==0.7.2 diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc023.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc023.yaml new file mode 100644 index 000000000..2804f25a2 --- /dev/null +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc023.yaml @@ -0,0 +1,176 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +--- + +schema: "yardstick:task:0.1" + +{% set file = file or "etc/yardstick/nodes/compass_sclab_virtual/pod.yaml" %} +{% set cpu_set = cpu_set or "0,1,2,3" %} +{% set memory_load = memory_load or 0 %} + +{% set flavor = flavor or "yardstick-migrate-flavor" %} +{% set ram = ram or "2048" %} +{% set vcpus = vcpus or "2" %} +{% set disk = disk or "3" %} + +scenarios: +- + type: GetServer + + output: status server + + host: server.migrate + + runner: + type: Iteration + iteration: 1 +- + type: GetNumaInfo + + options: + server: $server + file: {{ file }} + + output: origin_numa_info + + host: server.migrate + + runner: + type: Iteration + iteration: 1 +- + type: GetMigrateTargetHost + + options: + server: $server + output: target_host + + runner: + type: Iteration + iteration: 1 +- + type: GetServerIp + + options: + server: $server + + output: server_ip + + runner: + type: Iteration + iteration: 1 +- + type: AddMemoryLoad + + options: + memory_load: {{ memory_load }} + + host: server.migrate + + runner: + type: Iteration + iteration: 1 +- + type: Migrate + + options: + server: $server + host: $target_host + server_ip: $server_ip + + output: status migrate_time1 downtime1 + + runner: + type: Iteration + iteration: 1 +- + type: CheckValue + + options: + value1: $status + value2: 0 + operator: eq + + runner: + type: Iteration + iteration: 1 +- + type: GetServer + + output: status server + + host: server.migrate + + runner: + type: Iteration + iteration: 1 +- + type: GetNumaInfo + + options: + server: $server + file: {{ file }} + + output: new_numa_info + + host: server.migrate + + runner: + type: Iteration + iteration: 1 +- + type: CheckNumaInfo + + options: + info1: $origin_numa_info + info2: $new_numa_info + cpu_set: {{ cpu_set }} + + output: status + + runner: + type: Iteration + iteration: 1 +- + type: CheckValue + + options: + value1: $status + value2: true + operator: eq + + runner: + type: Iteration + iteration: 1 + + +contexts: +- + type: Node + name: env-prepare + file: {{ file }} + + env: + type: ansible + setup: migrate_pinning_setup.yaml -e "flavor={{ flavor }} ram={{ ram }} vcpus={{ vcpus }} disk={{ disk }} cpu_set={{ cpu_set }}" + teardown: migrate_pinning_teardown.yaml -e "flavor={{ flavor }}" + +- + name: migrate + image: yardstick-image + flavor: {{ flavor }} + user: ubuntu + + servers: + server: + floating_ip: true + + networks: + test: + cidr: '10.0.1.0/24' diff --git a/tests/unit/benchmark/scenarios/lib/__init__.py b/tests/unit/benchmark/scenarios/lib/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/__init__.py diff --git a/tests/unit/benchmark/scenarios/lib/test_add_memory_load.py b/tests/unit/benchmark/scenarios/lib/test_add_memory_load.py new file mode 100644 index 000000000..bda07f723 --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_add_memory_load.py @@ -0,0 +1,65 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import unittest +import mock + +from yardstick.benchmark.scenarios.lib.add_memory_load import AddMemoryLoad + + +class AddMemoryLoadTestCase(unittest.TestCase): + + @mock.patch('yardstick.ssh.SSH.from_node') + def test_add_memory_load_with_load(self, mock_from_node): + scenario_cfg = { + 'options': { + 'memory_load': 0.5 + } + } + context_cfg = { + 'host': {} + } + mock_from_node().execute.return_value = (0, '0 2048 512', '') + obj = AddMemoryLoad(scenario_cfg, context_cfg) + obj.run({}) + self.assertTrue(mock_from_node.called) + + @mock.patch('yardstick.ssh.SSH.from_node') + def test_add_memory_load_without_load(self, mock_from_node): + scenario_cfg = { + 'options': { + 'memory_load': 0 + } + } + context_cfg = { + 'host': {} + } + obj = AddMemoryLoad(scenario_cfg, context_cfg) + obj.run({}) + self.assertTrue(mock_from_node.called) + + @mock.patch('yardstick.ssh.SSH.from_node') + def test_add_memory_load_without_args(self, mock_from_node): + scenario_cfg = { + 'options': { + } + } + context_cfg = { + 'host': {} + } + obj = AddMemoryLoad(scenario_cfg, context_cfg) + obj.run({}) + self.assertTrue(mock_from_node.called) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_check_numa_info.py b/tests/unit/benchmark/scenarios/lib/test_check_numa_info.py new file mode 100644 index 000000000..bdf1e66e5 --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_check_numa_info.py @@ -0,0 +1,84 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import unittest +import mock + +from yardstick.benchmark.scenarios.lib.check_numa_info import CheckNumaInfo + + +class CheckNumaInfoTestCase(unittest.TestCase): + + @mock.patch('yardstick.benchmark.scenarios.lib.check_numa_info.CheckNumaInfo._check_vm2_status') + def test_check_numa_info(self, mock_check_vm2): + scenario_cfg = {'info1': {}, 'info2': {}} + obj = CheckNumaInfo(scenario_cfg, {}) + obj.run({}) + self.assertTrue(mock_check_vm2.called) + + def test_check_vm2_status_length_eq_1(self): + info1 = { + 'pinning': [0], + 'vcpupin': [{ + 'cpuset': '1,2' + }] + } + info2 = { + 'pinning': [0], + 'vcpupin': [{ + 'cpuset': '1,2' + }] + } + scenario_cfg = {'info1': info1, 'info2': info2} + obj = CheckNumaInfo(scenario_cfg, {}) + status = obj._check_vm2_status(info1, info2) + self.assertEqual(status, True) + + def test_check_vm2_status_length_gt_1(self): + info1 = { + 'pinning': [0, 1], + 'vcpupin': [{ + 'cpuset': '1,2' + }] + } + info2 = { + 'pinning': [0, 1], + 'vcpupin': [{ + 'cpuset': '1,2' + }] + } + scenario_cfg = {'info1': info1, 'info2': info2} + obj = CheckNumaInfo(scenario_cfg, {}) + status = obj._check_vm2_status(info1, info2) + self.assertEqual(status, False) + + def test_check_vm2_status_length_not_in_set(self): + info1 = { + 'pinning': [0], + 'vcpupin': [{ + 'cpuset': '1,7' + }] + } + info2 = { + 'pinning': [0], + 'vcpupin': [{ + 'cpuset': '1,7' + }] + } + scenario_cfg = {'info1': info1, 'info2': info2} + obj = CheckNumaInfo(scenario_cfg, {}) + status = obj._check_vm2_status(info1, info2) + self.assertEqual(status, False) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_check_value.py b/tests/unit/benchmark/scenarios/lib/test_check_value.py new file mode 100644 index 000000000..21e83f830 --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_check_value.py @@ -0,0 +1,46 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import unittest + +from yardstick.benchmark.scenarios.lib.check_value import CheckValue + + +class CheckValueTestCase(unittest.TestCase): + + def test_check_value_eq(self): + scenario_cfg = {'options': {'operator': 'eq', 'value1': 1, 'value2': 2}} + obj = CheckValue(scenario_cfg, {}) + try: + obj.run({}) + except Exception as e: + self.assertIsInstance(e, AssertionError) + + def test_check_value_eq_pass(self): + scenario_cfg = {'options': {'operator': 'eq', 'value1': 1, 'value2': 1}} + obj = CheckValue(scenario_cfg, {}) + try: + obj.run({}) + except Exception as e: + self.assertIsInstance(e, AssertionError) + + def test_check_value_ne(self): + scenario_cfg = {'options': {'operator': 'ne', 'value1': 1, 'value2': 1}} + obj = CheckValue(scenario_cfg, {}) + try: + obj.run({}) + except Exception as e: + self.assertIsInstance(e, AssertionError) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py b/tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py new file mode 100644 index 000000000..f046c92ea --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py @@ -0,0 +1,51 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import unittest +import mock + +from yardstick.benchmark.scenarios.lib.get_migrate_target_host import GetMigrateTargetHost + +BASE = 'yardstick.benchmark.scenarios.lib.get_migrate_target_host' + + +class GetMigrateTargetHostTestCase(unittest.TestCase): + + @mock.patch('{}.openstack_utils.get_nova_client'.format(BASE)) + @mock.patch('{}.GetMigrateTargetHost._get_migrate_host'.format(BASE)) + @mock.patch('{}.GetMigrateTargetHost._get_current_host_name'.format(BASE)) + def test_get_migrate_target_host(self, + mock_get_current_host_name, + mock_get_migrate_host, + mock_get_nova_client): + obj = GetMigrateTargetHost({}, {}) + obj.run({}) + self.assertTrue(mock_get_nova_client.called) + self.assertTrue(mock_get_current_host_name.called) + self.assertTrue(mock_get_migrate_host.called) + + @mock.patch('{}.openstack_utils.get_nova_client'.format(BASE)) + def test_get_migrate_host(self, mock_get_nova_client): + class A(object): + def __init__(self, service): + self.service = service + self.host = 'host4' + + mock_get_nova_client().hosts.list_all.return_value = [A('compute')] + obj = GetMigrateTargetHost({}, {}) + host = obj._get_migrate_host('host5') + self.assertTrue(mock_get_nova_client.called) + self.assertEqual(host, 'host4') + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py b/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py new file mode 100644 index 000000000..e7ba3ca73 --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py @@ -0,0 +1,106 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import unittest +import mock + +from yardstick.benchmark.scenarios.lib.get_numa_info import GetNumaInfo + +BASE = 'yardstick.benchmark.scenarios.lib.get_numa_info' + + +class GetNumaInfoTestCase(unittest.TestCase): + + @mock.patch('{}.GetNumaInfo._check_numa_node'.format(BASE)) + @mock.patch('{}.GetNumaInfo._get_current_host_name'.format(BASE)) + @mock.patch('yaml.safe_load') + @mock.patch('yardstick.common.task_template.TaskTemplate.render') + def test_get_numa_info(self, + mock_render, + mock_safe_load, + mock_get_current_host_name, + mock_check_numa_node): + scenario_cfg = { + 'options': { + 'server': { + 'id': '1' + }, + 'file': 'yardstick/ssh.py' + }, + 'output': 'numa_info' + } + mock_safe_load.return_value = { + 'nodes': [] + } + obj = GetNumaInfo(scenario_cfg, {}) + obj.run({}) + self.assertTrue(mock_get_current_host_name.called) + self.assertTrue(mock_check_numa_node.called) + + @mock.patch('yardstick.ssh.SSH.from_node') + @mock.patch('{}.GetNumaInfo._get_current_host_name'.format(BASE)) + @mock.patch('yaml.safe_load') + @mock.patch('yardstick.common.task_template.TaskTemplate.render') + def test_check_numa_node(self, + mock_render, + mock_safe_load, + mock_get_current_host_name, + mock_from_node): + scenario_cfg = { + 'options': { + 'server': { + 'id': '1' + }, + 'file': 'yardstick/ssh.py' + }, + 'output': 'numa_info' + } + mock_safe_load.return_value = { + 'nodes': [] + } + data = """ + <data> + </data> + """ + mock_from_node().execute.return_value = (0, data, '') + obj = GetNumaInfo(scenario_cfg, {}) + result = obj._check_numa_node('1', 'host4') + self.assertEqual(result, {'pinning': [], 'vcpupin': []}) + + @mock.patch('{}.change_obj_to_dict'.format(BASE)) + @mock.patch('{}.get_nova_client'.format(BASE)) + @mock.patch('yaml.safe_load') + @mock.patch('yardstick.common.task_template.TaskTemplate.render') + def test_get_current_host_name(self, + mock_render, + mock_safe_load, + mock_get_nova_client, + mock_change_obj_to_dict): + scenario_cfg = { + 'options': { + 'server': { + 'id': '1' + }, + 'file': 'yardstick/ssh.py' + }, + 'output': 'numa_info' + } + mock_get_nova_client().servers.get.return_value = '' + mock_change_obj_to_dict.return_value = {'OS-EXT-SRV-ATTR:host': 'host5'} + + obj = GetNumaInfo(scenario_cfg, {}) + result = obj._get_current_host_name('1') + self.assertEqual(result, 'host5') + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_get_server.py b/tests/unit/benchmark/scenarios/lib/test_get_server.py new file mode 100644 index 000000000..aebbf5416 --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_get_server.py @@ -0,0 +1,50 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import unittest +import mock + +from yardstick.benchmark.scenarios.lib.get_server import GetServer + + +class GetServerTestCase(unittest.TestCase): + + @mock.patch('yardstick.common.openstack_utils.get_server_by_name') + @mock.patch('yardstick.common.openstack_utils.get_nova_client') + def test_get_server_with_name(self, mock_get_nova_client, mock_get_server_by_name): + scenario_cfg = { + 'options': { + 'server_name': 'yardstick_server' + }, + 'output': 'status server' + } + obj = GetServer(scenario_cfg, {}) + obj.run({}) + self.assertTrue(mock_get_nova_client.called) + self.assertTrue(mock_get_server_by_name.called) + + @mock.patch('yardstick.common.openstack_utils.get_nova_client') + def test_get_server_with_id(self, mock_get_nova_client): + scenario_cfg = { + 'options': { + 'server_id': '1' + }, + 'output': 'status server' + } + mock_get_nova_client().servers.get.return_value = None + obj = GetServer(scenario_cfg, {}) + obj.run({}) + self.assertTrue(mock_get_nova_client.called) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/tests/unit/benchmark/scenarios/lib/test_get_server_ip.py b/tests/unit/benchmark/scenarios/lib/test_get_server_ip.py new file mode 100644 index 000000000..3d20d5439 --- /dev/null +++ b/tests/unit/benchmark/scenarios/lib/test_get_server_ip.py @@ -0,0 +1,41 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +import unittest + +from yardstick.benchmark.scenarios.lib.get_server_ip import GetServerIp + + +class GetServerIpTestCase(unittest.TestCase): + def test_get_server_ip(self): + scenario_cfg = { + 'options': { + 'server': { + 'addresses': { + 'net1': [ + { + 'OS-EXT-IPS:type': 'floating', + 'addr': '127.0.0.1' + } + ] + } + } + }, + 'output': 'ip' + } + obj = GetServerIp(scenario_cfg, {}) + result = obj.run({}) + self.assertEqual(result, {'ip': '127.0.0.1'}) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/yardstick/benchmark/scenarios/base.py b/yardstick/benchmark/scenarios/base.py index 5d3c36c38..3cb138dd8 100644 --- a/yardstick/benchmark/scenarios/base.py +++ b/yardstick/benchmark/scenarios/base.py @@ -63,3 +63,15 @@ class Scenario(object): return scenario.__module__ + "." + scenario.__name__ raise RuntimeError("No such scenario type %s" % scenario_type) + + def _push_to_outputs(self, keys, values): + return dict(zip(keys, values)) + + def _change_obj_to_dict(self, obj): + dic = {} + for k, v in vars(obj).items(): + try: + vars(v) + except TypeError: + dic[k] = v + return dic diff --git a/yardstick/benchmark/scenarios/lib/__init__.py b/yardstick/benchmark/scenarios/lib/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/__init__.py diff --git a/yardstick/benchmark/scenarios/lib/add_memory_load.py b/yardstick/benchmark/scenarios/lib/add_memory_load.py new file mode 100644 index 000000000..26cf140d1 --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/add_memory_load.py @@ -0,0 +1,57 @@ +# ############################################################################ +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# ############################################################################ + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +import yardstick.ssh as ssh +from yardstick.benchmark.scenarios import base + +LOG = logging.getLogger(__name__) + + +class AddMemoryLoad(base.Scenario): + """Add memory load in server + """ + + __scenario_type__ = "AddMemoryLoad" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + + self.options = scenario_cfg.get('options', {}) + + self.client = ssh.SSH.from_node(self.context_cfg['host']) + self.client.wait(timeout=600) + + def run(self, result): + self._add_load() + + def _add_load(self): + try: + memory_load = self.options['memory_load'] + except KeyError: + LOG.error('memory_load parameter must be provided') + else: + if float(memory_load) == 0: + return + cmd = 'free | awk "/Mem/ {print $2}"' + code, stdout, stderr = self.client.execute(cmd) + total = int(stdout.split()[1]) + used = int(stdout.split()[2]) + remain_memory = total * float(memory_load) - used + if remain_memory > 0: + count = remain_memory / 1024 / 128 + LOG.info('Add %s vm load', count) + if count != 0: + cmd = 'stress -t 10 -m {} --vm-keep'.format(count) + self.client.execute(cmd) diff --git a/yardstick/benchmark/scenarios/lib/check_numa_info.py b/yardstick/benchmark/scenarios/lib/check_numa_info.py new file mode 100644 index 000000000..59a47547e --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/check_numa_info.py @@ -0,0 +1,61 @@ +# ############################################################################ +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# ############################################################################ + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +from yardstick.benchmark.scenarios import base + +LOG = logging.getLogger(__name__) + + +class CheckNumaInfo(base.Scenario): + """ + Execute a live migration for two hosts + + """ + + __scenario_type__ = "CheckNumaInfo" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + + self.options = self.scenario_cfg.get('options', {}) + + self.cpu_set = self.options.get('cpu_set', '1,2,3,4,5,6') + + def run(self, result): + info1 = self.options.get('info1') + info2 = self.options.get('info2') + LOG.debug('Origin numa info: %s', info1) + LOG.debug('Current numa info: %s', info2) + status = self._check_vm2_status(info1, info2) + + keys = self.scenario_cfg.get('output', '').split() + values = [status] + return self._push_to_outputs(keys, values) + + def _check_vm2_status(self, info1, info2): + if len(info1['pinning']) != 1 or len(info2['pinning']) != 1: + return False + + for i in info1['vcpupin']: + for j in i['cpuset'].split(','): + if j not in self.cpu_set.split(','): + return False + + for i in info2['vcpupin']: + for j in i['cpuset'].split(','): + if j not in self.cpu_set.split(','): + return False + + return True diff --git a/yardstick/benchmark/scenarios/lib/check_value.py b/yardstick/benchmark/scenarios/lib/check_value.py new file mode 100644 index 000000000..759076068 --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/check_value.py @@ -0,0 +1,58 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +from yardstick.benchmark.scenarios import base + +LOG = logging.getLogger(__name__) + + +class CheckValue(base.Scenario): + """Check values between value1 and value2 + + options: + operator: equal(eq) and not equal(ne) + value1: + value2: + output: check_result + """ + + __scenario_type__ = "CheckValue" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg['options'] + + def run(self, result): + """execute the test""" + + op = self.options.get("operator") + LOG.debug("options=%s", self.options) + value1 = str(self.options.get("value1")) + value2 = str(self.options.get("value2")) + check_result = "PASS" + if op == "eq" and value1 != value2: + LOG.info("value1=%s, value2=%s, error: should equal!!!", value1, + value2) + check_result = "FAIL" + assert value1 == value2, "Error %s!=%s" % (value1, value2) + elif op == "ne" and value1 == value2: + LOG.info("value1=%s, value2=%s, error: should not equal!!!", + value1, value2) + check_result = "FAIL" + assert value1 != value2, "Error %s==%s" % (value1, value2) + LOG.info("Check result is %s", check_result) + keys = self.scenario_cfg.get('output', '').split() + values = [check_result] + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/get_migrate_target_host.py b/yardstick/benchmark/scenarios/lib/get_migrate_target_host.py new file mode 100644 index 000000000..c19d96d68 --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/get_migrate_target_host.py @@ -0,0 +1,56 @@ + +# ############################################################################ +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# ############################################################################ + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +from yardstick.common import openstack_utils +from yardstick.common.utils import change_obj_to_dict +from yardstick.benchmark.scenarios import base + +LOG = logging.getLogger(__name__) + + +class GetMigrateTargetHost(base.Scenario): + """Get a migrate target host according server + """ + + __scenario_type__ = "GetMigrateTargetHost" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + + self.options = self.scenario_cfg.get('options', {}) + default_instance_id = self.options.get('server', {}).get('id', '') + self.instance_id = self.options.get('server_id', default_instance_id) + + self.nova_client = openstack_utils.get_nova_client() + + def run(self, result): + current_host = self._get_current_host_name(self.instance_id) + target_host = self._get_migrate_host(current_host) + + keys = self.scenario_cfg.get('output', '').split() + values = [target_host] + return self._push_to_outputs(keys, values) + + def _get_current_host_name(self, server_id): + + return change_obj_to_dict(self.nova_client.servers.get(server_id))['OS-EXT-SRV-ATTR:host'] + + def _get_migrate_host(self, current_host): + hosts = self.nova_client.hosts.list_all() + compute_hosts = [a.host for a in hosts if a.service == 'compute'] + for host in compute_hosts: + if host.strip() != current_host.strip(): + return host diff --git a/yardstick/benchmark/scenarios/lib/get_numa_info.py b/yardstick/benchmark/scenarios/lib/get_numa_info.py new file mode 100644 index 000000000..4e4a44d95 --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/get_numa_info.py @@ -0,0 +1,79 @@ +# ############################################################################ +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# ############################################################################ + +from __future__ import print_function +from __future__ import absolute_import + +import logging +import os + +import yaml +from xml.etree import ElementTree as ET + +from yardstick import ssh +from yardstick.benchmark.scenarios import base +from yardstick.common import constants as consts +from yardstick.common.utils import change_obj_to_dict +from yardstick.common.openstack_utils import get_nova_client +from yardstick.common.task_template import TaskTemplate + +LOG = logging.getLogger(__name__) + + +class GetNumaInfo(base.Scenario): + """ + Execute a live migration for two hosts + + """ + + __scenario_type__ = "GetNumaInfo" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg.get('options', {}) + + server = self.options['server'] + self.server_id = server['id'] + self.host = self._get_current_host_name(self.server_id) + + node_file = os.path.join(consts.YARDSTICK_ROOT_PATH, + self.options.get('file')) + + with open(node_file) as f: + nodes = yaml.safe_load(TaskTemplate.render(f.read())) + self.nodes = {a['host_name']: a for a in nodes['nodes']} + + def run(self, result): + numa_info = self._check_numa_node(self.server_id, self.host) + + keys = self.scenario_cfg.get('output', '').split() + values = [numa_info] + return self._push_to_outputs(keys, values) + + def _get_current_host_name(self, server_id): + + return change_obj_to_dict(get_nova_client().servers.get(server_id))['OS-EXT-SRV-ATTR:host'] + + def _get_host_client(self, node_name): + self.host_client = ssh.SSH.from_node(self.nodes.get(node_name)) + self.host_client.wait(timeout=600) + + def _check_numa_node(self, server_id, host): + self._get_host_client(host) + + cmd = "sudo virsh dumpxml %s" % server_id + LOG.debug("Executing command: %s", cmd) + status, stdout, stderr = self.host_client.execute(cmd) + if status: + raise RuntimeError(stderr) + root = ET.fromstring(stdout) + vcpupin = [a.attrib for a in root.iter('vcpupin')] + pinning = [a.attrib for a in root.iter('memnode')] + return {"pinning": pinning, 'vcpupin': vcpupin} diff --git a/yardstick/benchmark/scenarios/lib/get_server.py b/yardstick/benchmark/scenarios/lib/get_server.py new file mode 100644 index 000000000..fcf47c80d --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/get_server.py @@ -0,0 +1,83 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +from yardstick.benchmark.scenarios import base +import yardstick.common.openstack_utils as op_utils + +LOG = logging.getLogger(__name__) + + +class GetServer(base.Scenario): + """Get a server instance + + Parameters + server_id - ID of the server + type: string + unit: N/A + default: null + server_name - name of the server + type: string + unit: N/A + default: null + + Either server_id or server_name is required. + + Outputs + rc - response code of getting server instance + 0 for success + 1 for failure + type: int + unit: N/A + server - instance of the server + type: dict + unit: N/A + """ + + __scenario_type__ = "GetServer" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg.get('options', {}) + + self.server_id = self.options.get("server_id") + if self.server_id: + LOG.debug('Server id is %s', self.server_id) + + default_name = self.scenario_cfg.get('host', + self.scenario_cfg.get('target')) + self.server_name = self.options.get('server_name', default_name) + if self.server_name: + LOG.debug('Server name is %s', self.server_name) + + self.nova_client = op_utils.get_nova_client() + + def run(self, result): + """execute the test""" + + if self.server_id: + server = self.nova_client.servers.get(self.server_id) + else: + server = op_utils.get_server_by_name(self.server_name) + + keys = self.scenario_cfg.get('output', '').split() + + if server: + LOG.info("Get server successful!") + values = [0, self._change_obj_to_dict(server)] + else: + LOG.info("Get server failed!") + values = [1] + + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/get_server_ip.py b/yardstick/benchmark/scenarios/lib/get_server_ip.py new file mode 100644 index 000000000..1eeeb7fca --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/get_server_ip.py @@ -0,0 +1,38 @@ +############################################################################## +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + +from __future__ import print_function +from __future__ import absolute_import + +import logging + +from yardstick.benchmark.scenarios import base + +LOG = logging.getLogger(__name__) + + +class GetServerIp(base.Scenario): + """Get a server by name""" + + __scenario_type__ = "GetServerIp" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg.get('options', {}) + self.ip_type = self.options.get('ip_type', "floating") + + def run(self, result): + server = self.options.get('server', {}) + ip = next(n['addr'] for k, v in server['addresses'].items() + for n in v if n['OS-EXT-IPS:type'] == self.ip_type) + + keys = self.scenario_cfg.get('output', '').split() + values = [ip] + return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/migrate.py b/yardstick/benchmark/scenarios/lib/migrate.py new file mode 100644 index 000000000..116bae69e --- /dev/null +++ b/yardstick/benchmark/scenarios/lib/migrate.py @@ -0,0 +1,155 @@ +# ############################################################################ +# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +# ############################################################################ + +from __future__ import print_function +from __future__ import absolute_import + +import logging +import subprocess +import threading +import time + +from datetime import datetime +import ping + +from yardstick.common import openstack_utils +from yardstick.common.utils import change_obj_to_dict +from yardstick.benchmark.scenarios import base + +LOG = logging.getLogger(__name__) + +TIMEOUT = 0.05 +PACKAGE_SIZE = 64 + + +class Migrate(base.Scenario): # pragma: no cover + """ + Execute a live migration for two hosts + + """ + + __scenario_type__ = "Migrate" + + def __init__(self, scenario_cfg, context_cfg): + self.scenario_cfg = scenario_cfg + self.context_cfg = context_cfg + self.options = self.scenario_cfg.get('options', {}) + + self.nova_client = openstack_utils.get_nova_client() + + def run(self, result): + default_instance_id = self.options.get('server', {}).get('id', '') + instance_id = self.options.get('server_id', default_instance_id) + LOG.info('Instance id is %s', instance_id) + + target_host = self.options.get('host') + LOG.info('Target host is %s', target_host) + + instance_ip = self.options.get('server_ip') + if instance_ip: + LOG.info('Instance ip is %s', instance_ip) + + self._ping_until_connected(instance_ip) + LOG.info('Instance is connected') + + LOG.debug('Start to ping instance') + ping_thread = self._do_ping_task(instance_ip) + + keys = self.scenario_cfg.get('output', '').split() + try: + LOG.info('Start to migrate') + self._do_migrate(instance_id, target_host) + except Exception as e: + return self._push_to_outputs(keys, [1, str(e).split('.')[0]]) + else: + migrate_time = self._get_migrate_time(instance_id) + LOG.info('Migration time is %s s', migrate_time) + + current_host = self._get_current_host_name(instance_id) + LOG.info('Current host is %s', current_host) + if current_host.strip() != target_host.strip(): + LOG.error('current_host not equal to target_host') + values = [1, 'current_host not equal to target_host'] + return self._push_to_outputs(keys, values) + + if instance_ip: + ping_thread.flag = False + ping_thread.join() + + downtime = ping_thread.get_delay() + LOG.info('Downtime is %s s', downtime) + + values = [0, migrate_time, downtime] + return self._push_to_outputs(keys, values) + else: + values = [0, migrate_time] + return self._push_to_outputs(keys, values) + + def _do_migrate(self, server_id, target_host): + + cmd = ['nova', 'live-migration', server_id, target_host] + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + p.communicate() + + def _ping_until_connected(self, instance_ip): + for i in range(3000): + res = ping.do_one(instance_ip, TIMEOUT, PACKAGE_SIZE) + if res: + break + + def _do_ping_task(self, instance_ip): + ping_thread = PingThread(instance_ip) + ping_thread.start() + return ping_thread + + def _get_current_host_name(self, server_id): + + return change_obj_to_dict(self.nova_client.servers.get(server_id))['OS-EXT-SRV-ATTR:host'] + + def _get_migrate_time(self, server_id): + while True: + status = self.nova_client.servers.get(server_id).status.lower() + if status == 'migrating': + start_time = datetime.now() + break + LOG.debug('Instance status change to MIGRATING') + + while True: + status = self.nova_client.servers.get(server_id).status.lower() + if status == 'active': + end_time = datetime.now() + break + if status == 'error': + LOG.error('Instance status is ERROR') + raise RuntimeError('The instance status is error') + LOG.debug('Instance status change to ACTIVE') + + duration = end_time - start_time + return duration.seconds + duration.microseconds * 1.0 / 1e6 + + +class PingThread(threading.Thread): # pragma: no cover + + def __init__(self, target): + super(PingThread, self).__init__() + self.target = target + self.flag = True + self.delay = 0.0 + + def run(self): + count = 0 + while self.flag: + res = ping.do_one(self.target, TIMEOUT, PACKAGE_SIZE) + if not res: + count += 1 + time.sleep(0.01) + self.delay = (TIMEOUT + 0.01) * count + + def get_delay(self): + return self.delay |