Revision d61df03e lib/cmdlib.py
b/lib/cmdlib.py | ||
---|---|---|
30 | 30 |
import tempfile |
31 | 31 |
import re |
32 | 32 |
import platform |
33 |
import simplejson |
|
33 | 34 |
|
34 | 35 |
from ganeti import rpc |
35 | 36 |
from ganeti import ssh |
... | ... | |
44 | 45 |
from ganeti import ssconf |
45 | 46 |
|
46 | 47 |
|
48 |
# Check whether the simplejson module supports indentation |
|
49 |
_JSON_INDENT = 2 |
|
50 |
try: |
|
51 |
simplejson.dumps(1, indent=_JSON_INDENT) |
|
52 |
except TypeError: |
|
53 |
_JSON_INDENT = None |
|
54 |
|
|
55 |
|
|
47 | 56 |
class LogicalUnit(object): |
48 | 57 |
"""Logical Unit base class. |
49 | 58 |
|
... | ... | |
4639 | 4648 |
if not node_result: |
4640 | 4649 |
raise errors.OpExecError("Failure during rpc call to node %s," |
4641 | 4650 |
" result: %s" % (node, node_result)) |
4651 |
|
|
4652 |
|
|
4653 |
def _AllocatorGetClusterData(cfg, sstore): |
|
4654 |
"""Compute the generic allocator input data. |
|
4655 |
|
|
4656 |
This is the data that is independent of the actual operation. |
|
4657 |
|
|
4658 |
""" |
|
4659 |
# cluster data |
|
4660 |
data = { |
|
4661 |
"version": 1, |
|
4662 |
"cluster_name": sstore.GetClusterName(), |
|
4663 |
"cluster_tags": list(cfg.GetClusterInfo().GetTags()), |
|
4664 |
# we don't have job IDs |
|
4665 |
} |
|
4666 |
|
|
4667 |
# node data |
|
4668 |
node_results = {} |
|
4669 |
node_list = cfg.GetNodeList() |
|
4670 |
node_data = rpc.call_node_info(node_list, cfg.GetVGName()) |
|
4671 |
for nname in node_list: |
|
4672 |
ninfo = cfg.GetNodeInfo(nname) |
|
4673 |
if nname not in node_data or not isinstance(node_data[nname], dict): |
|
4674 |
raise errors.OpExecError("Can't get data for node %s" % nname) |
|
4675 |
remote_info = node_data[nname] |
|
4676 |
for attr in ['memory_total', 'memory_free', |
|
4677 |
'vg_size', 'vg_free']: |
|
4678 |
if attr not in remote_info: |
|
4679 |
raise errors.OpExecError("Node '%s' didn't return attribute '%s'" % |
|
4680 |
(nname, attr)) |
|
4681 |
try: |
|
4682 |
int(remote_info[attr]) |
|
4683 |
except ValueError, err: |
|
4684 |
raise errors.OpExecError("Node '%s' returned invalid value for '%s':" |
|
4685 |
" %s" % (nname, attr, str(err))) |
|
4686 |
pnr = { |
|
4687 |
"tags": list(ninfo.GetTags()), |
|
4688 |
"total_memory": utils.TryConvert(int, remote_info['memory_total']), |
|
4689 |
"free_memory": utils.TryConvert(int, remote_info['memory_free']), |
|
4690 |
"total_disk": utils.TryConvert(int, remote_info['vg_size']), |
|
4691 |
"free_disk": utils.TryConvert(int, remote_info['vg_free']), |
|
4692 |
"primary_ip": ninfo.primary_ip, |
|
4693 |
"secondary_ip": ninfo.secondary_ip, |
|
4694 |
} |
|
4695 |
node_results[nname] = pnr |
|
4696 |
data["nodes"] = node_results |
|
4697 |
|
|
4698 |
# instance data |
|
4699 |
instance_data = {} |
|
4700 |
i_list = cfg.GetInstanceList() |
|
4701 |
for iname in i_list: |
|
4702 |
iinfo = cfg.GetInstanceInfo(iname) |
|
4703 |
nic_data = [{"mac": n.mac, "ip": n.ip, "bridge": n.bridge} |
|
4704 |
for n in iinfo.nics] |
|
4705 |
pir = { |
|
4706 |
"tags": list(iinfo.GetTags()), |
|
4707 |
"should_run": iinfo.status == "up", |
|
4708 |
"vcpus": iinfo.vcpus, |
|
4709 |
"memory": iinfo.memory, |
|
4710 |
"os": iinfo.os, |
|
4711 |
"nodes": [iinfo.primary_node] + list(iinfo.secondary_nodes), |
|
4712 |
"nics": nic_data, |
|
4713 |
"disks": [{"size": dsk.size, "mode": "w"} for dsk in iinfo.disks], |
|
4714 |
"disk_template": iinfo.disk_template, |
|
4715 |
} |
|
4716 |
instance_data[iname] = pir |
|
4717 |
|
|
4718 |
data["instances"] = instance_data |
|
4719 |
|
|
4720 |
return data |
|
4721 |
|
|
4722 |
|
|
4723 |
def _AllocatorAddNewInstance(data, op): |
|
4724 |
"""Add new instance data to allocator structure. |
|
4725 |
|
|
4726 |
This in combination with _AllocatorGetClusterData will create the |
|
4727 |
correct structure needed as input for the allocator. |
|
4728 |
|
|
4729 |
The checks for the completeness of the opcode must have already been |
|
4730 |
done. |
|
4731 |
|
|
4732 |
""" |
|
4733 |
request = { |
|
4734 |
"type": "allocate", |
|
4735 |
"name": op.name, |
|
4736 |
"disk_template": op.disk_template, |
|
4737 |
"tags": op.tags, |
|
4738 |
"os": op.os, |
|
4739 |
"vcpus": op.vcpus, |
|
4740 |
"memory": op.mem_size, |
|
4741 |
"disks": op.disks, |
|
4742 |
"nics": op.nics, |
|
4743 |
} |
|
4744 |
data["request"] = request |
|
4745 |
|
|
4746 |
|
|
4747 |
def _AllocatorAddRelocateInstance(data, op): |
|
4748 |
"""Add relocate instance data to allocator structure. |
|
4749 |
|
|
4750 |
This in combination with _AllocatorGetClusterData will create the |
|
4751 |
correct structure needed as input for the allocator. |
|
4752 |
|
|
4753 |
The checks for the completeness of the opcode must have already been |
|
4754 |
done. |
|
4755 |
|
|
4756 |
""" |
|
4757 |
request = { |
|
4758 |
"type": "replace_secondary", |
|
4759 |
"name": op.name, |
|
4760 |
} |
|
4761 |
data["request"] = request |
|
4762 |
|
|
4763 |
|
|
4764 |
class LUTestAllocator(NoHooksLU): |
|
4765 |
"""Run allocator tests. |
|
4766 |
|
|
4767 |
This LU runs the allocator tests |
|
4768 |
|
|
4769 |
""" |
|
4770 |
_OP_REQP = ["direction", "mode", "name"] |
|
4771 |
|
|
4772 |
def CheckPrereq(self): |
|
4773 |
"""Check prerequisites. |
|
4774 |
|
|
4775 |
This checks the opcode parameters depending on the director and mode test. |
|
4776 |
|
|
4777 |
""" |
|
4778 |
if self.op.mode == constants.ALF_MODE_ALLOC: |
|
4779 |
for attr in ["name", "mem_size", "disks", "disk_template", |
|
4780 |
"os", "tags", "nics", "vcpus"]: |
|
4781 |
if not hasattr(self.op, attr): |
|
4782 |
raise errors.OpPrereqError("Missing attribute '%s' on opcode input" % |
|
4783 |
attr) |
|
4784 |
iname = self.cfg.ExpandInstanceName(self.op.name) |
|
4785 |
if iname is not None: |
|
4786 |
raise errors.OpPrereqError("Instance '%s' already in the cluster" % |
|
4787 |
iname) |
|
4788 |
if not isinstance(self.op.nics, list): |
|
4789 |
raise errors.OpPrereqError("Invalid parameter 'nics'") |
|
4790 |
for row in self.op.nics: |
|
4791 |
if (not isinstance(row, dict) or |
|
4792 |
"mac" not in row or |
|
4793 |
"ip" not in row or |
|
4794 |
"bridge" not in row): |
|
4795 |
raise errors.OpPrereqError("Invalid contents of the" |
|
4796 |
" 'nics' parameter") |
|
4797 |
if not isinstance(self.op.disks, list): |
|
4798 |
raise errors.OpPrereqError("Invalid parameter 'disks'") |
|
4799 |
for row in self.op.disks: |
|
4800 |
if (not isinstance(row, dict) or |
|
4801 |
"size" not in row or |
|
4802 |
not isinstance(row["size"], int) or |
|
4803 |
"mode" not in row or |
|
4804 |
row["mode"] not in ['r', 'w']): |
|
4805 |
raise errors.OpPrereqError("Invalid contents of the" |
|
4806 |
" 'disks' parameter") |
|
4807 |
elif self.op.mode == constants.ALF_MODE_RELOC: |
|
4808 |
if not hasattr(self.op, "name"): |
|
4809 |
raise errors.OpPrereqError("Missing attribute 'name' on opcode input") |
|
4810 |
fname = self.cfg.ExpandInstanceName(self.op.name) |
|
4811 |
if fname is None: |
|
4812 |
raise errors.OpPrereqError("Instance '%s' not found for relocation" % |
|
4813 |
self.op.name) |
|
4814 |
self.op.name = fname |
|
4815 |
else: |
|
4816 |
raise errors.OpPrereqError("Invalid test allocator mode '%s'" % |
|
4817 |
self.op.mode) |
|
4818 |
|
|
4819 |
if self.op.direction == constants.ALF_DIR_OUT: |
|
4820 |
if not hasattr(self.op, "allocator"): |
|
4821 |
raise errors.OpPrereqError("Missing allocator name") |
|
4822 |
raise errors.OpPrereqError("Allocator out mode not supported yet") |
|
4823 |
elif self.op.direction != constants.ALF_DIR_IN: |
|
4824 |
raise errors.OpPrereqError("Wrong allocator test '%s'" % |
|
4825 |
self.op.direction) |
|
4826 |
|
|
4827 |
def Exec(self, feedback_fn): |
|
4828 |
"""Run the allocator test. |
|
4829 |
|
|
4830 |
""" |
|
4831 |
data = _AllocatorGetClusterData(self.cfg, self.sstore) |
|
4832 |
if self.op.mode == constants.ALF_MODE_ALLOC: |
|
4833 |
_AllocatorAddNewInstance(data, self.op) |
|
4834 |
else: |
|
4835 |
_AllocatorAddRelocateInstance(data, self.op) |
|
4836 |
|
|
4837 |
if _JSON_INDENT is None: |
|
4838 |
text = simplejson.dumps(data) |
|
4839 |
else: |
|
4840 |
text = simplejson.dumps(data, indent=_JSON_INDENT) |
|
4841 |
return text |
Also available in: Unified diff