Revision b255379d
b/Makefile.am | ||
---|---|---|
1038 | 1038 |
test/data/vgreduce-removemissing-2.02.66-ok.txt \ |
1039 | 1039 |
test/data/vgs-missing-pvs-2.02.02.txt \ |
1040 | 1040 |
test/data/vgs-missing-pvs-2.02.66.txt \ |
1041 |
test/data/xen-xm-list-4.0.1-dom0-only.txt \ |
|
1042 |
test/data/xen-xm-list-4.0.1-four-instances.txt \ |
|
1041 | 1043 |
test/py/ganeti-cli.test \ |
1042 | 1044 |
test/py/gnt-cli.test \ |
1043 | 1045 |
test/py/import-export_unittest-helper |
b/lib/hypervisor/hv_xen.py | ||
---|---|---|
75 | 75 |
return "cpus = [ %s ]" % ", ".join(map(_GetCPUMap, cpu_list)) |
76 | 76 |
|
77 | 77 |
|
78 |
def _RunXmList(fn, xmllist_errors): |
|
79 |
"""Helper function for L{_GetXmList} to run "xm list". |
|
80 |
|
|
81 |
@type fn: callable |
|
82 |
@param fn: Function returning result of running C{xm list} |
|
83 |
@type xmllist_errors: list |
|
84 |
@param xmllist_errors: Error list |
|
85 |
@rtype: list |
|
86 |
|
|
87 |
""" |
|
88 |
result = fn() |
|
89 |
if result.failed: |
|
90 |
logging.error("xm list failed (%s): %s", result.fail_reason, |
|
91 |
result.output) |
|
92 |
xmllist_errors.append(result) |
|
93 |
raise utils.RetryAgain() |
|
94 |
|
|
95 |
# skip over the heading |
|
96 |
return result.stdout.splitlines() |
|
97 |
|
|
98 |
|
|
99 |
def _ParseXmList(lines, include_node): |
|
100 |
"""Parses the output of C{xm list}. |
|
101 |
|
|
102 |
@type lines: list |
|
103 |
@param lines: Output lines of C{xm list} |
|
104 |
@type include_node: boolean |
|
105 |
@param include_node: If True, return information for Dom0 |
|
106 |
@return: list of tuple containing (name, id, memory, vcpus, state, time |
|
107 |
spent) |
|
108 |
|
|
109 |
""" |
|
110 |
result = [] |
|
111 |
|
|
112 |
# Iterate through all lines while ignoring header |
|
113 |
for line in lines[1:]: |
|
114 |
# The format of lines is: |
|
115 |
# Name ID Mem(MiB) VCPUs State Time(s) |
|
116 |
# Domain-0 0 3418 4 r----- 266.2 |
|
117 |
data = line.split() |
|
118 |
if len(data) != 6: |
|
119 |
raise errors.HypervisorError("Can't parse output of xm list," |
|
120 |
" line: %s" % line) |
|
121 |
try: |
|
122 |
data[1] = int(data[1]) |
|
123 |
data[2] = int(data[2]) |
|
124 |
data[3] = int(data[3]) |
|
125 |
data[5] = float(data[5]) |
|
126 |
except (TypeError, ValueError), err: |
|
127 |
raise errors.HypervisorError("Can't parse output of xm list," |
|
128 |
" line: %s, error: %s" % (line, err)) |
|
129 |
|
|
130 |
# skip the Domain-0 (optional) |
|
131 |
if include_node or data[0] != _DOM0_NAME: |
|
132 |
result.append(data) |
|
133 |
|
|
134 |
return result |
|
135 |
|
|
136 |
|
|
137 |
def _GetXmList(fn, include_node, _timeout=5): |
|
138 |
"""Return the list of running instances. |
|
139 |
|
|
140 |
See L{_RunXmList} and L{_ParseXmList} for parameter details. |
|
141 |
|
|
142 |
""" |
|
143 |
xmllist_errors = [] |
|
144 |
try: |
|
145 |
lines = utils.Retry(_RunXmList, (0.3, 1.5, 1.0), _timeout, |
|
146 |
args=(fn, xmllist_errors)) |
|
147 |
except utils.RetryTimeout: |
|
148 |
if xmllist_errors: |
|
149 |
xmlist_result = xmllist_errors.pop() |
|
150 |
|
|
151 |
errmsg = ("xm list failed, timeout exceeded (%s): %s" % |
|
152 |
(xmlist_result.fail_reason, xmlist_result.output)) |
|
153 |
else: |
|
154 |
errmsg = "xm list failed" |
|
155 |
|
|
156 |
raise errors.HypervisorError(errmsg) |
|
157 |
|
|
158 |
return _ParseXmList(lines, include_node) |
|
159 |
|
|
160 |
|
|
78 | 161 |
class XenHypervisor(hv_base.BaseHypervisor): |
79 | 162 |
"""Xen generic hypervisor interface |
80 | 163 |
|
... | ... | |
154 | 237 |
utils.RemoveFile(XenHypervisor._ConfigFileName(instance_name)) |
155 | 238 |
|
156 | 239 |
@staticmethod |
157 |
def _RunXmList(xmlist_errors):
|
|
158 |
"""Helper function for L{_GetXMList} to run "xm list".
|
|
240 |
def _GetXmList(include_node):
|
|
241 |
"""Wrapper around module level L{_GetXmList}.
|
|
159 | 242 |
|
160 | 243 |
""" |
161 |
result = utils.RunCmd([constants.XEN_CMD, "list"]) |
|
162 |
if result.failed: |
|
163 |
logging.error("xm list failed (%s): %s", result.fail_reason, |
|
164 |
result.output) |
|
165 |
xmlist_errors.append(result) |
|
166 |
raise utils.RetryAgain() |
|
167 |
|
|
168 |
# skip over the heading |
|
169 |
return result.stdout.splitlines()[1:] |
|
170 |
|
|
171 |
@classmethod |
|
172 |
def _GetXMList(cls, include_node): |
|
173 |
"""Return the list of running instances. |
|
174 |
|
|
175 |
If the include_node argument is True, then we return information |
|
176 |
for dom0 also, otherwise we filter that from the return value. |
|
177 |
|
|
178 |
@return: list of (name, id, memory, vcpus, state, time spent) |
|
179 |
|
|
180 |
""" |
|
181 |
xmlist_errors = [] |
|
182 |
try: |
|
183 |
lines = utils.Retry(cls._RunXmList, 1, 5, args=(xmlist_errors, )) |
|
184 |
except utils.RetryTimeout: |
|
185 |
if xmlist_errors: |
|
186 |
xmlist_result = xmlist_errors.pop() |
|
187 |
|
|
188 |
errmsg = ("xm list failed, timeout exceeded (%s): %s" % |
|
189 |
(xmlist_result.fail_reason, xmlist_result.output)) |
|
190 |
else: |
|
191 |
errmsg = "xm list failed" |
|
192 |
|
|
193 |
raise errors.HypervisorError(errmsg) |
|
194 |
|
|
195 |
result = [] |
|
196 |
for line in lines: |
|
197 |
# The format of lines is: |
|
198 |
# Name ID Mem(MiB) VCPUs State Time(s) |
|
199 |
# Domain-0 0 3418 4 r----- 266.2 |
|
200 |
data = line.split() |
|
201 |
if len(data) != 6: |
|
202 |
raise errors.HypervisorError("Can't parse output of xm list," |
|
203 |
" line: %s" % line) |
|
204 |
try: |
|
205 |
data[1] = int(data[1]) |
|
206 |
data[2] = int(data[2]) |
|
207 |
data[3] = int(data[3]) |
|
208 |
data[5] = float(data[5]) |
|
209 |
except (TypeError, ValueError), err: |
|
210 |
raise errors.HypervisorError("Can't parse output of xm list," |
|
211 |
" line: %s, error: %s" % (line, err)) |
|
212 |
|
|
213 |
# skip the Domain-0 (optional) |
|
214 |
if include_node or data[0] != _DOM0_NAME: |
|
215 |
result.append(data) |
|
216 |
|
|
217 |
return result |
|
244 |
# TODO: Abstract running Xen command for testing |
|
245 |
return _GetXmList(lambda: utils.RunCmd([constants.XEN_CMD, "list"]), |
|
246 |
include_node) |
|
218 | 247 |
|
219 | 248 |
def ListInstances(self): |
220 | 249 |
"""Get the list of running instances. |
221 | 250 |
|
222 | 251 |
""" |
223 |
xm_list = self._GetXMList(False)
|
|
252 |
xm_list = self._GetXmList(False)
|
|
224 | 253 |
names = [info[0] for info in xm_list] |
225 | 254 |
return names |
226 | 255 |
|
... | ... | |
232 | 261 |
@return: tuple (name, id, memory, vcpus, stat, times) |
233 | 262 |
|
234 | 263 |
""" |
235 |
xm_list = self._GetXMList(instance_name == _DOM0_NAME)
|
|
264 |
xm_list = self._GetXmList(instance_name == _DOM0_NAME)
|
|
236 | 265 |
result = None |
237 | 266 |
for data in xm_list: |
238 | 267 |
if data[0] == instance_name: |
... | ... | |
246 | 275 |
@return: list of tuples (name, id, memory, vcpus, stat, times) |
247 | 276 |
|
248 | 277 |
""" |
249 |
xm_list = self._GetXMList(False)
|
|
278 |
xm_list = self._GetXmList(False)
|
|
250 | 279 |
return xm_list |
251 | 280 |
|
252 | 281 |
def StartInstance(self, instance, block_devices, startup_paused): |
... | ... | |
395 | 424 |
result["cpu_sockets"] = nr_cpus / (cores_per_socket * threads_per_core) |
396 | 425 |
|
397 | 426 |
total_instmem = 0 |
398 |
for (name, _, mem, vcpus, _, _) in self._GetXMList(True):
|
|
427 |
for (name, _, mem, vcpus, _, _) in self._GetXmList(True):
|
|
399 | 428 |
if name == _DOM0_NAME: |
400 | 429 |
result["memory_dom0"] = mem |
401 | 430 |
result["dom0_cpus"] = vcpus |
b/test/data/xen-xm-list-4.0.1-dom0-only.txt | ||
---|---|---|
1 |
Name ID Mem VCPUs State Time(s) |
|
2 |
Domain-0 0 1023 1 r----- 121152.6 |
b/test/data/xen-xm-list-4.0.1-four-instances.txt | ||
---|---|---|
1 |
Name ID Mem VCPUs State Time(s) |
|
2 |
Domain-0 0 1023 1 r----- 154706.1 |
|
3 |
server01.example.com 1 1024 1 -b---- 167643.2 |
|
4 |
web3106215069.example.com 3 4096 1 -b---- 466690.9 |
|
5 |
testinstance.example.com 2 2048 2 r----- 244443.0 |
b/test/py/ganeti.hypervisor.hv_xen_unittest.py | ||
---|---|---|
1 | 1 |
#!/usr/bin/python |
2 | 2 |
# |
3 | 3 |
|
4 |
# Copyright (C) 2011 Google Inc. |
|
4 |
# Copyright (C) 2011, 2013 Google Inc.
|
|
5 | 5 |
# |
6 | 6 |
# This program is free software; you can redistribute it and/or modify |
7 | 7 |
# it under the terms of the GNU General Public License as published by |
... | ... | |
26 | 26 |
from ganeti import constants |
27 | 27 |
from ganeti import objects |
28 | 28 |
from ganeti import hypervisor |
29 |
from ganeti import utils |
|
30 |
from ganeti import errors |
|
31 |
from ganeti import compat |
|
29 | 32 |
|
30 | 33 |
from ganeti.hypervisor import hv_xen |
31 | 34 |
|
... | ... | |
63 | 66 |
constants.CPU_PINNING_ALL_XEN)) |
64 | 67 |
|
65 | 68 |
|
69 |
class TestParseXmList(testutils.GanetiTestCase): |
|
70 |
def test(self): |
|
71 |
data = testutils.ReadTestData("xen-xm-list-4.0.1-dom0-only.txt") |
|
72 |
|
|
73 |
# Exclude node |
|
74 |
self.assertEqual(hv_xen._ParseXmList(data.splitlines(), False), []) |
|
75 |
|
|
76 |
# Include node |
|
77 |
result = hv_xen._ParseXmList(data.splitlines(), True) |
|
78 |
self.assertEqual(len(result), 1) |
|
79 |
self.assertEqual(len(result[0]), 6) |
|
80 |
|
|
81 |
# Name |
|
82 |
self.assertEqual(result[0][0], hv_xen._DOM0_NAME) |
|
83 |
|
|
84 |
# ID |
|
85 |
self.assertEqual(result[0][1], 0) |
|
86 |
|
|
87 |
# Memory |
|
88 |
self.assertEqual(result[0][2], 1023) |
|
89 |
|
|
90 |
# VCPUs |
|
91 |
self.assertEqual(result[0][3], 1) |
|
92 |
|
|
93 |
# State |
|
94 |
self.assertEqual(result[0][4], "r-----") |
|
95 |
|
|
96 |
# Time |
|
97 |
self.assertAlmostEqual(result[0][5], 121152.6) |
|
98 |
|
|
99 |
def testWrongLineFormat(self): |
|
100 |
tests = [ |
|
101 |
["three fields only"], |
|
102 |
["name InvalidID 128 1 r----- 12345"], |
|
103 |
] |
|
104 |
|
|
105 |
for lines in tests: |
|
106 |
try: |
|
107 |
hv_xen._ParseXmList(["Header would be here"] + lines, False) |
|
108 |
except errors.HypervisorError, err: |
|
109 |
self.assertTrue("Can't parse output of xm list" in str(err)) |
|
110 |
else: |
|
111 |
self.fail("Exception was not raised") |
|
112 |
|
|
113 |
|
|
114 |
class TestGetXmList(testutils.GanetiTestCase): |
|
115 |
def _Fail(self): |
|
116 |
return utils.RunResult(constants.EXIT_FAILURE, None, |
|
117 |
"stdout", "stderr", None, |
|
118 |
NotImplemented, NotImplemented) |
|
119 |
|
|
120 |
def testTimeout(self): |
|
121 |
fn = testutils.CallCounter(self._Fail) |
|
122 |
try: |
|
123 |
hv_xen._GetXmList(fn, False, _timeout=0.1) |
|
124 |
except errors.HypervisorError, err: |
|
125 |
self.assertTrue("timeout exceeded" in str(err)) |
|
126 |
else: |
|
127 |
self.fail("Exception was not raised") |
|
128 |
|
|
129 |
self.assertTrue(fn.Count() < 10, |
|
130 |
msg="'xm list' was called too many times") |
|
131 |
|
|
132 |
def _Success(self, stdout): |
|
133 |
return utils.RunResult(constants.EXIT_SUCCESS, None, stdout, "", None, |
|
134 |
NotImplemented, NotImplemented) |
|
135 |
|
|
136 |
def testSuccess(self): |
|
137 |
data = testutils.ReadTestData("xen-xm-list-4.0.1-four-instances.txt") |
|
138 |
|
|
139 |
fn = testutils.CallCounter(compat.partial(self._Success, data)) |
|
140 |
|
|
141 |
result = hv_xen._GetXmList(fn, True, _timeout=0.1) |
|
142 |
|
|
143 |
self.assertEqual(len(result), 4) |
|
144 |
|
|
145 |
self.assertEqual(map(compat.fst, result), [ |
|
146 |
"Domain-0", |
|
147 |
"server01.example.com", |
|
148 |
"web3106215069.example.com", |
|
149 |
"testinstance.example.com", |
|
150 |
]) |
|
151 |
|
|
152 |
self.assertEqual(fn.Count(), 1) |
|
153 |
|
|
154 |
|
|
66 | 155 |
if __name__ == "__main__": |
67 | 156 |
testutils.GanetiTestProgram() |
Also available in: Unified diff