Revision d61df03e
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 |
b/lib/constants.py | ||
---|---|---|
184 | 184 |
VERIFY_NPLUSONE_MEM = 'nplusone_mem' |
185 | 185 |
VERIFY_OPTIONAL_CHECKS = frozenset([VERIFY_NPLUSONE_MEM]) |
186 | 186 |
|
187 |
# Allocator framework constants |
|
188 |
ALF_DIR_IN = "in" |
|
189 |
ALF_DIR_OUT = "out" |
|
190 |
ALF_MODE_ALLOC = "allocate" |
|
191 |
ALF_MODE_RELOC = "relocate" |
b/lib/mcpu.py | ||
---|---|---|
87 | 87 |
opcodes.OpDelTags: cmdlib.LUDelTags, |
88 | 88 |
# test lu |
89 | 89 |
opcodes.OpTestDelay: cmdlib.LUTestDelay, |
90 |
opcodes.OpTestAllocator: cmdlib.LUTestAllocator, |
|
90 | 91 |
} |
91 | 92 |
|
92 | 93 |
def __init__(self, feedback=None): |
b/lib/opcodes.py | ||
---|---|---|
444 | 444 |
""" |
445 | 445 |
OP_ID = "OP_TEST_DELAY" |
446 | 446 |
__slots__ = ["duration", "on_master", "on_nodes"] |
447 |
|
|
448 |
|
|
449 |
class OpTestAllocator(OpCode): |
|
450 |
"""Allocator framework testing. |
|
451 |
|
|
452 |
This opcode has two modes: |
|
453 |
- gather and return allocator input for a given mode (allocate new |
|
454 |
or replace secondary) and a given instance definition (direction |
|
455 |
'in') |
|
456 |
- run a selected allocator for a given operation (as above) and |
|
457 |
return the allocator output (direction 'out') |
|
458 |
|
|
459 |
""" |
|
460 |
OP_ID = "OP_TEST_ALLOCATOR" |
|
461 |
__slots__ = [ |
|
462 |
"direction", "mode", "allocator", "name", |
|
463 |
"mem_size", "disks", "disk_template", |
|
464 |
"os", "tags", "nics", "vcpus", |
|
465 |
] |
b/scripts/gnt-debug | ||
---|---|---|
97 | 97 |
return 0 |
98 | 98 |
|
99 | 99 |
|
100 |
def TestAllocator(opts, args): |
|
101 |
"""Runs the test allocator opcode""" |
|
102 |
|
|
103 |
try: |
|
104 |
disks = [{"size": utils.ParseUnit(val), "mode": 'w'} |
|
105 |
for val in opts.disks.split(",")] |
|
106 |
except errors.UnitParseError, err: |
|
107 |
print >> sys.stderr, "Invalid disks parameter '%s': %s" % (opts.disks, err) |
|
108 |
return 1 |
|
109 |
|
|
110 |
nics = [val.split("/") for val in opts.nics.split(",")] |
|
111 |
for row in nics: |
|
112 |
while len(row) < 3: |
|
113 |
row.append(None) |
|
114 |
for i in range(3): |
|
115 |
if row[i] == '': |
|
116 |
row[i] = None |
|
117 |
nic_dict = [{"mac": v[0], "ip": v[1], "bridge": v[2]} for v in nics] |
|
118 |
|
|
119 |
if opts.tags is None: |
|
120 |
opts.tags = [] |
|
121 |
else: |
|
122 |
opts.tags = opts.tags.split(",") |
|
123 |
|
|
124 |
op = opcodes.OpTestAllocator(mode=opts.mode, |
|
125 |
name=args[0], |
|
126 |
mem_size=opts.mem, |
|
127 |
disks=disks, |
|
128 |
disk_template=opts.disk_template, |
|
129 |
nics=nic_dict, |
|
130 |
os=opts.os_type, |
|
131 |
vcpus=opts.vcpus, |
|
132 |
tags=opts.tags, |
|
133 |
direction=opts.direction, |
|
134 |
allocator=opts.allocator, |
|
135 |
) |
|
136 |
result = SubmitOpCode(op) |
|
137 |
print result |
|
138 |
return 0 |
|
139 |
|
|
140 |
|
|
100 | 141 |
commands = { |
101 | 142 |
'delay': (Delay, ARGS_ONE, |
102 | 143 |
[DEBUG_OPT, |
... | ... | |
113 | 154 |
], |
114 | 155 |
"<op_list_file>", "Submits a job built from a json-file" |
115 | 156 |
" with a list of serialized opcodes"), |
157 |
'allocator': (TestAllocator, ARGS_ONE, |
|
158 |
[DEBUG_OPT, |
|
159 |
make_option("--dir", dest="direction", |
|
160 |
default="in", choices=["in", "out"], |
|
161 |
help="Show allocator input (in) or allocator" |
|
162 |
" results (out)"), |
|
163 |
make_option("--algorithm", dest="allocator", |
|
164 |
default=None, |
|
165 |
help="Allocator algorithm name"), |
|
166 |
make_option("-m", "--mode", default="relocate", |
|
167 |
choices=["relocate", "allocate"], |
|
168 |
help="Request mode, either allocate or" |
|
169 |
"relocate"), |
|
170 |
cli_option("--mem", default=128, type="unit", |
|
171 |
help="Memory size for the instance (MiB)"), |
|
172 |
make_option("--disks", default="4096,4096", |
|
173 |
help="Comma separated list of disk sizes (MiB)"), |
|
174 |
make_option("-t", "--disk-template", default="drbd", |
|
175 |
help="Select the disk template"), |
|
176 |
make_option("--nics", default="00:11:22:33:44:55", |
|
177 |
help="Comma separated list of nics, each nic" |
|
178 |
" definition is of form mac/ip/bridge, if" |
|
179 |
" missing values are replace by None"), |
|
180 |
make_option("-o", "--os-type", default=None, |
|
181 |
help="Select os for the instance"), |
|
182 |
make_option("-p", "--vcpus", default=1, type="int", |
|
183 |
help="Select number of VCPUs for the instance"), |
|
184 |
make_option("--tags", default=None, |
|
185 |
help="Comma separated list of tags"), |
|
186 |
], |
|
187 |
"{opts...} <instance>", "Executes a TestAllocator OpCode"), |
|
116 | 188 |
} |
117 | 189 |
|
118 | 190 |
|
Also available in: Unified diff