42
41
'if none provided first external is used'),
43
42
cfg.BoolOpt('limit_cpu_features',
45
help='required for live migration among '
46
'hosts with different CPU features')
44
help='Required for live migration among '
45
'hosts with different CPU features'),
46
cfg.BoolOpt('config_drive_inject_password',
48
help='Sets the admin password in the config drive image'),
49
cfg.StrOpt('qemu_img_cmd',
50
default="qemu-img.exe",
51
help='qemu-img is used to convert between '
52
'different image types'),
53
cfg.BoolOpt('config_drive_cdrom',
55
help='Attaches the Config Drive image as a cdrom drive '
56
'instead of a disk drive')
50
FLAGS.register_opts(hyperv_opts)
60
CONF.register_opts(hyperv_opts)
61
CONF.import_opt('use_cow_images', 'nova.config')
53
64
class VMOps(baseops.BaseOps):
159
175
self.destroy(instance)
178
def _create_config_drive(self, instance, injected_files, admin_password):
179
if CONF.config_drive_format != 'iso9660':
180
vmutils.HyperVException(_('Invalid config_drive_format "%s"') %
181
CONF.config_drive_format)
183
LOG.info(_('Using config drive'), instance=instance)
185
if admin_password and CONF.config_drive_inject_password:
186
extra_md['admin_pass'] = admin_password
188
inst_md = instance_metadata.InstanceMetadata(instance,
189
content=injected_files, extra_md=extra_md)
191
instance_path = self._vmutils.get_instance_path(
193
configdrive_path_iso = os.path.join(instance_path, 'configdrive.iso')
194
LOG.info(_('Creating config drive at %(path)s'),
195
{'path': configdrive_path_iso}, instance=instance)
197
cdb = configdrive.ConfigDriveBuilder(instance_md=inst_md)
199
cdb.make_drive(configdrive_path_iso)
203
if not CONF.config_drive_cdrom:
204
drive_type = constants.IDE_DISK
205
configdrive_path = os.path.join(instance_path,
207
utils.execute(CONF.qemu_img_cmd,
213
configdrive_path_iso,
216
os.remove(configdrive_path_iso)
218
drive_type = constants.IDE_DVD
219
configdrive_path = configdrive_path_iso
221
self._attach_ide_drive(instance['name'], configdrive_path, 1, 0,
162
224
def _create_vm(self, instance):
163
225
"""Create a VM but don't start it. """
164
226
instance_name = instance["name"]
231
293
_('Failed to add scsi controller to VM %s') %
234
def _create_disk(self, vm_name, vhdfile):
235
"""Create a disk and attach it to the vm"""
236
LOG.debug(_('Creating disk for %(vm_name)s by attaching'
237
' disk file %(vhdfile)s') % locals())
296
def _get_ide_controller(self, vm, ctrller_addr):
238
297
#Find the IDE controller for the vm.
239
vms = self._conn.MSVM_ComputerSystem(ElementName=vm_name)
241
298
vmsettings = vm.associators(
242
299
wmi_result_class='Msvm_VirtualSystemSettingData')
243
300
rasds = vmsettings[0].associators(
244
301
wmi_result_class='MSVM_ResourceAllocationSettingData')
245
302
ctrller = [r for r in rasds
246
303
if r.ResourceSubType == 'Microsoft Emulated IDE Controller'
247
and r.Address == "0"]
304
and r.Address == str(ctrller_addr)]
307
def _attach_ide_drive(self, vm_name, path, ctrller_addr, drive_addr,
308
drive_type=constants.IDE_DISK):
309
"""Create an IDE drive and attach it to the vm"""
310
LOG.debug(_('Creating disk for %(vm_name)s by attaching'
311
' disk file %(path)s') % locals())
313
vms = self._conn.MSVM_ComputerSystem(ElementName=vm_name)
316
ctrller = self._get_ide_controller(vm, ctrller_addr)
318
if drive_type == constants.IDE_DISK:
319
resSubType = 'Microsoft Synthetic Disk Drive'
320
elif drive_type == constants.IDE_DVD:
321
resSubType = 'Microsoft Synthetic DVD Drive'
248
323
#Find the default disk drive object for the vm and clone it.
249
diskdflt = self._conn.query(
324
drivedflt = self._conn.query(
250
325
"SELECT * FROM Msvm_ResourceAllocationSettingData \
251
WHERE ResourceSubType LIKE 'Microsoft Synthetic Disk Drive'\
252
AND InstanceID LIKE '%Default%'")[0]
253
diskdrive = self._vmutils.clone_wmi_obj(self._conn,
254
'Msvm_ResourceAllocationSettingData', diskdflt)
326
WHERE ResourceSubType LIKE '%(resSubType)s'\
327
AND InstanceID LIKE '%%Default%%'" % locals())[0]
328
drive = self._vmutils.clone_wmi_obj(self._conn,
329
'Msvm_ResourceAllocationSettingData', drivedflt)
255
330
#Set the IDE ctrller as parent.
256
diskdrive.Parent = ctrller[0].path_()
257
diskdrive.Address = 0
331
drive.Parent = ctrller[0].path_()
332
drive.Address = drive_addr
258
333
#Add the cloned disk drive object to the vm.
259
334
new_resources = self._vmutils.add_virt_resource(self._conn,
261
336
if new_resources is None:
262
337
raise vmutils.HyperVException(
263
_('Failed to add diskdrive to VM %s') %
338
_('Failed to add drive to VM %s') %
265
diskdrive_path = new_resources[0]
266
LOG.debug(_('New disk drive path is %s'), diskdrive_path)
340
drive_path = new_resources[0]
341
LOG.debug(_('New %(drive_type)s drive path is %(drive_path)s') %
344
if drive_type == constants.IDE_DISK:
345
resSubType = 'Microsoft Virtual Hard Disk'
346
elif drive_type == constants.IDE_DVD:
347
resSubType = 'Microsoft Virtual CD/DVD Disk'
267
349
#Find the default VHD disk object.
268
vhddefault = self._conn.query(
350
drivedefault = self._conn.query(
269
351
"SELECT * FROM Msvm_ResourceAllocationSettingData \
270
WHERE ResourceSubType LIKE 'Microsoft Virtual Hard Disk' AND \
271
InstanceID LIKE '%Default%' ")[0]
352
WHERE ResourceSubType LIKE '%(resSubType)s' AND \
353
InstanceID LIKE '%%Default%%' " % locals())[0]
273
355
#Clone the default and point it to the image file.
274
vhddisk = self._vmutils.clone_wmi_obj(self._conn,
275
'Msvm_ResourceAllocationSettingData', vhddefault)
356
res = self._vmutils.clone_wmi_obj(self._conn,
357
'Msvm_ResourceAllocationSettingData', drivedefault)
276
358
#Set the new drive as the parent.
277
vhddisk.Parent = diskdrive_path
278
vhddisk.Connection = [vhdfile]
359
res.Parent = drive_path
360
res.Connection = [path]
280
362
#Add the new vhd object as a virtual hard disk to the vm.
281
new_resources = self._vmutils.add_virt_resource(self._conn,
363
new_resources = self._vmutils.add_virt_resource(self._conn, res, vm)
283
364
if new_resources is None:
284
365
raise vmutils.HyperVException(
285
_('Failed to add vhd file to VM %s') %
287
LOG.info(_('Created disk for %s'), vm_name)
366
_('Failed to add %(drive_type)s image to VM %(vm_name)s') %
368
LOG.info(_('Created drive type %(drive_type)s for %(vm_name)s') %
289
371
def _create_nic(self, vm_name, mac):
290
372
"""Create a (synthetic) nic and attach it to the vm"""
476
558
raise vmutils.HyperVException(msg)
478
def _get_vcpu_total(self):
479
"""Get vcpu number of physical computer.
480
:returns: the number of cpu core.
482
# On certain platforms, this will raise a NotImplementedError.
484
return multiprocessing.cpu_count()
485
except NotImplementedError:
486
LOG.warn(_("Cannot get the number of cpu, because this "
487
"function is not implemented for this platform. "
488
"This error can be safely ignored for now."))
491
def _get_memory_mb_total(self):
492
"""Get the total memory size(MB) of physical computer.
493
:returns: the total amount of memory(MB).
495
total_kb = self._conn_cimv2.query(
496
"SELECT TotalVisibleMemorySize FROM win32_operatingsystem")[0]\
497
.TotalVisibleMemorySize
498
total_mb = long(total_kb) / 1024
501
def _get_local_gb_total(self):
502
"""Get the total hdd size(GB) of physical computer.
504
The total amount of HDD(GB).
505
Note that this value shows a partition where
506
NOVA-INST-DIR/instances mounts.
508
#TODO(jordanrinke): This binds to C only right now,
509
#need to bind to instance dir
510
total_kb = self._conn_cimv2.query(
511
"SELECT Size FROM win32_logicaldisk WHERE DriveType=3")[0].Size
512
total_gb = long(total_kb) / (1024 ** 3)
515
def _get_vcpu_used(self):
516
""" Get vcpu usage number of physical computer.
517
:returns: The total number of vcpu that currently used.
519
#TODO(jordanrinke) figure out a way to count assigned VCPUs
523
def _get_memory_mb_used(self):
524
"""Get the free memory size(MB) of physical computer.
525
:returns: the total usage of memory(MB).
527
total_kb = self._conn_cimv2.query(
528
"SELECT FreePhysicalMemory FROM win32_operatingsystem")[0]\
530
total_mb = long(total_kb) / 1024
534
def _get_local_gb_used(self):
535
"""Get the free hdd size(GB) of physical computer.
537
The total usage of HDD(GB).
538
Note that this value shows a partition where
539
NOVA-INST-DIR/instances mounts.
541
#TODO(jordanrinke): This binds to C only right now,
542
#need to bind to instance dir
543
total_kb = self._conn_cimv2.query(
544
"SELECT FreeSpace FROM win32_logicaldisk WHERE DriveType=3")[0]\
546
total_gb = long(total_kb) / (1024 ** 3)
549
def _get_hypervisor_version(self):
550
"""Get hypervisor version.
551
:returns: hypervisor version (ex. 12003)
553
version = self._conn_cimv2.Win32_OperatingSystem()[0]\
554
.Version.replace('.', '')
555
LOG.info(_('Windows version: %s ') % version)
558
def get_available_resource(self):
559
"""Retrieve resource info.
561
This method is called when nova-compute launches, and
562
as part of a periodic task.
564
:returns: dictionary describing resources
567
LOG.info(_('get_available_resource called'))
569
# TODO(alexpilotti) implemented cpu_info
570
dic = {'vcpus': self._get_vcpu_total(),
571
'memory_mb': self._get_memory_mb_total(),
572
'local_gb': self._get_local_gb_total(),
573
'vcpus_used': self._get_vcpu_used(),
574
'memory_mb_used': self._get_memory_mb_used(),
575
'local_gb_used': self._get_local_gb_used(),
576
'hypervisor_type': "hyperv",
577
'hypervisor_version': self._get_hypervisor_version(),
578
'hypervisor_hostname': platform.node(),
579
'cpu_info': 'unknown'}
583
560
def _cache_image(self, fn, target, fname, cow=False, Size=None,
584
561
*args, **kwargs):
585
562
"""Wrapper for a method that creates an image that caches the image.