31 |
31 |
import re
|
32 |
32 |
import platform
|
33 |
33 |
import logging
|
|
34 |
import copy
|
34 |
35 |
|
35 |
36 |
from ganeti import ssh
|
36 |
37 |
from ganeti import logger
|
... | ... | |
3139 |
3140 |
return req_size_dict[disk_template]
|
3140 |
3141 |
|
3141 |
3142 |
|
|
3143 |
def _CheckHVParams(lu, nodenames, hvname, hvparams):
|
|
3144 |
"""Hypervisor parameter validation.
|
|
3145 |
|
|
3146 |
This function abstract the hypervisor parameter validation to be
|
|
3147 |
used in both instance create and instance modify.
|
|
3148 |
|
|
3149 |
@type lu: L{LogicalUnit}
|
|
3150 |
@param lu: the logical unit for which we check
|
|
3151 |
@type nodenames: list
|
|
3152 |
@param nodenames: the list of nodes on which we should check
|
|
3153 |
@type hvname: string
|
|
3154 |
@param hvname: the name of the hypervisor we should use
|
|
3155 |
@type hvparams: dict
|
|
3156 |
@param hvparams: the parameters which we need to check
|
|
3157 |
@raise errors.OpPrereqError: if the parameters are not valid
|
|
3158 |
|
|
3159 |
"""
|
|
3160 |
hvinfo = lu.rpc.call_hypervisor_validate_params(nodenames,
|
|
3161 |
hvname,
|
|
3162 |
hvparams)
|
|
3163 |
for node in nodenames:
|
|
3164 |
info = hvinfo.get(node, None)
|
|
3165 |
if not info or not isinstance(info, (tuple, list)):
|
|
3166 |
raise errors.OpPrereqError("Cannot get current information"
|
|
3167 |
" from node '%s' (%s)" % (node, info))
|
|
3168 |
if not info[0]:
|
|
3169 |
raise errors.OpPrereqError("Hypervisor parameter validation failed:"
|
|
3170 |
" %s" % info[1])
|
|
3171 |
|
|
3172 |
|
3142 |
3173 |
class LUCreateInstance(LogicalUnit):
|
3143 |
3174 |
"""Create an instance.
|
3144 |
3175 |
|
... | ... | |
3449 |
3480 |
" %d MB available, %d MB required" %
|
3450 |
3481 |
(node, info['vg_free'], req_size))
|
3451 |
3482 |
|
3452 |
|
# hypervisor parameter validation
|
3453 |
|
hvinfo = self.rpc.call_hypervisor_validate_params(nodenames,
|
3454 |
|
self.op.hypervisor,
|
3455 |
|
self.op.hvparams)
|
3456 |
|
for node in nodenames:
|
3457 |
|
info = hvinfo.get(node, None)
|
3458 |
|
if not info or not isinstance(info, (tuple, list)):
|
3459 |
|
raise errors.OpPrereqError("Cannot get current information"
|
3460 |
|
" from node '%s' (%s)" % (node, info))
|
3461 |
|
if not info[0]:
|
3462 |
|
raise errors.OpPrereqError("Hypervisor parameter validation failed:"
|
3463 |
|
" %s" % info[1])
|
|
3483 |
_CheckHVParams(self, nodenames, self.op.hypervisor, self.op.hvparams)
|
3464 |
3484 |
|
3465 |
3485 |
# os verification
|
3466 |
3486 |
os_obj = self.rpc.call_os_get(pnode.name, self.op.os_type)
|
... | ... | |
4450 |
4470 |
"""
|
4451 |
4471 |
HPATH = "instance-modify"
|
4452 |
4472 |
HTYPE = constants.HTYPE_INSTANCE
|
4453 |
|
_OP_REQP = ["instance_name"]
|
|
4473 |
_OP_REQP = ["instance_name", "hvparams"]
|
4454 |
4474 |
REQ_BGL = False
|
4455 |
4475 |
|
4456 |
4476 |
def ExpandNames(self):
|
4457 |
4477 |
self._ExpandAndLockInstance()
|
|
4478 |
self.needed_locks[locking.LEVEL_NODE] = []
|
|
4479 |
self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
|
|
4480 |
|
|
4481 |
|
|
4482 |
def DeclareLocks(self, level):
|
|
4483 |
if level == locking.LEVEL_NODE:
|
|
4484 |
self._LockInstancesNodes()
|
4458 |
4485 |
|
4459 |
4486 |
def BuildHooksEnv(self):
|
4460 |
4487 |
"""Build hooks env.
|
... | ... | |
4502 |
4529 |
self.bridge = getattr(self.op, "bridge", None)
|
4503 |
4530 |
self.kernel_path = getattr(self.op, "kernel_path", None)
|
4504 |
4531 |
self.initrd_path = getattr(self.op, "initrd_path", None)
|
4505 |
|
self.hvm_boot_order = getattr(self.op, "hvm_boot_order", None)
|
4506 |
|
self.hvm_acpi = getattr(self.op, "hvm_acpi", None)
|
4507 |
|
self.hvm_pae = getattr(self.op, "hvm_pae", None)
|
4508 |
|
self.hvm_nic_type = getattr(self.op, "hvm_nic_type", None)
|
4509 |
|
self.hvm_disk_type = getattr(self.op, "hvm_disk_type", None)
|
4510 |
|
self.hvm_cdrom_image_path = getattr(self.op, "hvm_cdrom_image_path", None)
|
4511 |
|
self.vnc_bind_address = getattr(self.op, "vnc_bind_address", None)
|
4512 |
4532 |
self.force = getattr(self.op, "force", None)
|
4513 |
|
all_parms = [self.mem, self.vcpus, self.ip, self.bridge, self.mac,
|
4514 |
|
self.kernel_path, self.initrd_path, self.hvm_boot_order,
|
4515 |
|
self.hvm_acpi, self.hvm_pae, self.hvm_cdrom_image_path,
|
4516 |
|
self.vnc_bind_address, self.hvm_nic_type, self.hvm_disk_type]
|
4517 |
|
if all_parms.count(None) == len(all_parms):
|
|
4533 |
all_parms = [self.mem, self.vcpus, self.ip, self.bridge, self.mac]
|
|
4534 |
if all_parms.count(None) == len(all_parms) and not self.op.hvparams:
|
4518 |
4535 |
raise errors.OpPrereqError("No changes submitted")
|
4519 |
4536 |
if self.mem is not None:
|
4520 |
4537 |
try:
|
... | ... | |
4543 |
4560 |
if not utils.IsValidMac(self.mac):
|
4544 |
4561 |
raise errors.OpPrereqError('Invalid MAC address %s' % self.mac)
|
4545 |
4562 |
|
4546 |
|
if self.kernel_path is not None:
|
4547 |
|
self.do_kernel_path = True
|
4548 |
|
if self.kernel_path == constants.VALUE_NONE:
|
4549 |
|
raise errors.OpPrereqError("Can't set instance to no kernel")
|
4550 |
|
|
4551 |
|
if self.kernel_path != constants.VALUE_DEFAULT:
|
4552 |
|
if not os.path.isabs(self.kernel_path):
|
4553 |
|
raise errors.OpPrereqError("The kernel path must be an absolute"
|
4554 |
|
" filename")
|
4555 |
|
else:
|
4556 |
|
self.do_kernel_path = False
|
4557 |
|
|
4558 |
|
if self.initrd_path is not None:
|
4559 |
|
self.do_initrd_path = True
|
4560 |
|
if self.initrd_path not in (constants.VALUE_NONE,
|
4561 |
|
constants.VALUE_DEFAULT):
|
4562 |
|
if not os.path.isabs(self.initrd_path):
|
4563 |
|
raise errors.OpPrereqError("The initrd path must be an absolute"
|
4564 |
|
" filename")
|
4565 |
|
else:
|
4566 |
|
self.do_initrd_path = False
|
4567 |
|
|
4568 |
|
# boot order verification
|
4569 |
|
if self.hvm_boot_order is not None:
|
4570 |
|
if self.hvm_boot_order != constants.VALUE_DEFAULT:
|
4571 |
|
if len(self.hvm_boot_order.strip("acdn")) != 0:
|
4572 |
|
raise errors.OpPrereqError("invalid boot order specified,"
|
4573 |
|
" must be one or more of [acdn]"
|
4574 |
|
" or 'default'")
|
4575 |
|
|
4576 |
|
# hvm_cdrom_image_path verification
|
4577 |
|
if self.op.hvm_cdrom_image_path is not None:
|
4578 |
|
if not (os.path.isabs(self.op.hvm_cdrom_image_path) or
|
4579 |
|
self.op.hvm_cdrom_image_path.lower() == "none"):
|
4580 |
|
raise errors.OpPrereqError("The path to the HVM CDROM image must"
|
4581 |
|
" be an absolute path or None, not %s" %
|
4582 |
|
self.op.hvm_cdrom_image_path)
|
4583 |
|
if not (os.path.isfile(self.op.hvm_cdrom_image_path) or
|
4584 |
|
self.op.hvm_cdrom_image_path.lower() == "none"):
|
4585 |
|
raise errors.OpPrereqError("The HVM CDROM image must either be a"
|
4586 |
|
" regular file or a symlink pointing to"
|
4587 |
|
" an existing regular file, not %s" %
|
4588 |
|
self.op.hvm_cdrom_image_path)
|
4589 |
|
|
4590 |
|
# vnc_bind_address verification
|
4591 |
|
if self.op.vnc_bind_address is not None:
|
4592 |
|
if not utils.IsValidIP(self.op.vnc_bind_address):
|
4593 |
|
raise errors.OpPrereqError("given VNC bind address '%s' doesn't look"
|
4594 |
|
" like a valid IP address" %
|
4595 |
|
self.op.vnc_bind_address)
|
|
4563 |
# checking the new params on the primary/secondary nodes
|
4596 |
4564 |
|
4597 |
4565 |
instance = self.instance = self.cfg.GetInstanceInfo(self.op.instance_name)
|
4598 |
4566 |
assert self.instance is not None, \
|
4599 |
4567 |
"Cannot retrieve locked instance %s" % self.op.instance_name
|
|
4568 |
pnode = self.instance.primary_node
|
|
4569 |
nodelist = [pnode]
|
|
4570 |
nodelist.extend(instance.secondary_nodes)
|
|
4571 |
|
|
4572 |
if self.op.hvparams:
|
|
4573 |
i_hvdict = copy.deepcopy(instance.hvparams)
|
|
4574 |
for key, val in self.op.hvparams.iteritems():
|
|
4575 |
if val is None:
|
|
4576 |
try:
|
|
4577 |
del i_hvdict[key]
|
|
4578 |
except KeyError:
|
|
4579 |
pass
|
|
4580 |
else:
|
|
4581 |
i_hvdict[key] = val
|
|
4582 |
cluster = self.cfg.GetClusterInfo()
|
|
4583 |
hv_new = cluster.FillDict(cluster.hvparams[instance.hypervisor],
|
|
4584 |
i_hvdict)
|
|
4585 |
# local check
|
|
4586 |
hypervisor.GetHypervisor(
|
|
4587 |
instance.hypervisor).CheckParameterSyntax(hv_new)
|
|
4588 |
_CheckHVParams(self, nodelist, instance.hypervisor, hv_new)
|
|
4589 |
self.hv_new = hv_new
|
|
4590 |
|
4600 |
4591 |
self.warn = []
|
4601 |
4592 |
if self.mem is not None and not self.force:
|
4602 |
|
pnode = self.instance.primary_node
|
4603 |
|
nodelist = [pnode]
|
4604 |
|
nodelist.extend(instance.secondary_nodes)
|
4605 |
4593 |
instance_info = self.rpc.call_instance_info(pnode, instance.name,
|
4606 |
4594 |
instance.hypervisor)
|
4607 |
4595 |
nodeinfo = self.rpc.call_node_info(nodelist, self.cfg.GetVGName(),
|
... | ... | |
4628 |
4616 |
if node not in nodeinfo or not isinstance(nodeinfo[node], dict):
|
4629 |
4617 |
self.warn.append("Can't get info from secondary node %s" % node)
|
4630 |
4618 |
elif self.mem > nodeinfo[node]['memory_free']:
|
4631 |
|
self.warn.append("Not enough memory to failover instance to secondary"
|
4632 |
|
" node %s" % node)
|
4633 |
|
|
4634 |
|
# Xen HVM device type checks
|
4635 |
|
if instance.hypervisor == constants.HT_XEN_HVM:
|
4636 |
|
if self.op.hvm_nic_type is not None:
|
4637 |
|
if self.op.hvm_nic_type not in constants.HT_HVM_VALID_NIC_TYPES:
|
4638 |
|
raise errors.OpPrereqError("Invalid NIC type %s specified for Xen"
|
4639 |
|
" HVM hypervisor" % self.op.hvm_nic_type)
|
4640 |
|
if self.op.hvm_disk_type is not None:
|
4641 |
|
if self.op.hvm_disk_type not in constants.HT_HVM_VALID_DISK_TYPES:
|
4642 |
|
raise errors.OpPrereqError("Invalid disk type %s specified for Xen"
|
4643 |
|
" HVM hypervisor" % self.op.hvm_disk_type)
|
|
4619 |
self.warn.append("Not enough memory to failover instance to"
|
|
4620 |
" secondary node %s" % node)
|
4644 |
4621 |
|
4645 |
4622 |
return
|
4646 |
4623 |
|
... | ... | |
4671 |
4648 |
if self.mac:
|
4672 |
4649 |
instance.nics[0].mac = self.mac
|
4673 |
4650 |
result.append(("mac", self.mac))
|
4674 |
|
if self.do_kernel_path:
|
4675 |
|
instance.kernel_path = self.kernel_path
|
4676 |
|
result.append(("kernel_path", self.kernel_path))
|
4677 |
|
if self.do_initrd_path:
|
4678 |
|
instance.initrd_path = self.initrd_path
|
4679 |
|
result.append(("initrd_path", self.initrd_path))
|
4680 |
|
if self.hvm_boot_order:
|
4681 |
|
if self.hvm_boot_order == constants.VALUE_DEFAULT:
|
4682 |
|
instance.hvm_boot_order = None
|
4683 |
|
else:
|
4684 |
|
instance.hvm_boot_order = self.hvm_boot_order
|
4685 |
|
result.append(("hvm_boot_order", self.hvm_boot_order))
|
4686 |
|
if self.hvm_acpi is not None:
|
4687 |
|
instance.hvm_acpi = self.hvm_acpi
|
4688 |
|
result.append(("hvm_acpi", self.hvm_acpi))
|
4689 |
|
if self.hvm_pae is not None:
|
4690 |
|
instance.hvm_pae = self.hvm_pae
|
4691 |
|
result.append(("hvm_pae", self.hvm_pae))
|
4692 |
|
if self.hvm_nic_type is not None:
|
4693 |
|
instance.hvm_nic_type = self.hvm_nic_type
|
4694 |
|
result.append(("hvm_nic_type", self.hvm_nic_type))
|
4695 |
|
if self.hvm_disk_type is not None:
|
4696 |
|
instance.hvm_disk_type = self.hvm_disk_type
|
4697 |
|
result.append(("hvm_disk_type", self.hvm_disk_type))
|
4698 |
|
if self.hvm_cdrom_image_path:
|
4699 |
|
if self.hvm_cdrom_image_path == constants.VALUE_NONE:
|
4700 |
|
instance.hvm_cdrom_image_path = None
|
4701 |
|
else:
|
4702 |
|
instance.hvm_cdrom_image_path = self.hvm_cdrom_image_path
|
4703 |
|
result.append(("hvm_cdrom_image_path", self.hvm_cdrom_image_path))
|
4704 |
|
if self.vnc_bind_address:
|
4705 |
|
instance.vnc_bind_address = self.vnc_bind_address
|
4706 |
|
result.append(("vnc_bind_address", self.vnc_bind_address))
|
|
4651 |
if self.op.hvparams:
|
|
4652 |
instance.hvparams = self.hv_new
|
|
4653 |
for key, val in self.op.hvparams.iteritems():
|
|
4654 |
result.append(("hv/%s" % key, val))
|
4707 |
4655 |
|
4708 |
4656 |
self.cfg.Update(instance)
|
4709 |
4657 |
|