1 # ############################################################################
2 # Copyright (c) 2017 Huawei Technologies Co.,Ltd and others.
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 # ############################################################################
10 from __future__ import print_function
11 from __future__ import absolute_import
18 from datetime import datetime
21 from yardstick.common import openstack_utils
22 from yardstick.common.utils import change_obj_to_dict
23 from yardstick.benchmark.scenarios import base
25 LOG = logging.getLogger(__name__)
34 # temp fix for ping module import error on Python3
35 # we need to replace the ping module anyway
37 ping = mock.MagicMock()
40 class Migrate(base.Scenario): # pragma: no cover
42 Execute a live migration for two hosts
46 __scenario_type__ = "Migrate"
48 def __init__(self, scenario_cfg, context_cfg):
49 self.scenario_cfg = scenario_cfg
50 self.context_cfg = context_cfg
51 self.options = self.scenario_cfg.get('options', {})
53 self.nova_client = openstack_utils.get_nova_client()
55 def run(self, result):
56 default_instance_id = self.options.get('server', {}).get('id', '')
57 instance_id = self.options.get('server_id', default_instance_id)
58 LOG.info('Instance id is %s', instance_id)
60 target_host = self.options.get('host')
61 LOG.info('Target host is %s', target_host)
63 instance_ip = self.options.get('server_ip')
65 LOG.info('Instance ip is %s', instance_ip)
67 self._ping_until_connected(instance_ip)
68 LOG.info('Instance is connected')
70 LOG.debug('Start to ping instance')
71 ping_thread = self._do_ping_task(instance_ip)
73 keys = self.scenario_cfg.get('output', '').split()
75 LOG.info('Start to migrate')
76 self._do_migrate(instance_id, target_host)
77 except Exception as e:
78 return self._push_to_outputs(keys, [1, str(e).split('.')[0]])
80 migrate_time = self._get_migrate_time(instance_id)
81 LOG.info('Migration time is %s s', migrate_time)
83 current_host = self._get_current_host_name(instance_id)
84 LOG.info('Current host is %s', current_host)
85 if current_host.strip() != target_host.strip():
86 LOG.error('current_host not equal to target_host')
87 values = [1, 'current_host not equal to target_host']
88 return self._push_to_outputs(keys, values)
91 ping_thread.flag = False
94 downtime = ping_thread.get_delay()
95 LOG.info('Downtime is %s s', downtime)
97 values = [0, migrate_time, downtime]
98 return self._push_to_outputs(keys, values)
100 values = [0, migrate_time]
101 return self._push_to_outputs(keys, values)
103 def _do_migrate(self, server_id, target_host):
105 cmd = ['nova', 'live-migration', server_id, target_host]
106 p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
109 def _ping_until_connected(self, instance_ip):
110 for i in range(3000):
111 res = ping.do_one(instance_ip, TIMEOUT, PACKAGE_SIZE)
115 def _do_ping_task(self, instance_ip):
116 ping_thread = PingThread(instance_ip)
120 def _get_current_host_name(self, server_id):
122 return change_obj_to_dict(self.nova_client.servers.get(server_id))['OS-EXT-SRV-ATTR:host']
124 def _get_migrate_time(self, server_id):
126 status = self.nova_client.servers.get(server_id).status.lower()
127 if status == 'migrating':
128 start_time = datetime.now()
130 LOG.debug('Instance status change to MIGRATING')
133 status = self.nova_client.servers.get(server_id).status.lower()
134 if status == 'active':
135 end_time = datetime.now()
137 if status == 'error':
138 LOG.error('Instance status is ERROR')
139 raise RuntimeError('The instance status is error')
140 LOG.debug('Instance status change to ACTIVE')
142 duration = end_time - start_time
143 return duration.seconds + duration.microseconds * 1.0 / 1e6
146 class PingThread(threading.Thread): # pragma: no cover
148 def __init__(self, target):
149 super(PingThread, self).__init__()
157 res = ping.do_one(self.target, TIMEOUT, PACKAGE_SIZE)
161 self.delay = (TIMEOUT + 0.01) * count