1 ##############################################################################
2 # Copyright (c) 2015 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 ##############################################################################
13 from vstf.common.utils import check_and_kill, randomMAC, my_mkdir, check_call, check_output, my_sleep
14 from vstf.agent.env.basic.vm9pfs import VMConfigBy9pfs
16 LOG = logging.getLogger(__name__)
19 class VMControlOperation(object):
21 a libivrt virsh wrapper for creating virtual machine.
26 all tmp files will be created under '/tmp/atf_vm_manager'
29 work_dir = '/tmp/atf_vm_manager'
30 shutil.rmtree(work_dir, ignore_errors=True)
32 self.work_dir = work_dir
36 self.vm_9p_controllers = {}
41 def composite_xml(context):
43 composit a libvirt xml configuration for creating vm from context.
45 :param context: a dict containing all necessary options for creating a vm.
46 :return: libvirt xml configuration string
48 from vm_xml_help import xml_head, xml_disk, xml_ovs, xml_pci, xml_9p, xml_tail, xml_ctrl_br, xml_br
50 tmp = xml_head.replace('VM_NAME', context['vm_name'])
51 tmp = tmp.replace('VM_MEMORY', str(context['vm_memory']))
52 tmp = tmp.replace('CPU_NUM', str(context['vm_cpu']))
54 tmp = xml_disk.replace('IMAGE_TYPE', context['image_type'])
55 tmp = tmp.replace('IMAGE_PATH', context['image_path'])
58 if context['9p_path']:
59 tmp = xml_9p.replace('9P_PATH', context['9p_path'])
62 if context['eth_pci']:
63 for pci in context['eth_pci']:
67 tmp = xml_pci.replace('BUS', bus)
68 tmp = tmp.replace('SLOT', slot)
69 tmp = tmp.replace('FUNCTION', func)
72 if context['ctrl_br']:
73 tmp = xml_ctrl_br.replace('CTRL_BR', context['ctrl_br'])
74 tmp = tmp.replace('CTRL_MAC', context['ctrl_mac'])
75 tmp = tmp.replace('CTRL_MODEL', context['ctrl_model'])
78 for tap_cfg in context['taps']:
79 if tap_cfg['br_type'] == "ovs":
80 br_type = "openvswitch"
82 br_type = tap_cfg['br_type']
83 if br_type == 'bridge':
85 tmp = xml_ovs.replace('BR_TYPE', br_type)
86 tmp = tmp.replace('TAP_MAC', tap_cfg['tap_mac'])
87 tmp = tmp.replace('TAP_NAME', tap_cfg['tap_name'])
88 tmp = tmp.replace('BR_NAME', tap_cfg['br_name'])
95 def check_required_options(context):
103 if key not in context:
104 raise Exception("vm config error, must set %s option" % key)
106 def set_vm_defaults(self, context):
107 vm_9p_path = '%s/%s' % (self.work_dir, context['vm_name'])
108 shutil.rmtree(vm_9p_path, ignore_errors=True)
110 default = {'vm_memory': 4194304,
112 'image_type': 'qcow2',
114 '9p_path': vm_9p_path,
117 'ctrl_mac': randomMAC(),
118 'ctrl_model': 'virtio',
119 'ctrl_ip_setting': '192.168.100.100/24',
120 'ctrl_gw': '192.168.100.1'
122 for k, v in default.items():
123 context.setdefault(k, v)
125 def _shutdown_vm(self):
127 "virsh list | sed 1,2d | awk '{print $2}'",
129 vm_set = set(out.split())
131 check_call("virsh shutdown %s" % vm, shell=True)
133 # wait for gracefully shutdown
136 "virsh list | sed 1,2d | awk '{print $2}'",
138 vm_set = set(out.split())
143 LOG.info("waiting for vms:%s to shutdown gracefully", vm_set)
146 check_call("virsh destroy %s" % vm, shell=True)
149 "virsh list --all | sed 1,2d | awk '{print $2}'",
151 vm_set = set(out.split())
153 check_call("virsh undefine %s" % vm, shell=True)
155 check_and_kill('qemu-system-x86_64')
157 def clean_all_vms(self):
159 for _, ctrl in self.vm_9p_controllers.items():
160 LOG.debug("remove vm9pfs dir:%s", ctrl.vm_9p_path)
161 shutil.rmtree(ctrl.vm_9p_path, ignore_errors=True)
162 self.vm_9p_controllers = {}
164 # shutil.rmtree(self.work_dir, ignore_errors=True)
171 def create_vm(self, context):
172 self.set_vm_defaults(context)
173 self.check_required_options(context)
174 xml = self.composite_xml(context)
175 vm_name = context['vm_name']
176 file_name = os.path.join(self.work_dir, vm_name + '.xml')
177 with open(file_name, 'w') as f:
179 check_call('virsh define %s' % file_name, shell=True)
180 check_call('virsh start %s' % vm_name, shell=True)
181 vm_name = context['vm_name']
182 vm_9pfs = context['9p_path']
183 self.vm_9p_controllers[vm_name] = VMConfigBy9pfs(vm_9pfs)
184 self.vm_configs[vm_name] = context
185 LOG.debug("%s's vm_9pfs path:%s", vm_name, vm_9pfs)
188 def wait_vm(self, vm_name):
189 vm9pctrl = self.vm_9p_controllers[vm_name]
190 ret = vm9pctrl.wait_up()
191 if ret not in (True,):
193 'vm running but stuck in boot process, please manully check.')
194 LOG.debug('waitVM %s up ok, ret:%s', vm_name, ret)
197 def init_config_vm(self, vm_name):
199 using libvirt 9pfs to config boot up options like network ip/gw.
201 :param vm_name: the vm to be config with.
202 :return: True if succeed, Exception if fail.
204 vm_cfg = self.vm_configs[vm_name]
205 vm9pctrl = self.vm_9p_controllers[vm_name]
206 # print self.vm_9p_controllers
207 init_cfg = vm_cfg['init_config']
208 if "ctrl_ip_setting" in init_cfg:
209 ret = vm9pctrl.config_ip(
211 init_cfg['ctrl_ip_setting'])
213 LOG.info('initConfigVM config ip ok')
214 if 'ctrl_gw' in init_cfg:
215 ret = vm9pctrl.config_gw(init_cfg['ctrl_gw'])
217 LOG.info('initConfigVM ctrl_gw ok')
218 if "ctrl_ip_setting" in init_cfg and "amqp_server" in init_cfg:
219 identity = init_cfg['ctrl_ip_setting'].split('/')[0]
220 if init_cfg['amqp_id'].strip():
221 identity = init_cfg['amqp_id'].strip()
222 server = init_cfg['amqp_server']
223 port = init_cfg['amqp_port']
224 user = init_cfg['amqp_user']
225 passwd = init_cfg['amqp_passwd']
226 ret = vm9pctrl.config_amqp(identity, server, port, user, passwd)
228 LOG.info('initConfigVM config_amqp ok')
229 if 'tap_pktloop_config' in init_cfg:
230 taps = vm_cfg['taps']
233 macs.append(tap['tap_mac'])
234 ret = vm9pctrl.set_pktloop_dpdk(macs)
236 LOG.info('initConfigVM set_pktloop_dpdk ok')