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__)
31 class Migrate(base.Scenario): # pragma: no cover
33 Execute a live migration for two hosts
37 __scenario_type__ = "Migrate"
39 def __init__(self, scenario_cfg, context_cfg):
40 self.scenario_cfg = scenario_cfg
41 self.context_cfg = context_cfg
42 self.options = self.scenario_cfg.get('options', {})
44 self.nova_client = openstack_utils.get_nova_client()
46 def run(self, result):
47 default_instance_id = self.options.get('server', {}).get('id', '')
48 instance_id = self.options.get('server_id', default_instance_id)
49 LOG.info('Instance id is %s', instance_id)
51 target_host = self.options.get('host')
52 LOG.info('Target host is %s', target_host)
54 instance_ip = self.options.get('server_ip')
56 LOG.info('Instance ip is %s', instance_ip)
58 self._ping_until_connected(instance_ip)
59 LOG.info('Instance is connected')
61 LOG.debug('Start to ping instance')
62 ping_thread = self._do_ping_task(instance_ip)
64 keys = self.scenario_cfg.get('output', '').split()
66 LOG.info('Start to migrate')
67 self._do_migrate(instance_id, target_host)
68 except Exception as e:
69 return self._push_to_outputs(keys, [1, str(e).split('.')[0]])
71 migrate_time = self._get_migrate_time(instance_id)
72 LOG.info('Migration time is %s s', migrate_time)
74 current_host = self._get_current_host_name(instance_id)
75 LOG.info('Current host is %s', current_host)
76 if current_host.strip() != target_host.strip():
77 LOG.error('current_host not equal to target_host')
78 values = [1, 'current_host not equal to target_host']
79 return self._push_to_outputs(keys, values)
82 ping_thread.flag = False
85 downtime = ping_thread.get_delay()
86 LOG.info('Downtime is %s s', downtime)
88 values = [0, migrate_time, downtime]
89 return self._push_to_outputs(keys, values)
91 values = [0, migrate_time]
92 return self._push_to_outputs(keys, values)
94 def _do_migrate(self, server_id, target_host):
96 cmd = ['nova', 'live-migration', server_id, target_host]
97 p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
100 def _ping_until_connected(self, instance_ip):
101 for i in range(3000):
102 res = ping.do_one(instance_ip, TIMEOUT, PACKAGE_SIZE)
106 def _do_ping_task(self, instance_ip):
107 ping_thread = PingThread(instance_ip)
111 def _get_current_host_name(self, server_id):
113 return change_obj_to_dict(self.nova_client.servers.get(server_id))['OS-EXT-SRV-ATTR:host']
115 def _get_migrate_time(self, server_id):
117 status = self.nova_client.servers.get(server_id).status.lower()
118 if status == 'migrating':
119 start_time = datetime.now()
121 LOG.debug('Instance status change to MIGRATING')
124 status = self.nova_client.servers.get(server_id).status.lower()
125 if status == 'active':
126 end_time = datetime.now()
128 if status == 'error':
129 LOG.error('Instance status is ERROR')
130 raise RuntimeError('The instance status is error')
131 LOG.debug('Instance status change to ACTIVE')
133 duration = end_time - start_time
134 return duration.seconds + duration.microseconds * 1.0 / 1e6
137 class PingThread(threading.Thread): # pragma: no cover
139 def __init__(self, target):
140 super(PingThread, self).__init__()
148 res = ping.do_one(self.target, TIMEOUT, PACKAGE_SIZE)
152 self.delay = (TIMEOUT + 0.01) * count