1 | # (C) Copyright IBM Corp. 2005 |
---|
2 | # Copyright (C) 2004 Mike Wray |
---|
3 | # Copyright (c) 2005-2006 XenSource Ltd. |
---|
4 | # |
---|
5 | # Authors: |
---|
6 | # Sean Dague <sean at dague dot net> |
---|
7 | # Mike Wray <mike dot wray at hp dot com> |
---|
8 | # |
---|
9 | # This library is free software; you can redistribute it and/or |
---|
10 | # modify it under the terms of version 2.1 of the GNU Lesser General Public |
---|
11 | # License as published by the Free Software Foundation. |
---|
12 | # |
---|
13 | # This library is distributed in the hope that it will be useful, |
---|
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
16 | # Lesser General Public License for more details. |
---|
17 | # |
---|
18 | # You should have received a copy of the GNU Lesser General Public |
---|
19 | # License along with this library; if not, write to the Free Software |
---|
20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
21 | |
---|
22 | """Grand unified management application for Xen. |
---|
23 | """ |
---|
24 | import atexit |
---|
25 | import cmd |
---|
26 | import os |
---|
27 | import pprint |
---|
28 | import readline |
---|
29 | import shlex |
---|
30 | import sys |
---|
31 | import re |
---|
32 | import getopt |
---|
33 | import socket |
---|
34 | import traceback |
---|
35 | import xmlrpclib |
---|
36 | import time |
---|
37 | import datetime |
---|
38 | from select import select |
---|
39 | import xml.dom.minidom |
---|
40 | from xen.util.blkif import blkdev_name_to_number |
---|
41 | |
---|
42 | import warnings |
---|
43 | warnings.filterwarnings('ignore', category=FutureWarning) |
---|
44 | |
---|
45 | from xen.xend import PrettyPrint |
---|
46 | from xen.xend import sxp |
---|
47 | from xen.xend import XendClient |
---|
48 | from xen.xend.XendConstants import * |
---|
49 | |
---|
50 | from xen.xm.opts import OptionError, Opts, wrap, set_true |
---|
51 | from xen.xm import console |
---|
52 | from xen.util.xmlrpcclient import ServerProxy |
---|
53 | |
---|
54 | import XenAPI |
---|
55 | |
---|
56 | |
---|
57 | # getopt.gnu_getopt is better, but only exists in Python 2.3+. Use |
---|
58 | # getopt.getopt if gnu_getopt is not available. This will mean that options |
---|
59 | # may only be specified before positional arguments. |
---|
60 | if not hasattr(getopt, 'gnu_getopt'): |
---|
61 | getopt.gnu_getopt = getopt.getopt |
---|
62 | |
---|
63 | XM_CONFIG_FILE_ENVVAR = 'XM_CONFIG_FILE' |
---|
64 | XM_CONFIG_FILE_DEFAULT = '/etc/xen/xm-config.xml' |
---|
65 | |
---|
66 | # Supported types of server |
---|
67 | SERVER_LEGACY_XMLRPC = 'LegacyXMLRPC' |
---|
68 | SERVER_XEN_API = 'Xen-API' |
---|
69 | |
---|
70 | # General help message |
---|
71 | |
---|
72 | USAGE_HELP = "Usage: xm <subcommand> [args]\n\n" \ |
---|
73 | "Control, list, and manipulate Xen guest instances.\n" |
---|
74 | |
---|
75 | USAGE_FOOTER = '<Domain> can either be the Domain Name or Id.\n' \ |
---|
76 | 'For more help on \'xm\' see the xm(1) man page.\n' \ |
---|
77 | 'For more help on \'xm create\' see the xmdomain.cfg(5) '\ |
---|
78 | ' man page.\n' |
---|
79 | |
---|
80 | # Help strings are indexed by subcommand name in this way: |
---|
81 | # 'subcommand': (argstring, description) |
---|
82 | |
---|
83 | SUBCOMMAND_HELP = { |
---|
84 | # common commands |
---|
85 | |
---|
86 | 'shell' : ('', 'Launch an interactive shell.'), |
---|
87 | |
---|
88 | 'console' : ('[-q|--quiet] <Domain>', |
---|
89 | 'Attach to <Domain>\'s console.'), |
---|
90 | 'create' : ('<ConfigFile> [options] [vars]', |
---|
91 | 'Create a domain based on <ConfigFile>.'), |
---|
92 | 'destroy' : ('<Domain>', |
---|
93 | 'Terminate a domain immediately.'), |
---|
94 | 'help' : ('', 'Display this message.'), |
---|
95 | 'list' : ('[options] [Domain, ...]', |
---|
96 | 'List information about all/some domains.'), |
---|
97 | 'mem-max' : ('<Domain> <Mem>', |
---|
98 | 'Set the maximum amount reservation for a domain.'), |
---|
99 | 'mem-set' : ('<Domain> <Mem>', |
---|
100 | 'Set the current memory usage for a domain.'), |
---|
101 | 'migrate' : ('<Domain> <Host>', |
---|
102 | 'Migrate a domain to another machine.'), |
---|
103 | 'pause' : ('<Domain>', 'Pause execution of a domain.'), |
---|
104 | 'reboot' : ('<Domain> [-wa]', 'Reboot a domain.'), |
---|
105 | 'restore' : ('<CheckpointFile> [-p]', |
---|
106 | 'Restore a domain from a saved state.'), |
---|
107 | 'save' : ('[-c] <Domain> <CheckpointFile>', |
---|
108 | 'Save a domain state to restore later.'), |
---|
109 | 'shutdown' : ('<Domain> [-waRH]', 'Shutdown a domain.'), |
---|
110 | 'top' : ('', 'Monitor a host and the domains in real time.'), |
---|
111 | 'unpause' : ('<Domain>', 'Unpause a paused domain.'), |
---|
112 | 'uptime' : ('[-s] <Domain>', 'Print uptime for a domain.'), |
---|
113 | |
---|
114 | # Life cycle xm commands |
---|
115 | 'new' : ('<ConfigFile> [options] [vars]', |
---|
116 | 'Adds a domain to Xend domain management'), |
---|
117 | 'delete' : ('<DomainName>', |
---|
118 | 'Remove a domain from Xend domain management.'), |
---|
119 | 'start' : ('<DomainName>', 'Start a Xend managed domain'), |
---|
120 | 'resume' : ('<DomainName>', 'Resume a Xend managed domain'), |
---|
121 | 'suspend' : ('<DomainName>', 'Suspend a Xend managed domain'), |
---|
122 | |
---|
123 | # less used commands |
---|
124 | |
---|
125 | 'dmesg' : ('[-c|--clear]', |
---|
126 | 'Read and/or clear Xend\'s message buffer.'), |
---|
127 | 'domid' : ('<DomainName>', 'Convert a domain name to domain id.'), |
---|
128 | 'domname' : ('<DomId>', 'Convert a domain id to domain name.'), |
---|
129 | 'dump-core' : ('[-L|--live] [-C|--crash] <Domain> [Filename]', |
---|
130 | 'Dump core for a specific domain.'), |
---|
131 | 'info' : ('', 'Get information about Xen host.'), |
---|
132 | 'log' : ('', 'Print Xend log'), |
---|
133 | 'rename' : ('<Domain> <NewDomainName>', 'Rename a domain.'), |
---|
134 | 'sched-sedf' : ('<Domain> [options]', 'Get/set EDF parameters.'), |
---|
135 | 'sched-credit': ('[-d <Domain> [-w[=WEIGHT]|-c[=CAP]]]', |
---|
136 | 'Get/set credit scheduler parameters.'), |
---|
137 | 'sysrq' : ('<Domain> <letter>', 'Send a sysrq to a domain.'), |
---|
138 | 'debug-keys' : ('<Keys>', 'Send debug keys to Xen.'), |
---|
139 | 'trigger' : ('<Domain> <nmi|reset|init> [<VCPU>]', |
---|
140 | 'Send a trigger to a domain.'), |
---|
141 | 'vcpu-list' : ('[<Domain>]', |
---|
142 | 'List the VCPUs for a domain or all domains.'), |
---|
143 | 'vcpu-pin' : ('<Domain> <VCPU> <CPUs|all>', |
---|
144 | 'Set which CPUs a VCPU can use.'), |
---|
145 | 'vcpu-set' : ('<Domain> <vCPUs>', |
---|
146 | 'Set the number of active VCPUs for allowed for the' |
---|
147 | ' domain.'), |
---|
148 | |
---|
149 | # device commands |
---|
150 | |
---|
151 | 'block-attach' : ('<Domain> <BackDev> <FrontDev> <Mode> [BackDomain]', |
---|
152 | 'Create a new virtual block device.'), |
---|
153 | 'block-configure': ('<Domain> <BackDev> <FrontDev> <Mode> [BackDomain]', |
---|
154 | 'Change block device configuration'), |
---|
155 | 'block-detach' : ('<Domain> <DevId> [-f|--force]', |
---|
156 | 'Destroy a domain\'s virtual block device.'), |
---|
157 | 'block-list' : ('<Domain> [--long]', |
---|
158 | 'List virtual block devices for a domain.'), |
---|
159 | 'network-attach': ('<Domain> [type=<type>] [mac=<mac>] [bridge=<bridge>] ' |
---|
160 | '[ip=<ip>] [script=<script>] [backend=<BackDomain>] ' |
---|
161 | '[vifname=<name>] [rate=<rate>] [model=<model>]', |
---|
162 | 'Create a new virtual network device.'), |
---|
163 | 'network-detach': ('<Domain> <DevId> [-f|--force]', |
---|
164 | 'Destroy a domain\'s virtual network device.'), |
---|
165 | 'network-list' : ('<Domain> [--long]', |
---|
166 | 'List virtual network interfaces for a domain.'), |
---|
167 | 'vnet-create' : ('<ConfigFile>','Create a vnet from ConfigFile.'), |
---|
168 | 'vnet-delete' : ('<VnetId>', 'Delete a Vnet.'), |
---|
169 | 'vnet-list' : ('[-l|--long]', 'List Vnets.'), |
---|
170 | 'vtpm-list' : ('<Domain> [--long]', 'List virtual TPM devices.'), |
---|
171 | |
---|
172 | # security |
---|
173 | |
---|
174 | 'addlabel' : ('<label> {dom <ConfigFile>|res <resource>} [<policy>]', |
---|
175 | 'Add security label to domain.'), |
---|
176 | 'rmlabel' : ('{dom <ConfigFile>|res <Resource>}', |
---|
177 | 'Remove a security label from domain.'), |
---|
178 | 'getlabel' : ('{dom <ConfigFile>|res <Resource>}', |
---|
179 | 'Show security label for domain or resource.'), |
---|
180 | 'dry-run' : ('<ConfigFile>', |
---|
181 | 'Test if a domain can access its resources.'), |
---|
182 | 'resources' : ('', 'Show info for each labeled resource.'), |
---|
183 | 'cfgbootpolicy' : ('<policy> [boot-title]', |
---|
184 | 'Add policy to boot configuration.'), |
---|
185 | 'dumppolicy' : ('', 'Print hypervisor ACM state information.'), |
---|
186 | 'loadpolicy' : ('<policy.bin>', 'Load binary policy into hypervisor.'), |
---|
187 | 'makepolicy' : ('<policy>', 'Build policy and create .bin/.map ' |
---|
188 | 'files.'), |
---|
189 | 'labels' : ('[policy] [type=dom|res|any]', |
---|
190 | 'List <type> labels for (active) policy.'), |
---|
191 | 'serve' : ('', 'Proxy Xend XMLRPC over stdio.'), |
---|
192 | } |
---|
193 | |
---|
194 | SUBCOMMAND_OPTIONS = { |
---|
195 | 'sched-sedf': ( |
---|
196 | ('-p [MS]', '--period[=MS]', 'Relative deadline(ms)'), |
---|
197 | ('-s [MS]', '--slice[=MS]' , |
---|
198 | 'Worst-case execution time(ms). (slice < period)'), |
---|
199 | ('-l [MS]', '--latency[=MS]', |
---|
200 | 'Scaled period (ms) when domain performs heavy I/O'), |
---|
201 | ('-e [FLAG]', '--extra[=FLAG]', |
---|
202 | 'Flag (0 or 1) controls if domain can run in extra time.'), |
---|
203 | ('-w [FLOAT]', '--weight[=FLOAT]', |
---|
204 | 'CPU Period/slice (do not set with --period/--slice)'), |
---|
205 | ), |
---|
206 | 'sched-credit': ( |
---|
207 | ('-d DOMAIN', '--domain=DOMAIN', 'Domain to modify'), |
---|
208 | ('-w WEIGHT', '--weight=WEIGHT', 'Weight (int)'), |
---|
209 | ('-c CAP', '--cap=CAP', 'Cap (int)'), |
---|
210 | ), |
---|
211 | 'list': ( |
---|
212 | ('-l', '--long', 'Output all VM details in SXP'), |
---|
213 | ('', '--label', 'Include security labels'), |
---|
214 | ('', '--state=<state>', 'Select only VMs with the specified state'), |
---|
215 | ), |
---|
216 | 'console': ( |
---|
217 | ('-q', '--quiet', 'Do not print an error message if the domain does not exist'), |
---|
218 | ), |
---|
219 | 'dmesg': ( |
---|
220 | ('-c', '--clear', 'Clear dmesg buffer as well as printing it'), |
---|
221 | ), |
---|
222 | 'vnet-list': ( |
---|
223 | ('-l', '--long', 'List Vnets as SXP'), |
---|
224 | ), |
---|
225 | 'network-list': ( |
---|
226 | ('-l', '--long', 'List resources as SXP'), |
---|
227 | ), |
---|
228 | 'dump-core': ( |
---|
229 | ('-L', '--live', 'Dump core without pausing the domain'), |
---|
230 | ('-C', '--crash', 'Crash domain after dumping core'), |
---|
231 | ), |
---|
232 | 'start': ( |
---|
233 | ('-p', '--paused', 'Do not unpause domain after starting it'), |
---|
234 | ), |
---|
235 | 'resume': ( |
---|
236 | ('-p', '--paused', 'Do not unpause domain after resuming it'), |
---|
237 | ), |
---|
238 | 'save': ( |
---|
239 | ('-c', '--checkpoint', 'Leave domain running after creating snapshot'), |
---|
240 | ), |
---|
241 | 'restore': ( |
---|
242 | ('-p', '--paused', 'Do not unpause domain after restoring it'), |
---|
243 | ), |
---|
244 | } |
---|
245 | |
---|
246 | common_commands = [ |
---|
247 | "console", |
---|
248 | "create", |
---|
249 | "new", |
---|
250 | "delete", |
---|
251 | "destroy", |
---|
252 | "dump-core", |
---|
253 | "help", |
---|
254 | "list", |
---|
255 | "mem-set", |
---|
256 | "migrate", |
---|
257 | "pause", |
---|
258 | "reboot", |
---|
259 | "restore", |
---|
260 | "resume", |
---|
261 | "save", |
---|
262 | "shell", |
---|
263 | "shutdown", |
---|
264 | "start", |
---|
265 | "suspend", |
---|
266 | "top", |
---|
267 | "unpause", |
---|
268 | "uptime", |
---|
269 | "vcpu-set", |
---|
270 | ] |
---|
271 | |
---|
272 | domain_commands = [ |
---|
273 | "console", |
---|
274 | "create", |
---|
275 | "new", |
---|
276 | "delete", |
---|
277 | "destroy", |
---|
278 | "domid", |
---|
279 | "domname", |
---|
280 | "dump-core", |
---|
281 | "list", |
---|
282 | "mem-max", |
---|
283 | "mem-set", |
---|
284 | "migrate", |
---|
285 | "pause", |
---|
286 | "reboot", |
---|
287 | "rename", |
---|
288 | "restore", |
---|
289 | "resume", |
---|
290 | "save", |
---|
291 | "shutdown", |
---|
292 | "start", |
---|
293 | "suspend", |
---|
294 | "sysrq", |
---|
295 | "trigger", |
---|
296 | "top", |
---|
297 | "unpause", |
---|
298 | "uptime", |
---|
299 | "vcpu-list", |
---|
300 | "vcpu-pin", |
---|
301 | "vcpu-set", |
---|
302 | ] |
---|
303 | |
---|
304 | host_commands = [ |
---|
305 | "debug-keys", |
---|
306 | "dmesg", |
---|
307 | "info", |
---|
308 | "log", |
---|
309 | "serve", |
---|
310 | ] |
---|
311 | |
---|
312 | scheduler_commands = [ |
---|
313 | "sched-credit", |
---|
314 | "sched-sedf", |
---|
315 | ] |
---|
316 | |
---|
317 | device_commands = [ |
---|
318 | "block-attach", |
---|
319 | "block-detach", |
---|
320 | "block-list", |
---|
321 | "block-configure", |
---|
322 | "network-attach", |
---|
323 | "network-detach", |
---|
324 | "network-list", |
---|
325 | "vtpm-list", |
---|
326 | ] |
---|
327 | |
---|
328 | vnet_commands = [ |
---|
329 | "vnet-list", |
---|
330 | "vnet-create", |
---|
331 | "vnet-delete", |
---|
332 | ] |
---|
333 | |
---|
334 | acm_commands = [ |
---|
335 | "labels", |
---|
336 | "addlabel", |
---|
337 | "rmlabel", |
---|
338 | "getlabel", |
---|
339 | "dry-run", |
---|
340 | "resources", |
---|
341 | "makepolicy", |
---|
342 | "loadpolicy", |
---|
343 | "cfgbootpolicy", |
---|
344 | "dumppolicy", |
---|
345 | ] |
---|
346 | |
---|
347 | all_commands = (domain_commands + host_commands + scheduler_commands + |
---|
348 | device_commands + vnet_commands + acm_commands + |
---|
349 | ['shell', 'event-monitor']) |
---|
350 | |
---|
351 | |
---|
352 | ## |
---|
353 | # Configuration File Parsing |
---|
354 | ## |
---|
355 | |
---|
356 | xmConfigFile = os.getenv(XM_CONFIG_FILE_ENVVAR, XM_CONFIG_FILE_DEFAULT) |
---|
357 | config = None |
---|
358 | if os.path.isfile(xmConfigFile): |
---|
359 | try: |
---|
360 | config = xml.dom.minidom.parse(xmConfigFile) |
---|
361 | except: |
---|
362 | print >>sys.stderr, ('Ignoring invalid configuration file %s.' % |
---|
363 | xmConfigFile) |
---|
364 | |
---|
365 | def parseServer(): |
---|
366 | if config: |
---|
367 | server = config.getElementsByTagName('server') |
---|
368 | if server: |
---|
369 | st = server[0].getAttribute('type') |
---|
370 | if st != SERVER_XEN_API and st != SERVER_LEGACY_XMLRPC: |
---|
371 | print >>sys.stderr, ('Invalid server type %s; using %s.' % |
---|
372 | (st, SERVER_LEGACY_XMLRPC)) |
---|
373 | st = SERVER_LEGACY_XMLRPC |
---|
374 | return (st, server[0].getAttribute('uri')) |
---|
375 | |
---|
376 | return SERVER_LEGACY_XMLRPC, XendClient.uri |
---|
377 | |
---|
378 | def parseAuthentication(): |
---|
379 | server = config.getElementsByTagName('server')[0] |
---|
380 | return (server.getAttribute('username'), |
---|
381 | server.getAttribute('password')) |
---|
382 | |
---|
383 | serverType, serverURI = parseServer() |
---|
384 | server = None |
---|
385 | |
---|
386 | |
---|
387 | #################################################################### |
---|
388 | # |
---|
389 | # Help/usage printing functions |
---|
390 | # |
---|
391 | #################################################################### |
---|
392 | |
---|
393 | def cmdHelp(cmd): |
---|
394 | """Print help for a specific subcommand.""" |
---|
395 | |
---|
396 | for fc in SUBCOMMAND_HELP.keys(): |
---|
397 | if fc[:len(cmd)] == cmd: |
---|
398 | cmd = fc |
---|
399 | break |
---|
400 | |
---|
401 | try: |
---|
402 | args, desc = SUBCOMMAND_HELP[cmd] |
---|
403 | except KeyError: |
---|
404 | shortHelp() |
---|
405 | return |
---|
406 | |
---|
407 | print 'Usage: xm %s %s' % (cmd, args) |
---|
408 | print |
---|
409 | print desc |
---|
410 | |
---|
411 | try: |
---|
412 | # If options help message is defined, print this. |
---|
413 | for shortopt, longopt, desc in SUBCOMMAND_OPTIONS[cmd]: |
---|
414 | if shortopt and longopt: |
---|
415 | optdesc = '%s, %s' % (shortopt, longopt) |
---|
416 | elif shortopt: |
---|
417 | optdesc = shortopt |
---|
418 | elif longopt: |
---|
419 | optdesc = longopt |
---|
420 | |
---|
421 | wrapped_desc = wrap(desc, 43) |
---|
422 | print ' %-30s %-43s' % (optdesc, wrapped_desc[0]) |
---|
423 | for line in wrapped_desc[1:]: |
---|
424 | print ' ' * 33 + line |
---|
425 | print |
---|
426 | except KeyError: |
---|
427 | # if the command is an external module, we grab usage help |
---|
428 | # from the module itself. |
---|
429 | if cmd in IMPORTED_COMMANDS: |
---|
430 | try: |
---|
431 | cmd_module = __import__(cmd, globals(), locals(), 'xen.xm') |
---|
432 | cmd_usage = getattr(cmd_module, "help", None) |
---|
433 | if cmd_usage: |
---|
434 | print cmd_usage() |
---|
435 | except ImportError: |
---|
436 | pass |
---|
437 | |
---|
438 | def shortHelp(): |
---|
439 | """Print out generic help when xm is called without subcommand.""" |
---|
440 | |
---|
441 | print USAGE_HELP |
---|
442 | print 'Common \'xm\' commands:\n' |
---|
443 | |
---|
444 | for command in common_commands: |
---|
445 | try: |
---|
446 | args, desc = SUBCOMMAND_HELP[command] |
---|
447 | except KeyError: |
---|
448 | continue |
---|
449 | wrapped_desc = wrap(desc, 50) |
---|
450 | print ' %-20s %-50s' % (command, wrapped_desc[0]) |
---|
451 | for line in wrapped_desc[1:]: |
---|
452 | print ' ' * 22 + line |
---|
453 | |
---|
454 | print |
---|
455 | print USAGE_FOOTER |
---|
456 | print 'For a complete list of subcommands run \'xm help\'.' |
---|
457 | |
---|
458 | def longHelp(): |
---|
459 | """Print out full help when xm is called with xm --help or xm help""" |
---|
460 | |
---|
461 | print USAGE_HELP |
---|
462 | print 'xm full list of subcommands:\n' |
---|
463 | |
---|
464 | for command in all_commands: |
---|
465 | try: |
---|
466 | args, desc = SUBCOMMAND_HELP[command] |
---|
467 | except KeyError: |
---|
468 | continue |
---|
469 | |
---|
470 | wrapped_desc = wrap(desc, 50) |
---|
471 | print ' %-20s %-50s' % (command, wrapped_desc[0]) |
---|
472 | for line in wrapped_desc[1:]: |
---|
473 | print ' ' * 22 + line |
---|
474 | |
---|
475 | print |
---|
476 | print USAGE_FOOTER |
---|
477 | |
---|
478 | def _usage(cmd): |
---|
479 | """ Print help usage information """ |
---|
480 | if cmd: |
---|
481 | cmdHelp(cmd) |
---|
482 | else: |
---|
483 | shortHelp() |
---|
484 | |
---|
485 | def usage(cmd = None): |
---|
486 | """ Print help usage information and exits """ |
---|
487 | _usage(cmd) |
---|
488 | sys.exit(1) |
---|
489 | |
---|
490 | |
---|
491 | #################################################################### |
---|
492 | # |
---|
493 | # Utility functions |
---|
494 | # |
---|
495 | #################################################################### |
---|
496 | |
---|
497 | def get_default_SR(): |
---|
498 | return [sr_ref |
---|
499 | for sr_ref in server.xenapi.SR.get_all() |
---|
500 | if server.xenapi.SR.get_type(sr_ref) == "local"][0] |
---|
501 | |
---|
502 | def get_default_Network(): |
---|
503 | return [network_ref |
---|
504 | for network_ref in server.xenapi.network.get_all()][0] |
---|
505 | |
---|
506 | class XenAPIUnsupportedException(Exception): |
---|
507 | pass |
---|
508 | |
---|
509 | def xenapi_unsupported(): |
---|
510 | if serverType == SERVER_XEN_API: |
---|
511 | raise XenAPIUnsupportedException, "This function is not supported by Xen-API" |
---|
512 | |
---|
513 | def xenapi_only(): |
---|
514 | if serverType != SERVER_XEN_API: |
---|
515 | raise XenAPIUnsupportedException, "This function is only supported by Xen-API" |
---|
516 | |
---|
517 | def map2sxp(m): |
---|
518 | return [[k, m[k]] for k in m.keys()] |
---|
519 | |
---|
520 | def arg_check(args, name, lo, hi = -1): |
---|
521 | n = len([i for i in args if i != '--']) |
---|
522 | |
---|
523 | if hi == -1: |
---|
524 | if n != lo: |
---|
525 | err("'xm %s' requires %d argument%s.\n" % (name, lo, |
---|
526 | lo == 1 and '' or 's')) |
---|
527 | usage(name) |
---|
528 | else: |
---|
529 | if n < lo or n > hi: |
---|
530 | err("'xm %s' requires between %d and %d arguments.\n" % |
---|
531 | (name, lo, hi)) |
---|
532 | usage(name) |
---|
533 | |
---|
534 | |
---|
535 | def unit(c): |
---|
536 | if not c.isalpha(): |
---|
537 | return 0 |
---|
538 | base = 1 |
---|
539 | if c == 'G' or c == 'g': base = 1024 * 1024 * 1024 |
---|
540 | elif c == 'M' or c == 'm': base = 1024 * 1024 |
---|
541 | elif c == 'K' or c == 'k': base = 1024 |
---|
542 | else: |
---|
543 | print 'ignoring unknown unit' |
---|
544 | return base |
---|
545 | |
---|
546 | def int_unit(str, dest): |
---|
547 | base = unit(str[-1]) |
---|
548 | if not base: |
---|
549 | return int(str) |
---|
550 | |
---|
551 | value = int(str[:-1]) |
---|
552 | dst_base = unit(dest) |
---|
553 | if dst_base == 0: |
---|
554 | dst_base = 1 |
---|
555 | if dst_base > base: |
---|
556 | return value / (dst_base / base) |
---|
557 | else: |
---|
558 | return value * (base / dst_base) |
---|
559 | |
---|
560 | def err(msg): |
---|
561 | print >>sys.stderr, "Error:", msg |
---|
562 | |
---|
563 | |
---|
564 | def get_single_vm(dom): |
---|
565 | if serverType == SERVER_XEN_API: |
---|
566 | uuids = server.xenapi.VM.get_by_name_label(dom) |
---|
567 | if len(uuids) > 0: |
---|
568 | return uuids[0] |
---|
569 | |
---|
570 | refs = [] |
---|
571 | |
---|
572 | try: |
---|
573 | domid = int(dom) |
---|
574 | refs = [vm_ref |
---|
575 | for vm_ref in server.xenapi.VM.get_all() |
---|
576 | if int(server.xenapi.VM.get_domid(vm_ref)) == domid] |
---|
577 | except: |
---|
578 | pass |
---|
579 | |
---|
580 | if len(refs) > 0: |
---|
581 | return refs[0] |
---|
582 | |
---|
583 | raise OptionError("Domain '%s' not found." % dom) |
---|
584 | else: |
---|
585 | dominfo = server.xend.domain(dom, False) |
---|
586 | return dominfo['uuid'] |
---|
587 | |
---|
588 | ## |
---|
589 | # |
---|
590 | # Xen-API Shell |
---|
591 | # |
---|
592 | ## |
---|
593 | |
---|
594 | class Shell(cmd.Cmd): |
---|
595 | def __init__(self): |
---|
596 | cmd.Cmd.__init__(self) |
---|
597 | self.prompt = "xm> " |
---|
598 | if serverType == SERVER_XEN_API: |
---|
599 | try: |
---|
600 | res = server.xenapi.host.list_methods() |
---|
601 | for f in res: |
---|
602 | setattr(Shell, 'do_' + f + ' ', self.default) |
---|
603 | except: |
---|
604 | pass |
---|
605 | |
---|
606 | def preloop(self): |
---|
607 | cmd.Cmd.preloop(self) |
---|
608 | readline.set_completer_delims(' ') |
---|
609 | |
---|
610 | def default(self, line): |
---|
611 | words = shlex.split(line) |
---|
612 | if len(words) > 0 and words[0] == 'xm': |
---|
613 | words = words[1:] |
---|
614 | if len(words) > 0: |
---|
615 | cmd = xm_lookup_cmd(words[0]) |
---|
616 | if cmd: |
---|
617 | _run_cmd(cmd, words[0], words[1:]) |
---|
618 | elif serverType == SERVER_XEN_API: |
---|
619 | ok, res = _run_cmd(lambda x: server.xenapi_request(words[0], |
---|
620 | tuple(x)), |
---|
621 | words[0], words[1:]) |
---|
622 | if ok and res is not None and res != '': |
---|
623 | pprint.pprint(res) |
---|
624 | else: |
---|
625 | print '*** Unknown command: %s' % words[0] |
---|
626 | return False |
---|
627 | |
---|
628 | def completedefault(self, text, line, begidx, endidx): |
---|
629 | words = shlex.split(line[:begidx]) |
---|
630 | clas, func = words[0].split('.') |
---|
631 | if len(words) > 1 or \ |
---|
632 | func.startswith('get_by_') or \ |
---|
633 | func == 'get_all': |
---|
634 | return [] |
---|
635 | uuids = server.xenapi_request('%s.get_all' % clas, ()) |
---|
636 | return [u + " " for u in uuids if u.startswith(text)] |
---|
637 | |
---|
638 | def emptyline(self): |
---|
639 | pass |
---|
640 | |
---|
641 | def do_EOF(self, line): |
---|
642 | print |
---|
643 | sys.exit(0) |
---|
644 | |
---|
645 | def do_help(self, line): |
---|
646 | _usage(line) |
---|
647 | |
---|
648 | |
---|
649 | def xm_shell(args): |
---|
650 | Shell().cmdloop('The Xen Master. Type "help" for a list of functions.') |
---|
651 | |
---|
652 | |
---|
653 | def xm_event_monitor(args): |
---|
654 | if serverType == SERVER_XEN_API: |
---|
655 | while True: |
---|
656 | server.xenapi.event.register(args) |
---|
657 | events = server.xenapi.event.next() |
---|
658 | for e in events: |
---|
659 | print e |
---|
660 | else: |
---|
661 | err("Event monitoring not supported unless using Xen-API.") |
---|
662 | |
---|
663 | |
---|
664 | ######################################################################### |
---|
665 | # |
---|
666 | # Main xm functions |
---|
667 | # |
---|
668 | ######################################################################### |
---|
669 | |
---|
670 | def xm_save(args): |
---|
671 | |
---|
672 | arg_check(args, "save", 2, 3) |
---|
673 | |
---|
674 | try: |
---|
675 | (options, params) = getopt.gnu_getopt(args, 'c', ['checkpoint']) |
---|
676 | except getopt.GetoptError, opterr: |
---|
677 | err(opterr) |
---|
678 | sys.exit(1) |
---|
679 | |
---|
680 | dom = params[0] |
---|
681 | savefile = params[1] |
---|
682 | |
---|
683 | checkpoint = False |
---|
684 | for (k, v) in options: |
---|
685 | if k in ['-c', '--checkpoint']: |
---|
686 | checkpoint = True |
---|
687 | |
---|
688 | if len(params) != 2: |
---|
689 | err("Wrong number of parameters") |
---|
690 | usage('save') |
---|
691 | sys.exit(1) |
---|
692 | |
---|
693 | savefile = os.path.abspath(savefile) |
---|
694 | |
---|
695 | if not os.access(os.path.dirname(savefile), os.W_OK): |
---|
696 | err("xm save: Unable to create file %s" % savefile) |
---|
697 | sys.exit(1) |
---|
698 | |
---|
699 | if serverType == SERVER_XEN_API: |
---|
700 | server.xenapi.VM.save(get_single_vm(dom), savefile, checkpoint) |
---|
701 | else: |
---|
702 | try: |
---|
703 | dominfo = parse_doms_info(server.xend.domain(dom)) |
---|
704 | except xmlrpclib.Fault, ex: |
---|
705 | raise ex |
---|
706 | |
---|
707 | domid = dominfo['domid'] |
---|
708 | server.xend.domain.save(domid, savefile, checkpoint) |
---|
709 | |
---|
710 | def xm_restore(args): |
---|
711 | arg_check(args, "restore", 1, 2) |
---|
712 | |
---|
713 | try: |
---|
714 | (options, params) = getopt.gnu_getopt(args, 'p', ['paused']) |
---|
715 | except getopt.GetoptError, opterr: |
---|
716 | err(opterr) |
---|
717 | usage('restore') |
---|
718 | |
---|
719 | paused = False |
---|
720 | for (k, v) in options: |
---|
721 | if k in ['-p', '--paused']: |
---|
722 | paused = True |
---|
723 | |
---|
724 | if len(params) != 1: |
---|
725 | err("Wrong number of parameters") |
---|
726 | usage('restore') |
---|
727 | |
---|
728 | savefile = os.path.abspath(params[0]) |
---|
729 | |
---|
730 | if not os.access(savefile, os.R_OK): |
---|
731 | err("xm restore: Unable to read file %s" % savefile) |
---|
732 | sys.exit(1) |
---|
733 | |
---|
734 | if serverType == SERVER_XEN_API: |
---|
735 | server.xenapi.VM.restore(savefile, paused) |
---|
736 | else: |
---|
737 | server.xend.domain.restore(savefile, paused) |
---|
738 | |
---|
739 | |
---|
740 | def datetime_to_secs(v): |
---|
741 | unwanted = ":-." |
---|
742 | for c in unwanted: |
---|
743 | v = str(v).replace(c, "") |
---|
744 | return time.mktime(time.strptime(v[0:14], '%Y%m%dT%H%M%S')) |
---|
745 | |
---|
746 | def getDomains(domain_names, state, full = 0): |
---|
747 | if serverType == SERVER_XEN_API: |
---|
748 | doms_sxp = [] |
---|
749 | doms_dict = [] |
---|
750 | |
---|
751 | dom_recs = server.xenapi.VM.get_all_records() |
---|
752 | dom_metrics_recs = server.xenapi.VM_metrics.get_all_records() |
---|
753 | |
---|
754 | for dom_ref, dom_rec in dom_recs.items(): |
---|
755 | dom_metrics_rec = dom_metrics_recs[dom_rec['metrics']] |
---|
756 | |
---|
757 | states = ('running', 'blocked', 'paused', 'shutdown', |
---|
758 | 'crashed', 'dying') |
---|
759 | def state_on_off(state): |
---|
760 | if state in dom_metrics_rec['state']: |
---|
761 | return state[0] |
---|
762 | else: |
---|
763 | return "-" |
---|
764 | state_str = "".join([state_on_off(state) |
---|
765 | for state in states]) |
---|
766 | |
---|
767 | dom_rec.update({'name': dom_rec['name_label'], |
---|
768 | 'memory_actual': int(dom_metrics_rec['memory_actual'])/1024, |
---|
769 | 'vcpus': dom_metrics_rec['VCPUs_number'], |
---|
770 | 'state': state_str, |
---|
771 | 'cpu_time': dom_metrics_rec['VCPUs_utilisation'], |
---|
772 | 'start_time': datetime_to_secs( |
---|
773 | dom_metrics_rec['start_time'])}) |
---|
774 | |
---|
775 | doms_sxp.append(['domain'] + map2sxp(dom_rec)) |
---|
776 | doms_dict.append(dom_rec) |
---|
777 | |
---|
778 | if domain_names: |
---|
779 | doms = [['domain'] + map2sxp(dom) for dom in doms_dict |
---|
780 | if dom["name"] in domain_names] |
---|
781 | |
---|
782 | if len(doms) > 0: |
---|
783 | return doms |
---|
784 | else: |
---|
785 | print "Error: no domain%s named %s" % \ |
---|
786 | (len(domain_names) > 1 and 's' or '', |
---|
787 | ', '.join(domain_names)) |
---|
788 | sys.exit(-1) |
---|
789 | else: |
---|
790 | return doms_sxp |
---|
791 | else: |
---|
792 | if domain_names: |
---|
793 | return [server.xend.domain(dom, full) for dom in domain_names] |
---|
794 | else: |
---|
795 | return server.xend.domains_with_state(True, state, full) |
---|
796 | |
---|
797 | |
---|
798 | def xm_list(args): |
---|
799 | use_long = 0 |
---|
800 | show_vcpus = 0 |
---|
801 | show_labels = 0 |
---|
802 | state = 'all' |
---|
803 | try: |
---|
804 | (options, params) = getopt.gnu_getopt(args, 'lv', |
---|
805 | ['long','vcpus','label', |
---|
806 | 'state=']) |
---|
807 | except getopt.GetoptError, opterr: |
---|
808 | err(opterr) |
---|
809 | usage('list') |
---|
810 | |
---|
811 | for (k, v) in options: |
---|
812 | if k in ['-l', '--long']: |
---|
813 | use_long = 1 |
---|
814 | if k in ['-v', '--vcpus']: |
---|
815 | show_vcpus = 1 |
---|
816 | if k in ['--label']: |
---|
817 | show_labels = 1 |
---|
818 | if k in ['--state']: |
---|
819 | state = v |
---|
820 | |
---|
821 | if state != 'all' and len(params) > 0: |
---|
822 | raise OptionError( |
---|
823 | "You may specify either a state or a particular VM, but not both") |
---|
824 | |
---|
825 | if show_vcpus: |
---|
826 | print >>sys.stderr, ( |
---|
827 | "xm list -v is deprecated. Please use xm vcpu-list.") |
---|
828 | xm_vcpu_list(params) |
---|
829 | return |
---|
830 | |
---|
831 | doms = getDomains(params, state, use_long) |
---|
832 | |
---|
833 | if use_long: |
---|
834 | map(PrettyPrint.prettyprint, doms) |
---|
835 | elif show_labels: |
---|
836 | xm_label_list(doms) |
---|
837 | else: |
---|
838 | xm_brief_list(doms) |
---|
839 | |
---|
840 | |
---|
841 | def parse_doms_info(info): |
---|
842 | def get_info(n, t, d): |
---|
843 | return t(sxp.child_value(info, n, d)) |
---|
844 | |
---|
845 | def get_status(n, t, d): |
---|
846 | return DOM_STATES[t(sxp.child_value(info, n, d))] |
---|
847 | |
---|
848 | start_time = get_info('start_time', float, -1) |
---|
849 | if start_time == -1: |
---|
850 | up_time = float(-1) |
---|
851 | else: |
---|
852 | up_time = time.time() - start_time |
---|
853 | |
---|
854 | parsed_info = { |
---|
855 | 'domid' : get_info('domid', str, ''), |
---|
856 | 'name' : get_info('name', str, '??'), |
---|
857 | 'state' : get_info('state', str, ''), |
---|
858 | |
---|
859 | # VCPUs is the number online when the VM is up, or the number |
---|
860 | # configured otherwise. |
---|
861 | 'vcpus' : get_info('online_vcpus', int, |
---|
862 | get_info('vcpus', int, 0)), |
---|
863 | 'up_time' : up_time |
---|
864 | } |
---|
865 | |
---|
866 | # We're not supporting security stuff just yet via XenAPI |
---|
867 | |
---|
868 | if serverType != SERVER_XEN_API: |
---|
869 | from xen.util import security |
---|
870 | parsed_info['seclabel'] = security.get_security_printlabel(info) |
---|
871 | else: |
---|
872 | parsed_info['seclabel'] = "" |
---|
873 | |
---|
874 | if serverType == SERVER_XEN_API: |
---|
875 | parsed_info['mem'] = get_info('memory_actual', int, 0) / 1024 |
---|
876 | cpu_times = get_info('cpu_time', lambda x : (x), 0.0) |
---|
877 | if sum(cpu_times.values()) > 0: |
---|
878 | parsed_info['cpu_time'] = sum(cpu_times.values()) / float(len(cpu_times.values())) |
---|
879 | else: |
---|
880 | parsed_info['cpu_time'] = 0 |
---|
881 | else: |
---|
882 | parsed_info['mem'] = get_info('memory', int,0) |
---|
883 | parsed_info['cpu_time'] = get_info('cpu_time', float, 0.0) |
---|
884 | |
---|
885 | return parsed_info |
---|
886 | |
---|
887 | def check_sched_type(sched): |
---|
888 | if serverType == SERVER_XEN_API: |
---|
889 | current = server.xenapi.host.get_sched_policy( |
---|
890 | server.xenapi.session.get_this_host(server.getSession())) |
---|
891 | else: |
---|
892 | current = 'unknown' |
---|
893 | for x in server.xend.node.info()[1:]: |
---|
894 | if len(x) > 1 and x[0] == 'xen_scheduler': |
---|
895 | current = x[1] |
---|
896 | break |
---|
897 | if sched != current: |
---|
898 | err("Xen is running with the %s scheduler" % current) |
---|
899 | sys.exit(1) |
---|
900 | |
---|
901 | def parse_sedf_info(info): |
---|
902 | def get_info(n, t, d): |
---|
903 | return t(sxp.child_value(info, n, d)) |
---|
904 | |
---|
905 | return { |
---|
906 | 'domid' : get_info('domid', int, -1), |
---|
907 | 'period' : get_info('period', int, -1), |
---|
908 | 'slice' : get_info('slice', int, -1), |
---|
909 | 'latency' : get_info('latency', int, -1), |
---|
910 | 'extratime': get_info('extratime', int, -1), |
---|
911 | 'weight' : get_info('weight', int, -1), |
---|
912 | } |
---|
913 | |
---|
914 | def domid_match(domid, info): |
---|
915 | return domid is None or domid == info['name'] or \ |
---|
916 | domid == str(info['domid']) |
---|
917 | |
---|
918 | def xm_brief_list(doms): |
---|
919 | print '%-40s %3s %5s %5s %10s %9s' % \ |
---|
920 | ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)') |
---|
921 | |
---|
922 | format = "%(name)-40s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s " \ |
---|
923 | "%(cpu_time)8.1f" |
---|
924 | |
---|
925 | for dom in doms: |
---|
926 | d = parse_doms_info(dom) |
---|
927 | print format % d |
---|
928 | |
---|
929 | def xm_label_list(doms): |
---|
930 | print '%-32s %3s %5s %5s %5s %9s %-8s' % \ |
---|
931 | ('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)', 'Label') |
---|
932 | |
---|
933 | output = [] |
---|
934 | format = '%(name)-32s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s ' \ |
---|
935 | '%(cpu_time)8.1f %(seclabel)9s' |
---|
936 | |
---|
937 | if serverType != SERVER_XEN_API: |
---|
938 | from xen.util import security |
---|
939 | |
---|
940 | for dom in doms: |
---|
941 | d = parse_doms_info(dom) |
---|
942 | |
---|
943 | if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']: |
---|
944 | if not d['seclabel']: |
---|
945 | d['seclabel'] = 'ERROR' |
---|
946 | elif security.active_policy in ['DEFAULT']: |
---|
947 | d['seclabel'] = 'DEFAULT' |
---|
948 | else: |
---|
949 | d['seclabel'] = 'INACTIVE' |
---|
950 | |
---|
951 | output.append((format % d, d['seclabel'])) |
---|
952 | |
---|
953 | #sort by labels |
---|
954 | output.sort(lambda x,y: cmp( x[1].lower(), y[1].lower())) |
---|
955 | for line, label in output: |
---|
956 | print line |
---|
957 | |
---|
958 | |
---|
959 | def xm_vcpu_list(args): |
---|
960 | if serverType == SERVER_XEN_API: |
---|
961 | if args: |
---|
962 | vm_refs = map(get_single_vm, args) |
---|
963 | else: |
---|
964 | vm_refs = server.xenapi.VM.get_all() |
---|
965 | |
---|
966 | vm_records = dict(map(lambda vm_ref: |
---|
967 | (vm_ref, server.xenapi.VM.get_record( |
---|
968 | vm_ref)), |
---|
969 | vm_refs)) |
---|
970 | |
---|
971 | vm_metrics = dict(map(lambda (ref, record): |
---|
972 | (ref, |
---|
973 | server.xenapi.VM_metrics.get_record( |
---|
974 | record['metrics'])), |
---|
975 | vm_records.items())) |
---|
976 | |
---|
977 | dominfo = [] |
---|
978 | |
---|
979 | # vcpu_list doesn't list 'managed' domains |
---|
980 | # when they are not running, so filter them out |
---|
981 | |
---|
982 | vm_refs = [vm_ref |
---|
983 | for vm_ref in vm_refs |
---|
984 | if vm_records[vm_ref]["power_state"] != "Halted"] |
---|
985 | |
---|
986 | for vm_ref in vm_refs: |
---|
987 | info = ['domain', |
---|
988 | ['domid', vm_records[vm_ref]['domid']], |
---|
989 | ['name', vm_records[vm_ref]['name_label']], |
---|
990 | ['vcpu_count', vm_records[vm_ref]['VCPUs_max']]] |
---|
991 | |
---|
992 | for i in range(int(vm_records[vm_ref]['VCPUs_max'])): |
---|
993 | def chk_flag(flag): |
---|
994 | return flag in vm_metrics[vm_ref]['VCPUs_flags'][str(i)] \ |
---|
995 | and 1 or 0 |
---|
996 | |
---|
997 | vcpu_info = ['vcpu', |
---|
998 | ['number', |
---|
999 | i], |
---|
1000 | ['online', |
---|
1001 | chk_flag("online")], |
---|
1002 | ['blocked', |
---|
1003 | chk_flag("blocked")], |
---|
1004 | ['running', |
---|
1005 | chk_flag("running")], |
---|
1006 | ['cpu_time', |
---|
1007 | vm_metrics[vm_ref]['VCPUs_utilisation'][str(i)]], |
---|
1008 | ['cpu', |
---|
1009 | vm_metrics[vm_ref]['VCPUs_CPU'][str(i)]], |
---|
1010 | ['cpumap', |
---|
1011 | vm_metrics[vm_ref]['VCPUs_params']\ |
---|
1012 | ['cpumap%i' % i].split(",")]] |
---|
1013 | |
---|
1014 | info.append(vcpu_info) |
---|
1015 | |
---|
1016 | dominfo.append(info) |
---|
1017 | else: |
---|
1018 | if args: |
---|
1019 | dominfo = map(server.xend.domain.getVCPUInfo, args) |
---|
1020 | else: |
---|
1021 | doms = server.xend.domains(False) |
---|
1022 | dominfo = map(server.xend.domain.getVCPUInfo, doms) |
---|
1023 | |
---|
1024 | print '%-32s %3s %5s %5s %5s %9s %s' % \ |
---|
1025 | ('Name', 'ID', 'VCPU', 'CPU', 'State', 'Time(s)', 'CPU Affinity') |
---|
1026 | |
---|
1027 | format = '%(name)-32s %(domid)3d %(number)5d %(c)5s %(s)5s ' \ |
---|
1028 | ' %(cpu_time)8.1f %(cpumap)s' |
---|
1029 | |
---|
1030 | for dom in dominfo: |
---|
1031 | def get_info(n): |
---|
1032 | return sxp.child_value(dom, n) |
---|
1033 | |
---|
1034 | # |
---|
1035 | # convert a list of integers into a list of pairs indicating |
---|
1036 | # continuous sequences in the list: |
---|
1037 | # |
---|
1038 | # [0,1,2,3] -> [(0,3)] |
---|
1039 | # [1,2,4,5] -> [(1,2),(4,5)] |
---|
1040 | # [0] -> [(0,0)] |
---|
1041 | # [0,1,4,6,7] -> [(0,1),(4,4),(6,7)] |
---|
1042 | # |
---|
1043 | def list_to_rangepairs(cmap): |
---|
1044 | cmap.sort() |
---|
1045 | pairs = [] |
---|
1046 | x = y = 0 |
---|
1047 | for i in range(0,len(cmap)): |
---|
1048 | try: |
---|
1049 | if ((cmap[y+1] - cmap[i]) > 1): |
---|
1050 | pairs.append((cmap[x],cmap[y])) |
---|
1051 | x = y = i+1 |
---|
1052 | else: |
---|
1053 | y = y + 1 |
---|
1054 | # if we go off the end, then just add x to y |
---|
1055 | except IndexError: |
---|
1056 | pairs.append((cmap[x],cmap[y])) |
---|
1057 | |
---|
1058 | return pairs |
---|
1059 | |
---|
1060 | # |
---|
1061 | # Convert pairs to range string, e.g: [(1,2),(3,3),(5,7)] -> 1-2,3,5-7 |
---|
1062 | # |
---|
1063 | def format_pairs(pairs): |
---|
1064 | if not pairs: |
---|
1065 | return "no cpus" |
---|
1066 | out = "" |
---|
1067 | for f,s in pairs: |
---|
1068 | if (f==s): |
---|
1069 | out += '%d'%f |
---|
1070 | else: |
---|
1071 | out += '%d-%d'%(f,s) |
---|
1072 | out += ',' |
---|
1073 | # trim trailing ',' |
---|
1074 | return out[:-1] |
---|
1075 | |
---|
1076 | def format_cpumap(cpumap): |
---|
1077 | cpumap = map(lambda x: int(x), cpumap) |
---|
1078 | cpumap.sort() |
---|
1079 | |
---|
1080 | if serverType == SERVER_XEN_API: |
---|
1081 | nr_cpus = len(server.xenapi.host.get_host_CPUs( |
---|
1082 | server.xenapi.session.get_this_host(server.getSession()))) |
---|
1083 | else: |
---|
1084 | for x in server.xend.node.info()[1:]: |
---|
1085 | if len(x) > 1 and x[0] == 'nr_cpus': |
---|
1086 | nr_cpus = int(x[1]) |
---|
1087 | |
---|
1088 | # normalize cpumap by modulus nr_cpus, and drop duplicates |
---|
1089 | cpumap = dict.fromkeys( |
---|
1090 | map(lambda x: x % nr_cpus, cpumap)).keys() |
---|
1091 | if len(cpumap) == nr_cpus: |
---|
1092 | return "any cpu" |
---|
1093 | |
---|
1094 | return format_pairs(list_to_rangepairs(cpumap)) |
---|
1095 | |
---|
1096 | name = get_info('name') |
---|
1097 | domid = int(get_info('domid')) |
---|
1098 | |
---|
1099 | for vcpu in sxp.children(dom, 'vcpu'): |
---|
1100 | def vinfo(n, t): |
---|
1101 | return t(sxp.child_value(vcpu, n)) |
---|
1102 | |
---|
1103 | number = vinfo('number', int) |
---|
1104 | cpu = vinfo('cpu', int) |
---|
1105 | cpumap = format_cpumap(vinfo('cpumap', list)) |
---|
1106 | online = vinfo('online', int) |
---|
1107 | cpu_time = vinfo('cpu_time', float) |
---|
1108 | running = vinfo('running', int) |
---|
1109 | blocked = vinfo('blocked', int) |
---|
1110 | |
---|
1111 | if online: |
---|
1112 | c = str(cpu) |
---|
1113 | if running: |
---|
1114 | s = 'r' |
---|
1115 | else: |
---|
1116 | s = '-' |
---|
1117 | if blocked: |
---|
1118 | s += 'b' |
---|
1119 | else: |
---|
1120 | s += '-' |
---|
1121 | s += '-' |
---|
1122 | else: |
---|
1123 | c = "-" |
---|
1124 | s = "--p" |
---|
1125 | |
---|
1126 | print format % locals() |
---|
1127 | |
---|
1128 | def xm_start(args): |
---|
1129 | arg_check(args, "start", 1, 2) |
---|
1130 | |
---|
1131 | try: |
---|
1132 | (options, params) = getopt.gnu_getopt(args, 'p', ['paused']) |
---|
1133 | except getopt.GetoptError, opterr: |
---|
1134 | err(opterr) |
---|
1135 | usage('start') |
---|
1136 | |
---|
1137 | paused = False |
---|
1138 | for (k, v) in options: |
---|
1139 | if k in ['-p', '--paused']: |
---|
1140 | paused = True |
---|
1141 | |
---|
1142 | if len(params) != 1: |
---|
1143 | err("Wrong number of parameters") |
---|
1144 | usage('start') |
---|
1145 | |
---|
1146 | dom = params[0] |
---|
1147 | if serverType == SERVER_XEN_API: |
---|
1148 | server.xenapi.VM.start(get_single_vm(dom), paused) |
---|
1149 | else: |
---|
1150 | server.xend.domain.start(dom, paused) |
---|
1151 | |
---|
1152 | def xm_delete(args): |
---|
1153 | arg_check(args, "delete", 1) |
---|
1154 | dom = args[0] |
---|
1155 | if serverType == SERVER_XEN_API: |
---|
1156 | server.xenapi.VM.destroy(get_single_vm(dom)) |
---|
1157 | else: |
---|
1158 | server.xend.domain.delete(dom) |
---|
1159 | |
---|
1160 | def xm_suspend(args): |
---|
1161 | arg_check(args, "suspend", 1) |
---|
1162 | dom = args[0] |
---|
1163 | if serverType == SERVER_XEN_API: |
---|
1164 | server.xenapi.VM.suspend(get_single_vm(dom)) |
---|
1165 | else: |
---|
1166 | server.xend.domain.suspend(dom) |
---|
1167 | |
---|
1168 | def xm_resume(args): |
---|
1169 | arg_check(args, "resume", 1, 2) |
---|
1170 | |
---|
1171 | try: |
---|
1172 | (options, params) = getopt.gnu_getopt(args, 'p', ['paused']) |
---|
1173 | except getopt.GetoptError, opterr: |
---|
1174 | err(opterr) |
---|
1175 | usage('resume') |
---|
1176 | |
---|
1177 | paused = False |
---|
1178 | for (k, v) in options: |
---|
1179 | if k in ['-p', '--paused']: |
---|
1180 | paused = True |
---|
1181 | |
---|
1182 | if len(params) != 1: |
---|
1183 | err("Wrong number of parameters") |
---|
1184 | usage('resume') |
---|
1185 | |
---|
1186 | dom = params[0] |
---|
1187 | if serverType == SERVER_XEN_API: |
---|
1188 | server.xenapi.VM.resume(get_single_vm(dom), paused) |
---|
1189 | else: |
---|
1190 | server.xend.domain.resume(dom, paused) |
---|
1191 | |
---|
1192 | def xm_reboot(args): |
---|
1193 | arg_check(args, "reboot", 1, 3) |
---|
1194 | from xen.xm import shutdown |
---|
1195 | shutdown.main(["shutdown", "-R"] + args) |
---|
1196 | |
---|
1197 | def xm_shutdown(args): |
---|
1198 | arg_check(args, "shutdown", 1, 4) |
---|
1199 | from xen.xm import shutdown |
---|
1200 | shutdown.main(["shutdown"] + args) |
---|
1201 | |
---|
1202 | def xm_pause(args): |
---|
1203 | arg_check(args, "pause", 1) |
---|
1204 | dom = args[0] |
---|
1205 | |
---|
1206 | if serverType == SERVER_XEN_API: |
---|
1207 | server.xenapi.VM.pause(get_single_vm(dom)) |
---|
1208 | else: |
---|
1209 | server.xend.domain.pause(dom) |
---|
1210 | |
---|
1211 | def xm_unpause(args): |
---|
1212 | arg_check(args, "unpause", 1) |
---|
1213 | dom = args[0] |
---|
1214 | |
---|
1215 | if serverType == SERVER_XEN_API: |
---|
1216 | server.xenapi.VM.unpause(get_single_vm(dom)) |
---|
1217 | else: |
---|
1218 | server.xend.domain.unpause(dom) |
---|
1219 | |
---|
1220 | def xm_dump_core(args): |
---|
1221 | live = False |
---|
1222 | crash = False |
---|
1223 | try: |
---|
1224 | (options, params) = getopt.gnu_getopt(args, 'LC', ['live','crash']) |
---|
1225 | for (k, v) in options: |
---|
1226 | if k in ('-L', '--live'): |
---|
1227 | live = True |
---|
1228 | if k in ('-C', '--crash'): |
---|
1229 | crash = True |
---|
1230 | |
---|
1231 | if len(params) not in (1, 2): |
---|
1232 | raise OptionError("Expects 1 or 2 argument(s)") |
---|
1233 | except getopt.GetoptError, e: |
---|
1234 | raise OptionError(str(e)) |
---|
1235 | |
---|
1236 | dom = params[0] |
---|
1237 | if len(params) == 2: |
---|
1238 | filename = os.path.abspath(params[1]) |
---|
1239 | else: |
---|
1240 | filename = None |
---|
1241 | |
---|
1242 | if not live: |
---|
1243 | server.xend.domain.pause(dom) |
---|
1244 | |
---|
1245 | try: |
---|
1246 | print "Dumping core of domain: %s ..." % str(dom) |
---|
1247 | server.xend.domain.dump(dom, filename, live, crash) |
---|
1248 | finally: |
---|
1249 | if not live: |
---|
1250 | server.xend.domain.unpause(dom) |
---|
1251 | |
---|
1252 | if crash: |
---|
1253 | print "Destroying domain: %s ..." % str(dom) |
---|
1254 | server.xend.domain.destroy(dom) |
---|
1255 | |
---|
1256 | def xm_rename(args): |
---|
1257 | arg_check(args, "rename", 2) |
---|
1258 | |
---|
1259 | if serverType == SERVER_XEN_API: |
---|
1260 | server.xenapi.VM.set_name_label(get_single_vm(args[0]), args[1]) |
---|
1261 | else: |
---|
1262 | server.xend.domain.setName(args[0], args[1]) |
---|
1263 | |
---|
1264 | def xm_importcommand(command, args): |
---|
1265 | cmd = __import__(command, globals(), locals(), 'xen.xm') |
---|
1266 | cmd.main([command] + args) |
---|
1267 | |
---|
1268 | |
---|
1269 | ############################################################# |
---|
1270 | |
---|
1271 | def xm_vcpu_pin(args): |
---|
1272 | arg_check(args, "vcpu-pin", 3) |
---|
1273 | |
---|
1274 | def cpu_make_map(cpulist): |
---|
1275 | cpus = [] |
---|
1276 | for c in cpulist.split(','): |
---|
1277 | if c.find('-') != -1: |
---|
1278 | (x,y) = c.split('-') |
---|
1279 | for i in range(int(x),int(y)+1): |
---|
1280 | cpus.append(int(i)) |
---|
1281 | else: |
---|
1282 | # remove this element from the list |
---|
1283 | if c[0] == '^': |
---|
1284 | cpus = [x for x in cpus if x != int(c[1:])] |
---|
1285 | else: |
---|
1286 | cpus.append(int(c)) |
---|
1287 | cpus.sort() |
---|
1288 | return cpus |
---|
1289 | |
---|
1290 | dom = args[0] |
---|
1291 | vcpu = int(args[1]) |
---|
1292 | if args[2] == 'all': |
---|
1293 | cpumap = cpu_make_map('0-63') |
---|
1294 | else: |
---|
1295 | cpumap = cpu_make_map(args[2]) |
---|
1296 | |
---|
1297 | if serverType == SERVER_XEN_API: |
---|
1298 | cpumap = map(str, cpumap) |
---|
1299 | server.xenapi.VM.add_to_VCPUs_params_live( |
---|
1300 | get_single_vm(dom), "cpumap%i" % int(vcpu), ",".join(cpumap)) |
---|
1301 | else: |
---|
1302 | server.xend.domain.pincpu(dom, vcpu, cpumap) |
---|
1303 | |
---|
1304 | def xm_mem_max(args): |
---|
1305 | arg_check(args, "mem-max", 2) |
---|
1306 | |
---|
1307 | dom = args[0] |
---|
1308 | |
---|
1309 | if serverType == SERVER_XEN_API: |
---|
1310 | mem = int_unit(args[1], 'k') * 1024 |
---|
1311 | server.xenapi.VM.set_memory_static_max(get_single_vm(dom), mem) |
---|
1312 | else: |
---|
1313 | mem = int_unit(args[1], 'm') |
---|
1314 | server.xend.domain.maxmem_set(dom, mem) |
---|
1315 | |
---|
1316 | def xm_mem_set(args): |
---|
1317 | arg_check(args, "mem-set", 2) |
---|
1318 | |
---|
1319 | dom = args[0] |
---|
1320 | |
---|
1321 | if serverType == SERVER_XEN_API: |
---|
1322 | mem_target = int_unit(args[1], 'm') * 1024 * 1024 |
---|
1323 | server.xenapi.VM.set_memory_dynamic_max_live(get_single_vm(dom), |
---|
1324 | mem_target) |
---|
1325 | server.xenapi.VM.set_memory_dynamic_min_live(get_single_vm(dom), |
---|
1326 | mem_target) |
---|
1327 | else: |
---|
1328 | mem_target = int_unit(args[1], 'm') |
---|
1329 | server.xend.domain.setMemoryTarget(dom, mem_target) |
---|
1330 | |
---|
1331 | def xm_vcpu_set(args): |
---|
1332 | arg_check(args, "vcpu-set", 2) |
---|
1333 | |
---|
1334 | dom = args[0] |
---|
1335 | vcpus = int(args[1]) |
---|
1336 | |
---|
1337 | if serverType == SERVER_XEN_API: |
---|
1338 | server.xenapi.VM.set_VCPUs_number_live(get_single_vm(dom), vcpus) |
---|
1339 | else: |
---|
1340 | server.xend.domain.setVCpuCount(dom, vcpus) |
---|
1341 | |
---|
1342 | def xm_destroy(args): |
---|
1343 | arg_check(args, "destroy", 1) |
---|
1344 | |
---|
1345 | dom = args[0] |
---|
1346 | |
---|
1347 | if serverType == SERVER_XEN_API: |
---|
1348 | server.xenapi.VM.hard_shutdown(get_single_vm(dom)) |
---|
1349 | else: |
---|
1350 | server.xend.domain.destroy(dom) |
---|
1351 | |
---|
1352 | def xm_domid(args): |
---|
1353 | arg_check(args, "domid", 1) |
---|
1354 | |
---|
1355 | name = args[0] |
---|
1356 | |
---|
1357 | if serverType == SERVER_XEN_API: |
---|
1358 | print server.xenapi.VM.get_domid(get_single_vm(name)) |
---|
1359 | else: |
---|
1360 | dom = server.xend.domain(name) |
---|
1361 | print sxp.child_value(dom, 'domid') |
---|
1362 | |
---|
1363 | def xm_domname(args): |
---|
1364 | arg_check(args, "domname", 1) |
---|
1365 | |
---|
1366 | name = args[0] |
---|
1367 | |
---|
1368 | if serverType == SERVER_XEN_API: |
---|
1369 | print server.xenapi.VM.get_name_label(get_single_vm(name)) |
---|
1370 | else: |
---|
1371 | dom = server.xend.domain(name) |
---|
1372 | print sxp.child_value(dom, 'name') |
---|
1373 | |
---|
1374 | def xm_sched_sedf(args): |
---|
1375 | xenapi_unsupported() |
---|
1376 | |
---|
1377 | def ns_to_ms(val): |
---|
1378 | return float(val) * 0.000001 |
---|
1379 | |
---|
1380 | def ms_to_ns(val): |
---|
1381 | return (float(val) / 0.000001) |
---|
1382 | |
---|
1383 | def print_sedf(info): |
---|
1384 | info['period'] = ns_to_ms(info['period']) |
---|
1385 | info['slice'] = ns_to_ms(info['slice']) |
---|
1386 | info['latency'] = ns_to_ms(info['latency']) |
---|
1387 | print( ("%(name)-32s %(domid)3d %(period)9.1f %(slice)9.1f" + |
---|
1388 | " %(latency)7.1f %(extratime)6d %(weight)6d") % info) |
---|
1389 | |
---|
1390 | check_sched_type('sedf') |
---|
1391 | |
---|
1392 | # we want to just display current info if no parameters are passed |
---|
1393 | if len(args) == 0: |
---|
1394 | domid = None |
---|
1395 | else: |
---|
1396 | # we expect at least a domain id (name or number) |
---|
1397 | # and at most a domid up to 5 options with values |
---|
1398 | arg_check(args, "sched-sedf", 1, 11) |
---|
1399 | domid = args[0] |
---|
1400 | # drop domid from args since get_opt doesn't recognize it |
---|
1401 | args = args[1:] |
---|
1402 | |
---|
1403 | opts = {} |
---|
1404 | try: |
---|
1405 | (options, params) = getopt.gnu_getopt(args, 'p:s:l:e:w:', |
---|
1406 | ['period=', 'slice=', 'latency=', 'extratime=', 'weight=']) |
---|
1407 | except getopt.GetoptError, opterr: |
---|
1408 | err(opterr) |
---|
1409 | usage('sched-sedf') |
---|
1410 | |
---|
1411 | # convert to nanoseconds if needed |
---|
1412 | for (k, v) in options: |
---|
1413 | if k in ['-p', '--period']: |
---|
1414 | opts['period'] = ms_to_ns(v) |
---|
1415 | elif k in ['-s', '--slice']: |
---|
1416 | opts['slice'] = ms_to_ns(v) |
---|
1417 | elif k in ['-l', '--latency']: |
---|
1418 | opts['latency'] = ms_to_ns(v) |
---|
1419 | elif k in ['-e', '--extratime']: |
---|
1420 | opts['extratime'] = v |
---|
1421 | elif k in ['-w', '--weight']: |
---|
1422 | opts['weight'] = v |
---|
1423 | |
---|
1424 | doms = filter(lambda x : domid_match(domid, x), |
---|
1425 | [parse_doms_info(dom) |
---|
1426 | for dom in getDomains(None, 'running')]) |
---|
1427 | if domid is not None and doms == []: |
---|
1428 | err("Domain '%s' does not exist." % domid) |
---|
1429 | usage('sched-sedf') |
---|
1430 | |
---|
1431 | # print header if we aren't setting any parameters |
---|
1432 | if len(opts.keys()) == 0: |
---|
1433 | print '%-33s %-2s %-4s %-4s %-7s %-5s %-6s' % \ |
---|
1434 | ('Name','ID','Period(ms)', 'Slice(ms)', 'Lat(ms)', |
---|
1435 | 'Extra','Weight') |
---|
1436 | |
---|
1437 | for d in doms: |
---|
1438 | # fetch current values so as not to clobber them |
---|
1439 | try: |
---|
1440 | sedf_raw = server.xend.domain.cpu_sedf_get(d['domid']) |
---|
1441 | except xmlrpclib.Fault: |
---|
1442 | # domain does not support sched-sedf? |
---|
1443 | sedf_raw = {} |
---|
1444 | |
---|
1445 | sedf_info = parse_sedf_info(sedf_raw) |
---|
1446 | sedf_info['name'] = d['name'] |
---|
1447 | # update values in case of call to set |
---|
1448 | if len(opts.keys()) > 0: |
---|
1449 | for k in opts.keys(): |
---|
1450 | sedf_info[k]=opts[k] |
---|
1451 | |
---|
1452 | # send the update, converting user input |
---|
1453 | v = map(int, [sedf_info['period'], sedf_info['slice'], |
---|
1454 | sedf_info['latency'],sedf_info['extratime'], |
---|
1455 | sedf_info['weight']]) |
---|
1456 | rv = server.xend.domain.cpu_sedf_set(d['domid'], *v) |
---|
1457 | if int(rv) != 0: |
---|
1458 | err("Failed to set sedf parameters (rv=%d)."%(rv)) |
---|
1459 | |
---|
1460 | # not setting values, display info |
---|
1461 | else: |
---|
1462 | print_sedf(sedf_info) |
---|
1463 | |
---|
1464 | def xm_sched_credit(args): |
---|
1465 | """Get/Set options for Credit Scheduler.""" |
---|
1466 | |
---|
1467 | check_sched_type('credit') |
---|
1468 | |
---|
1469 | try: |
---|
1470 | opts, params = getopt.getopt(args, "d:w:c:", |
---|
1471 | ["domain=", "weight=", "cap="]) |
---|
1472 | except getopt.GetoptError, opterr: |
---|
1473 | err(opterr) |
---|
1474 | usage('sched-credit') |
---|
1475 | |
---|
1476 | domid = None |
---|
1477 | weight = None |
---|
1478 | cap = None |
---|
1479 | |
---|
1480 | for o, a in opts: |
---|
1481 | if o == "-d": |
---|
1482 | domid = a |
---|
1483 | elif o == "-w": |
---|
1484 | weight = int(a) |
---|
1485 | elif o == "-c": |
---|
1486 | cap = int(a); |
---|
1487 | |
---|
1488 | doms = filter(lambda x : domid_match(domid, x), |
---|
1489 | [parse_doms_info(dom) |
---|
1490 | for dom in getDomains(None, 'running')]) |
---|
1491 | |
---|
1492 | if weight is None and cap is None: |
---|
1493 | if domid is not None and doms == []: |
---|
1494 | err("Domain '%s' does not exist." % domid) |
---|
1495 | usage('sched-credit') |
---|
1496 | # print header if we aren't setting any parameters |
---|
1497 | print '%-33s %-2s %-6s %-4s' % ('Name','ID','Weight','Cap') |
---|
1498 | |
---|
1499 | for d in doms: |
---|
1500 | try: |
---|
1501 | if serverType == SERVER_XEN_API: |
---|
1502 | info = server.xenapi.VM_metrics.get_VCPUs_params( |
---|
1503 | server.xenapi.VM.get_metrics( |
---|
1504 | get_single_vm(d['name']))) |
---|
1505 | else: |
---|
1506 | info = server.xend.domain.sched_credit_get(d['domid']) |
---|
1507 | except xmlrpclib.Fault: |
---|
1508 | pass |
---|
1509 | |
---|
1510 | if 'weight' not in info or 'cap' not in info: |
---|
1511 | # domain does not support sched-credit? |
---|
1512 | info = {'weight': -1, 'cap': -1} |
---|
1513 | |
---|
1514 | info['weight'] = int(info['weight']) |
---|
1515 | info['cap'] = int(info['cap']) |
---|
1516 | |
---|
1517 | info['name'] = d['name'] |
---|
1518 | info['domid'] = int(d['domid']) |
---|
1519 | print( ("%(name)-32s %(domid)3d %(weight)6d %(cap)4d") % info) |
---|
1520 | else: |
---|
1521 | if domid is None: |
---|
1522 | # place holder for system-wide scheduler parameters |
---|
1523 | err("No domain given.") |
---|
1524 | usage('sched-credit') |
---|
1525 | |
---|
1526 | if serverType == SERVER_XEN_API: |
---|
1527 | server.xenapi.VM.add_to_VCPUs_params_live( |
---|
1528 | get_single_vm(domid), |
---|
1529 | "weight", |
---|
1530 | weight) |
---|
1531 | server.xenapi.VM.add_to_VCPUs_params_live( |
---|
1532 | get_single_vm(domid), |
---|
1533 | "cap", |
---|
1534 | cap) |
---|
1535 | else: |
---|
1536 | result = server.xend.domain.sched_credit_set(domid, weight, cap) |
---|
1537 | if result != 0: |
---|
1538 | err(str(result)) |
---|
1539 | |
---|
1540 | def xm_info(args): |
---|
1541 | arg_check(args, "info", 0) |
---|
1542 | |
---|
1543 | if serverType == SERVER_XEN_API: |
---|
1544 | |
---|
1545 | # Need to fake out old style xm info as people rely on parsing it |
---|
1546 | |
---|
1547 | host_record = server.xenapi.host.get_record( |
---|
1548 | server.xenapi.session.get_this_host(server.getSession())) |
---|
1549 | |
---|
1550 | host_cpu_records = map(server.xenapi.host_cpu.get_record, host_record["host_CPUs"]) |
---|
1551 | |
---|
1552 | host_metrics_record = server.xenapi.host_metrics.get_record(host_record["metrics"]) |
---|
1553 | |
---|
1554 | def getVal(keys, default=""): |
---|
1555 | data = host_record |
---|
1556 | for key in keys: |
---|
1557 | if key in data: |
---|
1558 | data = data[key] |
---|
1559 | else: |
---|
1560 | return default |
---|
1561 | return data |
---|
1562 | |
---|
1563 | def getCpuMhz(): |
---|
1564 | cpu_speeds = [int(host_cpu_record["speed"]) |
---|
1565 | for host_cpu_record in host_cpu_records |
---|
1566 | if "speed" in host_cpu_record] |
---|
1567 | if len(cpu_speeds) > 0: |
---|
1568 | return sum(cpu_speeds) / len(cpu_speeds) |
---|
1569 | else: |
---|
1570 | return 0 |
---|
1571 | |
---|
1572 | getCpuMhz() |
---|
1573 | |
---|
1574 | def getCpuFeatures(): |
---|
1575 | if len(host_cpu_records) > 0: |
---|
1576 | return host_cpu_records[0].get("features", "") |
---|
1577 | else: |
---|
1578 | return "" |
---|
1579 | |
---|
1580 | info = { |
---|
1581 | "host": getVal(["name_label"]), |
---|
1582 | "release": getVal(["software_version", "release"]), |
---|
1583 | "version": getVal(["software_version", "version"]), |
---|
1584 | "machine": getVal(["software_version", "machine"]), |
---|
1585 | "nr_cpus": len(getVal(["host_CPUs"], [])), |
---|
1586 | "nr_nodes": getVal(["cpu_configuration", "nr_nodes"]), |
---|
1587 | "sockets_per_node": getVal(["cpu_configuration", "sockets_per_node"]), |
---|
1588 | "cores_per_socket": getVal(["cpu_configuration", "cores_per_socket"]), |
---|
1589 | "threads_per_core": getVal(["cpu_configuration", "threads_per_core"]), |
---|
1590 | "cpu_mhz": getCpuMhz(), |
---|
1591 | "hw_caps": getCpuFeatures(), |
---|
1592 | "total_memory": int(host_metrics_record["memory_total"])/1024/1024, |
---|
1593 | "free_memory": int(host_metrics_record["memory_free"])/1024/1024, |
---|
1594 | "xen_major": getVal(["software_version", "xen_major"]), |
---|
1595 | "xen_minor": getVal(["software_version", "xen_minor"]), |
---|
1596 | "xen_extra": getVal(["software_version", "xen_extra"]), |
---|
1597 | "xen_caps": " ".join(getVal(["capabilities"], [])), |
---|
1598 | "xen_scheduler": getVal(["sched_policy"]), |
---|
1599 | "xen_pagesize": getVal(["other_config", "xen_pagesize"]), |
---|
1600 | "platform_params": getVal(["other_config", "platform_params"]), |
---|
1601 | "xen_changeset": getVal(["software_version", "xen_changeset"]), |
---|
1602 | "cc_compiler": getVal(["software_version", "cc_compiler"]), |
---|
1603 | "cc_compile_by": getVal(["software_version", "cc_compile_by"]), |
---|
1604 | "cc_compile_domain": getVal(["software_version", "cc_compile_domain"]), |
---|
1605 | "cc_compile_date": getVal(["software_version", "cc_compile_date"]), |
---|
1606 | "xend_config_format":getVal(["software_version", "xend_config_format"]) |
---|
1607 | } |
---|
1608 | |
---|
1609 | sorted = info.items() |
---|
1610 | sorted.sort(lambda (x1,y1), (x2,y2): -cmp(x1,x2)) |
---|
1611 | |
---|
1612 | for (k, v) in sorted: |
---|
1613 | print "%-23s:" % k, v |
---|
1614 | else: |
---|
1615 | info = server.xend.node.info() |
---|
1616 | for x in info[1:]: |
---|
1617 | if len(x) < 2: |
---|
1618 | print "%-23s: (none)" % x[0] |
---|
1619 | else: |
---|
1620 | print "%-23s:" % x[0], x[1] |
---|
1621 | |
---|
1622 | def xm_console(args): |
---|
1623 | arg_check(args, "console", 1, 2) |
---|
1624 | |
---|
1625 | quiet = False; |
---|
1626 | |
---|
1627 | try: |
---|
1628 | (options, params) = getopt.gnu_getopt(args, 'q', ['quiet']) |
---|
1629 | except getopt.GetoptError, opterr: |
---|
1630 | err(opterr) |
---|
1631 | usage('console') |
---|
1632 | |
---|
1633 | for (k, v) in options: |
---|
1634 | if k in ['-q', '--quiet']: |
---|
1635 | quiet = True |
---|
1636 | else: |
---|
1637 | assert False |
---|
1638 | |
---|
1639 | if len(params) != 1: |
---|
1640 | err('No domain given') |
---|
1641 | usage('console') |
---|
1642 | |
---|
1643 | dom = params[0] |
---|
1644 | |
---|
1645 | try: |
---|
1646 | if serverType == SERVER_XEN_API: |
---|
1647 | domid = int(server.xenapi.VM.get_domid(get_single_vm(dom))) |
---|
1648 | else: |
---|
1649 | info = server.xend.domain(dom) |
---|
1650 | domid = int(sxp.child_value(info, 'domid', '-1')) |
---|
1651 | except: |
---|
1652 | if quiet: |
---|
1653 | sys.exit(1) |
---|
1654 | else: |
---|
1655 | raise |
---|
1656 | |
---|
1657 | if domid == -1: |
---|
1658 | if quiet: |
---|
1659 | sys.exit(1) |
---|
1660 | else: |
---|
1661 | raise xmlrpclib.Fault(0, "Domain '%s' is not started" % dom) |
---|
1662 | |
---|
1663 | console.execConsole(domid) |
---|
1664 | |
---|
1665 | |
---|
1666 | def xm_uptime(args): |
---|
1667 | short_mode = 0 |
---|
1668 | |
---|
1669 | try: |
---|
1670 | (options, params) = getopt.gnu_getopt(args, 's', ['short']) |
---|
1671 | except getopt.GetoptError, opterr: |
---|
1672 | err(opterr) |
---|
1673 | usage('uptime') |
---|
1674 | |
---|
1675 | for (k, v) in options: |
---|
1676 | if k in ['-s', '--short']: |
---|
1677 | short_mode = 1 |
---|
1678 | |
---|
1679 | doms = getDomains(params, 'running') |
---|
1680 | |
---|
1681 | if short_mode == 0: |
---|
1682 | print 'Name ID Uptime' |
---|
1683 | |
---|
1684 | for dom in doms: |
---|
1685 | d = parse_doms_info(dom) |
---|
1686 | if int(d['domid']) > 0: |
---|
1687 | uptime = int(round(d['up_time'])) |
---|
1688 | else: |
---|
1689 | f=open('/proc/uptime', 'r') |
---|
1690 | upfile = f.read() |
---|
1691 | uptime = int(round(float(upfile.split(' ')[0]))) |
---|
1692 | f.close() |
---|
1693 | |
---|
1694 | days = int(uptime / 86400) |
---|
1695 | uptime -= (days * 86400) |
---|
1696 | hours = int(uptime / 3600) |
---|
1697 | uptime -= (hours * 3600) |
---|
1698 | minutes = int(uptime / 60) |
---|
1699 | uptime -= (minutes * 60) |
---|
1700 | seconds = uptime |
---|
1701 | |
---|
1702 | upstring = "" |
---|
1703 | if days > 0: |
---|
1704 | upstring += str(days) + " day" |
---|
1705 | if days > 1: |
---|
1706 | upstring += "s" |
---|
1707 | upstring += ", " |
---|
1708 | upstring += '%(hours)2d:%(minutes)02d' % vars() |
---|
1709 | |
---|
1710 | if short_mode: |
---|
1711 | now = datetime.datetime.now() |
---|
1712 | upstring = now.strftime(" %H:%M:%S") + " up " + upstring |
---|
1713 | upstring += ", " + d['name'] + " (" + d['domid'] + ")" |
---|
1714 | else: |
---|
1715 | upstring += ':%(seconds)02d' % vars() |
---|
1716 | upstring = ("%(name)-32s %(domid)3s " % d) + upstring |
---|
1717 | |
---|
1718 | print upstring |
---|
1719 | |
---|
1720 | def xm_sysrq(args): |
---|
1721 | arg_check(args, "sysrq", 2) |
---|
1722 | dom = args[0] |
---|
1723 | req = args[1] |
---|
1724 | if serverType == SERVER_XEN_API: |
---|
1725 | server.xenapi.VM.send_sysrq(get_single_vm(dom), req) |
---|
1726 | else: |
---|
1727 | server.xend.domain.send_sysrq(dom, req) |
---|
1728 | |
---|
1729 | def xm_trigger(args): |
---|
1730 | vcpu = 0 |
---|
1731 | |
---|
1732 | arg_check(args, "trigger", 2, 3) |
---|
1733 | dom = args[0] |
---|
1734 | trigger = args[1] |
---|
1735 | if len(args) == 3: |
---|
1736 | vcpu = int(args[2]) |
---|
1737 | |
---|
1738 | if serverType == SERVER_XEN_API: |
---|
1739 | server.xenapi.VM.send_trigger(get_single_vm(dom), trigger, vcpu) |
---|
1740 | else: |
---|
1741 | server.xend.domain.send_trigger(dom, trigger, vcpu) |
---|
1742 | |
---|
1743 | def xm_debug_keys(args): |
---|
1744 | arg_check(args, "debug-keys", 1) |
---|
1745 | |
---|
1746 | keys = str(args[0]) |
---|
1747 | |
---|
1748 | if serverType == SERVER_XEN_API: |
---|
1749 | server.xenapi.host.send_debug_keys( |
---|
1750 | server.xenapi.session.get_this_host(server.getSession()), |
---|
1751 | keys) |
---|
1752 | else: |
---|
1753 | server.xend.node.send_debug_keys(keys) |
---|
1754 | |
---|
1755 | def xm_top(args): |
---|
1756 | arg_check(args, "top", 0) |
---|
1757 | |
---|
1758 | os.execvp('xentop', ['xentop']) |
---|
1759 | |
---|
1760 | def xm_dmesg(args): |
---|
1761 | arg_check(args, "dmesg", 0, 1) |
---|
1762 | |
---|
1763 | try: |
---|
1764 | (options, params) = getopt.gnu_getopt(args, 'c', ['clear']) |
---|
1765 | except getopt.GetoptError, opterr: |
---|
1766 | err(opterr) |
---|
1767 | usage('dmesg') |
---|
1768 | |
---|
1769 | use_clear = 0 |
---|
1770 | for (k, v) in options: |
---|
1771 | if k in ['-c', '--clear']: |
---|
1772 | use_clear = 1 |
---|
1773 | |
---|
1774 | if len(params) : |
---|
1775 | err("No parameter required") |
---|
1776 | usage('dmesg') |
---|
1777 | |
---|
1778 | if serverType == SERVER_XEN_API: |
---|
1779 | host = server.xenapi.session.get_this_host(server.getSession()) |
---|
1780 | if use_clear: |
---|
1781 | print server.xenapi.host.dmesg_clear(host), |
---|
1782 | else: |
---|
1783 | print server.xenapi.host.dmesg(host), |
---|
1784 | else: |
---|
1785 | if not use_clear: |
---|
1786 | print server.xend.node.dmesg.info(), |
---|
1787 | else: |
---|
1788 | print server.xend.node.dmesg.clear(), |
---|
1789 | |
---|
1790 | def xm_log(args): |
---|
1791 | arg_check(args, "log", 0) |
---|
1792 | |
---|
1793 | if serverType == SERVER_XEN_API: |
---|
1794 | print server.xenapi.host.get_log( |
---|
1795 | server.xenapi.session.get_this_host(server.getSession())) |
---|
1796 | else: |
---|
1797 | print server.xend.node.log() |
---|
1798 | |
---|
1799 | def xm_serve(args): |
---|
1800 | if serverType == SERVER_XEN_API: |
---|
1801 | print "Not supported with XenAPI" |
---|
1802 | sys.exit(-1) |
---|
1803 | |
---|
1804 | arg_check(args, "serve", 0) |
---|
1805 | |
---|
1806 | from fcntl import fcntl, F_SETFL |
---|
1807 | |
---|
1808 | s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
---|
1809 | s.connect(XendClient.XML_RPC_SOCKET) |
---|
1810 | fcntl(sys.stdin, F_SETFL, os.O_NONBLOCK) |
---|
1811 | |
---|
1812 | while True: |
---|
1813 | iwtd, owtd, ewtd = select([sys.stdin, s], [], []) |
---|
1814 | if s in iwtd: |
---|
1815 | data = s.recv(4096) |
---|
1816 | if len(data) > 0: |
---|
1817 | sys.stdout.write(data) |
---|
1818 | sys.stdout.flush() |
---|
1819 | else: |
---|
1820 | break |
---|
1821 | if sys.stdin in iwtd: |
---|
1822 | data = sys.stdin.read(4096) |
---|
1823 | if len(data) > 0: |
---|
1824 | s.sendall(data) |
---|
1825 | else: |
---|
1826 | break |
---|
1827 | s.close() |
---|
1828 | |
---|
1829 | def parse_dev_info(info): |
---|
1830 | def get_info(n, t, d): |
---|
1831 | i = 0 |
---|
1832 | while i < len(info): |
---|
1833 | if (info[i][0] == n): |
---|
1834 | return t(info[i][1]) |
---|
1835 | i = i + 1 |
---|
1836 | return t(d) |
---|
1837 | return { |
---|
1838 | #common |
---|
1839 | 'backend-id' : get_info('backend-id', int, -1), |
---|
1840 | 'handle' : get_info('handle', int, 0), |
---|
1841 | 'state' : get_info('state', int, -1), |
---|
1842 | 'be-path' : get_info('backend', str, '??'), |
---|
1843 | 'event-ch' : get_info('event-channel',int, -1), |
---|
1844 | #network specific |
---|
1845 | 'virtual-device' : get_info('virtual-device', str, '??'), |
---|
1846 | 'tx-ring-ref': get_info('tx-ring-ref', int, -1), |
---|
1847 | 'rx-ring-ref': get_info('rx-ring-ref', int, -1), |
---|
1848 | 'mac' : get_info('mac', str, '??'), |
---|
1849 | #block-device specific |
---|
1850 | 'ring-ref' : get_info('ring-ref', int, -1), |
---|
1851 | } |
---|
1852 | |
---|
1853 | def arg_check_for_resource_list(args, name): |
---|
1854 | use_long = 0 |
---|
1855 | try: |
---|
1856 | (options, params) = getopt.gnu_getopt(args, 'l', ['long']) |
---|
1857 | except getopt.GetoptError, opterr: |
---|
1858 | err(opterr) |
---|
1859 | sys.exit(1) |
---|
1860 | |
---|
1861 | for (k, v) in options: |
---|
1862 | if k in ['-l', '--long']: |
---|
1863 | use_long = 1 |
---|
1864 | |
---|
1865 | if len(params) == 0: |
---|
1866 | print 'No domain parameter given' |
---|
1867 | usage(name) |
---|
1868 | if len(params) > 1: |
---|
1869 | print 'No multiple domain parameters allowed' |
---|
1870 | usage(name) |
---|
1871 | |
---|
1872 | return (use_long, params) |
---|
1873 | |
---|
1874 | def xm_network_list(args): |
---|
1875 | (use_long, params) = arg_check_for_resource_list(args, "network-list") |
---|
1876 | |
---|
1877 | dom = params[0] |
---|
1878 | |
---|
1879 | if serverType == SERVER_XEN_API: |
---|
1880 | vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom)) |
---|
1881 | vif_properties = \ |
---|
1882 | map(server.xenapi.VIF.get_runtime_properties, vif_refs) |
---|
1883 | devs = map(lambda (handle, properties): [handle, map2sxp(properties)], |
---|
1884 | zip(range(len(vif_properties)), vif_properties)) |
---|
1885 | else: |
---|
1886 | devs = server.xend.domain.getDeviceSxprs(dom, 'vif') |
---|
1887 | |
---|
1888 | if use_long: |
---|
1889 | map(PrettyPrint.prettyprint, devs) |
---|
1890 | else: |
---|
1891 | hdr = 0 |
---|
1892 | for x in devs: |
---|
1893 | if hdr == 0: |
---|
1894 | print 'Idx BE MAC Addr. handle state evt-ch tx-/rx-ring-ref BE-path' |
---|
1895 | hdr = 1 |
---|
1896 | ni = parse_dev_info(x[1]) |
---|
1897 | ni['idx'] = int(x[0]) |
---|
1898 | print ("%(idx)-3d " |
---|
1899 | "%(backend-id)-3d" |
---|
1900 | "%(mac)-17s " |
---|
1901 | "%(handle)-3d " |
---|
1902 | "%(state)-3d " |
---|
1903 | "%(event-ch)-3d " |
---|
1904 | "%(tx-ring-ref)-5d/%(rx-ring-ref)-5d " |
---|
1905 | "%(be-path)-30s " |
---|
1906 | % ni) |
---|
1907 | |
---|
1908 | def xm_block_list(args): |
---|
1909 | (use_long, params) = arg_check_for_resource_list(args, "block-list") |
---|
1910 | |
---|
1911 | dom = params[0] |
---|
1912 | |
---|
1913 | if serverType == SERVER_XEN_API: |
---|
1914 | vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom)) |
---|
1915 | vbd_properties = \ |
---|
1916 | map(server.xenapi.VBD.get_runtime_properties, vbd_refs) |
---|
1917 | vbd_devs = \ |
---|
1918 | map(server.xenapi.VBD.get_device, vbd_refs) |
---|
1919 | vbd_devids = \ |
---|
1920 | map(blkdev_name_to_number, vbd_devs) |
---|
1921 | devs = map(lambda (devid, prop): [devid, map2sxp(prop)], |
---|
1922 | zip(vbd_devids, vbd_properties)) |
---|
1923 | else: |
---|
1924 | devs = server.xend.domain.getDeviceSxprs(dom, 'vbd') |
---|
1925 | |
---|
1926 | if use_long: |
---|
1927 | map(PrettyPrint.prettyprint, devs) |
---|
1928 | else: |
---|
1929 | hdr = 0 |
---|
1930 | for x in devs: |
---|
1931 | if hdr == 0: |
---|
1932 | print 'Vdev BE handle state evt-ch ring-ref BE-path' |
---|
1933 | hdr = 1 |
---|
1934 | ni = parse_dev_info(x[1]) |
---|
1935 | ni['idx'] = int(x[0]) |
---|
1936 | print ("%(idx)-3d " |
---|
1937 | "%(backend-id)-3d " |
---|
1938 | "%(handle)-3d " |
---|
1939 | "%(state)-3d " |
---|
1940 | "%(event-ch)-3d " |
---|
1941 | "%(ring-ref)-5d " |
---|
1942 | "%(be-path)-30s " |
---|
1943 | % ni) |
---|
1944 | |
---|
1945 | def xm_vtpm_list(args): |
---|
1946 | xenapi_unsupported() |
---|
1947 | (use_long, params) = arg_check_for_resource_list(args, "vtpm-list") |
---|
1948 | |
---|
1949 | dom = params[0] |
---|
1950 | if use_long: |
---|
1951 | devs = server.xend.domain.getDeviceSxprs(dom, 'vtpm') |
---|
1952 | map(PrettyPrint.prettyprint, devs) |
---|
1953 | else: |
---|
1954 | hdr = 0 |
---|
1955 | for x in server.xend.domain.getDeviceSxprs(dom, 'vtpm'): |
---|
1956 | if hdr == 0: |
---|
1957 | print 'Idx BE handle state evt-ch ring-ref BE-path' |
---|
1958 | hdr = 1 |
---|
1959 | ni = parse_dev_info(x[1]) |
---|
1960 | ni['idx'] = int(x[0]) |
---|
1961 | print ("%(idx)-3d " |
---|
1962 | "%(backend-id)-3d " |
---|
1963 | "%(handle)-3d " |
---|
1964 | "%(state)-3d " |
---|
1965 | "%(event-ch)-3d " |
---|
1966 | "%(ring-ref)-5d " |
---|
1967 | "%(be-path)-30s " |
---|
1968 | % ni) |
---|
1969 | |
---|
1970 | |
---|
1971 | def parse_block_configuration(args): |
---|
1972 | dom = args[0] |
---|
1973 | |
---|
1974 | if args[1].startswith('tap:'): |
---|
1975 | cls = 'tap' |
---|
1976 | else: |
---|
1977 | cls = 'vbd' |
---|
1978 | |
---|
1979 | vbd = [cls, |
---|
1980 | ['uname', args[1]], |
---|
1981 | ['dev', args[2]], |
---|
1982 | ['mode', args[3]]] |
---|
1983 | if len(args) == 5: |
---|
1984 | vbd.append(['backend', args[4]]) |
---|
1985 | |
---|
1986 | if serverType != SERVER_XEN_API: |
---|
1987 | # verify that policy permits attaching this resource |
---|
1988 | from xen.util import security |
---|
1989 | |
---|
1990 | if security.on(): |
---|
1991 | dominfo = server.xend.domain(dom) |
---|
1992 | label = security.get_security_printlabel(dominfo) |
---|
1993 | else: |
---|
1994 | label = None |
---|
1995 | |
---|
1996 | security.res_security_check(args[1], label) |
---|
1997 | |
---|
1998 | return (dom, vbd) |
---|
1999 | |
---|
2000 | |
---|
2001 | def xm_block_attach(args): |
---|
2002 | arg_check(args, 'block-attach', 4, 5) |
---|
2003 | |
---|
2004 | if serverType == SERVER_XEN_API: |
---|
2005 | dom = args[0] |
---|
2006 | uname = args[1] |
---|
2007 | dev = args[2] |
---|
2008 | mode = args[3] |
---|
2009 | |
---|
2010 | # First create new VDI |
---|
2011 | vdi_record = { |
---|
2012 | "name_label": "vdi" + str(uname.__hash__()), |
---|
2013 | "name_description": "", |
---|
2014 | "SR": get_default_SR(), |
---|
2015 | "virtual_size": 0, |
---|
2016 | "sector_size": 512, |
---|
2017 | "type": "system", |
---|
2018 | "sharable": False, |
---|
2019 | "read_only": mode!="w", |
---|
2020 | "other_config": {"location": uname} |
---|
2021 | } |
---|
2022 | |
---|
2023 | vdi_ref = server.xenapi.VDI.create(vdi_record) |
---|
2024 | |
---|
2025 | # Now create new VBD |
---|
2026 | |
---|
2027 | vbd_record = { |
---|
2028 | "VM": get_single_vm(dom), |
---|
2029 | "VDI": vdi_ref, |
---|
2030 | "device": dev, |
---|
2031 | "bootable": True, |
---|
2032 | "mode": mode=="w" and "RW" or "RO", |
---|
2033 | "type": "Disk", |
---|
2034 | "qos_algorithm_type": "", |
---|
2035 | "qos_algorithm_params": {} |
---|
2036 | } |
---|
2037 | |
---|
2038 | server.xenapi.VBD.create(vbd_record) |
---|
2039 | |
---|
2040 | else: |
---|
2041 | (dom, vbd) = parse_block_configuration(args) |
---|
2042 | server.xend.domain.device_create(dom, vbd) |
---|
2043 | |
---|
2044 | |
---|
2045 | def xm_block_configure(args): |
---|
2046 | arg_check(args, 'block-configure', 4, 5) |
---|
2047 | |
---|
2048 | (dom, vbd) = parse_block_configuration(args) |
---|
2049 | server.xend.domain.device_configure(dom, vbd) |
---|
2050 | |
---|
2051 | |
---|
2052 | def xm_network_attach(args): |
---|
2053 | arg_check(args, 'network-attach', 1, 10) |
---|
2054 | |
---|
2055 | dom = args[0] |
---|
2056 | vif = ['vif'] |
---|
2057 | vif_params = ['type', 'mac', 'bridge', 'ip', 'script', \ |
---|
2058 | 'backend', 'vifname', 'rate', 'model'] |
---|
2059 | |
---|
2060 | if serverType == SERVER_XEN_API: |
---|
2061 | vif_record = { |
---|
2062 | "device": "eth0", |
---|
2063 | "network": get_default_Network(), |
---|
2064 | "VM": get_single_vm(dom), |
---|
2065 | "MAC": "", |
---|
2066 | "MTU": "", |
---|
2067 | "qos_algorithm_type": "", |
---|
2068 | "qos_algorithm_params": {}, |
---|
2069 | "other_config": {} |
---|
2070 | } |
---|
2071 | |
---|
2072 | def set(keys, val): |
---|
2073 | record = vif_record |
---|
2074 | for key in keys[:-1]: |
---|
2075 | record = record[key] |
---|
2076 | record[keys[-1]] = val |
---|
2077 | |
---|
2078 | def get_net_from_bridge(bridge): |
---|
2079 | # In OSS, we just assert network.name_label == bridge name |
---|
2080 | networks = dict([(record['name_label'], ref) |
---|
2081 | for ref, record in server.xenapi.network |
---|
2082 | .get_all_records().items()]) |
---|
2083 | if bridge not in networks.keys(): |
---|
2084 | raise "Unknown bridge name!" |
---|
2085 | return networks[bridge] |
---|
2086 | |
---|
2087 | vif_conv = { |
---|
2088 | 'type': |
---|
2089 | lambda x: None, |
---|
2090 | 'mac': |
---|
2091 | lambda x: set(['MAC'], x), |
---|
2092 | 'bridge': |
---|
2093 | lambda x: set(['network'], get_net_from_bridge(x)), |
---|
2094 | 'ip': |
---|
2095 | lambda x: set(['other_config', 'ip'], x), |
---|
2096 | 'script': |
---|
2097 | lambda x: set(['other_config', 'script'], x), |
---|
2098 | 'backend': |
---|
2099 | lambda x: set(['other_config', 'backend'], x), |
---|
2100 | 'vifname': |
---|
2101 | lambda x: set(['device'], x), |
---|
2102 | 'rate': |
---|
2103 | lambda x: set(['qos_algorithm_params', 'rate'], x), |
---|
2104 | 'model': |
---|
2105 | lambda x: None |
---|
2106 | } |
---|
2107 | |
---|
2108 | for a in args[1:]: |
---|
2109 | vif_param = a.split("=") |
---|
2110 | if len(vif_param) != 2 or vif_param[1] == '' or \ |
---|
2111 | vif_param[0] not in vif_params: |
---|
2112 | err("Invalid argument: %s" % a) |
---|
2113 | usage('network-attach') |
---|
2114 | else: |
---|
2115 | vif_conv[vif_param[0]](vif_param[1]) |
---|
2116 | |
---|
2117 | server.xenapi.VIF.create(vif_record) |
---|
2118 | else: |
---|
2119 | for a in args[1:]: |
---|
2120 | vif_param = a.split("=") |
---|
2121 | if len(vif_param) != 2 or vif_param[1] == '' or \ |
---|
2122 | vif_param[0] not in vif_params: |
---|
2123 | err("Invalid argument: %s" % a) |
---|
2124 | usage('network-attach') |
---|
2125 | vif.append(vif_param) |
---|
2126 | server.xend.domain.device_create(dom, vif) |
---|
2127 | |
---|
2128 | |
---|
2129 | def detach(args, command, deviceClass): |
---|
2130 | arg_check(args, command, 2, 3) |
---|
2131 | |
---|
2132 | dom = args[0] |
---|
2133 | dev = args[1] |
---|
2134 | try: |
---|
2135 | force = args[2] |
---|
2136 | if (force != "--force") and (force != "-f"): |
---|
2137 | print "Ignoring option %s"%(force) |
---|
2138 | force = None |
---|
2139 | except IndexError: |
---|
2140 | force = None |
---|
2141 | |
---|
2142 | server.xend.domain.destroyDevice(dom, deviceClass, dev, force) |
---|
2143 | |
---|
2144 | |
---|
2145 | def xm_block_detach(args): |
---|
2146 | if serverType == SERVER_XEN_API: |
---|
2147 | arg_check(args, "xm_block_detach", 2, 3) |
---|
2148 | dom = args[0] |
---|
2149 | dev = args[1] |
---|
2150 | vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom)) |
---|
2151 | vbd_refs = [vbd_ref for vbd_ref in vbd_refs |
---|
2152 | if server.xenapi.VBD.get_device(vbd_ref) == dev] |
---|
2153 | if len(vbd_refs) > 0: |
---|
2154 | vbd_ref = vbd_refs[0] |
---|
2155 | vdi_ref = server.xenapi.VBD.get_VDI(vbd_ref) |
---|
2156 | |
---|
2157 | server.xenapi.VBD.destroy(vbd_ref) |
---|
2158 | |
---|
2159 | if len(server.xenapi.VDI.get_VBDs(vdi_ref)) <= 0: |
---|
2160 | server.xenapi.VDI.destroy(vdi_ref) |
---|
2161 | else: |
---|
2162 | raise OptionError("Cannot find device '%s' in domain '%s'" |
---|
2163 | % (dev,dom)) |
---|
2164 | else: |
---|
2165 | try: |
---|
2166 | detach(args, 'block-detach', 'vbd') |
---|
2167 | return |
---|
2168 | except: |
---|
2169 | pass |
---|
2170 | detach(args, 'block-detach', 'tap') |
---|
2171 | |
---|
2172 | def xm_network_detach(args): |
---|
2173 | if serverType == SERVER_XEN_API: |
---|
2174 | arg_check(args, "xm_block_detach", 2, 3) |
---|
2175 | dom = args[0] |
---|
2176 | devid = args[1] |
---|
2177 | vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom)) |
---|
2178 | vif_refs = [vif_ref for vif_ref in vif_refs |
---|
2179 | if server.xenapi.VIF.\ |
---|
2180 | get_runtime_properties(vif_ref)["handle"] == devid] |
---|
2181 | if len(vif_refs) > 0: |
---|
2182 | vif_ref = vif_refs[0] |
---|
2183 | |
---|
2184 | server.xenapi.VIF.destroy(vif_ref) |
---|
2185 | else: |
---|
2186 | print "Cannot find device '%s' in domain '%s'" % (devid,dom) |
---|
2187 | else: |
---|
2188 | detach(args, 'network-detach', 'vif') |
---|
2189 | |
---|
2190 | |
---|
2191 | def xm_vnet_list(args): |
---|
2192 | xenapi_unsupported() |
---|
2193 | try: |
---|
2194 | (options, params) = getopt.gnu_getopt(args, 'l', ['long']) |
---|
2195 | except getopt.GetoptError, opterr: |
---|
2196 | err(opterr) |
---|
2197 | usage('vnet-list') |
---|
2198 | |
---|
2199 | use_long = 0 |
---|
2200 | for (k, v) in options: |
---|
2201 | if k in ['-l', '--long']: |
---|
2202 | use_long = 1 |
---|
2203 | |
---|
2204 | if params: |
---|
2205 | use_long = 1 |
---|
2206 | vnets = params |
---|
2207 | else: |
---|
2208 | vnets = server.xend_vnets() |
---|
2209 | |
---|
2210 | for vnet in vnets: |
---|
2211 | try: |
---|
2212 | if use_long: |
---|
2213 | info = server.xend_vnet(vnet) |
---|
2214 | PrettyPrint.prettyprint(info) |
---|
2215 | else: |
---|
2216 | print vnet |
---|
2217 | except Exception, ex: |
---|
2218 | print vnet, ex |
---|
2219 | |
---|
2220 | def xm_vnet_create(args): |
---|
2221 | xenapi_unsupported() |
---|
2222 | arg_check(args, "vnet-create", 1) |
---|
2223 | conf = args[0] |
---|
2224 | if not os.access(conf, os.R_OK): |
---|
2225 | print "File not found: %s" % conf |
---|
2226 | sys.exit(1) |
---|
2227 | |
---|
2228 | server.xend_vnet_create(conf) |
---|
2229 | |
---|
2230 | def xm_vnet_delete(args): |
---|
2231 | xenapi_unsupported() |
---|
2232 | arg_check(args, "vnet-delete", 1) |
---|
2233 | vnet = args[0] |
---|
2234 | server.xend_vnet_delete(vnet) |
---|
2235 | |
---|
2236 | def xm_network_new(args): |
---|
2237 | xenapi_only() |
---|
2238 | arg_check(args, "network-new", 1) |
---|
2239 | network = args[0] |
---|
2240 | |
---|
2241 | record = { |
---|
2242 | "name_label": network, |
---|
2243 | "name_description": "", |
---|
2244 | "other_config": {}, |
---|
2245 | "default_gateway": "", |
---|
2246 | "default_netmask": "" |
---|
2247 | } |
---|
2248 | |
---|
2249 | server.xenapi.network.create(record) |
---|
2250 | |
---|
2251 | def xm_network_del(args): |
---|
2252 | xenapi_only() |
---|
2253 | arg_check(args, "network-del", 1) |
---|
2254 | network = args[0] |
---|
2255 | |
---|
2256 | networks = dict([(record['name_label'], ref) |
---|
2257 | for ref, record in |
---|
2258 | server.xenapi.network.get_all_records().items()]) |
---|
2259 | |
---|
2260 | if network not in networks.keys(): |
---|
2261 | raise ValueError("'%s' is not a valid network name" % network) |
---|
2262 | |
---|
2263 | server.xenapi.network.destroy(networks[network]) |
---|
2264 | |
---|
2265 | def xm_network_show(args): |
---|
2266 | xenapi_only() |
---|
2267 | arg_check(args, "network-show", 0) |
---|
2268 | |
---|
2269 | networks = server.xenapi.network.get_all_records() |
---|
2270 | pifs = server.xenapi.PIF.get_all_records() |
---|
2271 | vifs = server.xenapi.VIF.get_all_records() |
---|
2272 | |
---|
2273 | print '%-20s %-40s %-10s' % \ |
---|
2274 | ('Name', 'VIFs', 'PIFs') |
---|
2275 | |
---|
2276 | format2 = "%(name_label)-20s %(vif)-40s %(pif)-10s" |
---|
2277 | |
---|
2278 | for network_ref, network in networks.items(): |
---|
2279 | for i in range(max(len(network['PIFs']), |
---|
2280 | len(network['VIFs']), 1)): |
---|
2281 | if i < len(network['PIFs']): |
---|
2282 | pif_uuid = network['PIFs'][i] |
---|
2283 | else: |
---|
2284 | pif_uuid = None |
---|
2285 | |
---|
2286 | if i < len(network['VIFs']): |
---|
2287 | vif_uuid = network['VIFs'][i] |
---|
2288 | else: |
---|
2289 | vif_uuid = None |
---|
2290 | |
---|
2291 | pif = pifs.get(pif_uuid, None) |
---|
2292 | vif = vifs.get(vif_uuid, None) |
---|
2293 | |
---|
2294 | if vif: |
---|
2295 | dom_name = server.xenapi.VM.get_name_label(vif['VM']) |
---|
2296 | vif = "%s.%s" % (dom_name, vif['device']) |
---|
2297 | else: |
---|
2298 | vif = '' |
---|
2299 | |
---|
2300 | if pif: |
---|
2301 | if int(pif['VLAN']) > -1: |
---|
2302 | pif = '%s.%s' % (pif['device'], pif['VLAN']) |
---|
2303 | else: |
---|
2304 | pif = pif['device'] |
---|
2305 | else: |
---|
2306 | pif = '' |
---|
2307 | |
---|
2308 | if i == 0: |
---|
2309 | r = {'name_label':network['name_label'], |
---|
2310 | 'vif':vif, 'pif':pif} |
---|
2311 | else: |
---|
2312 | r = {'name_label':'', 'vif':vif, 'pif':pif} |
---|
2313 | |
---|
2314 | print format2 % r |
---|
2315 | |
---|
2316 | |
---|
2317 | commands = { |
---|
2318 | "shell": xm_shell, |
---|
2319 | "event-monitor": xm_event_monitor, |
---|
2320 | # console commands |
---|
2321 | "console": xm_console, |
---|
2322 | # xenstat commands |
---|
2323 | "top": xm_top, |
---|
2324 | # domain commands |
---|
2325 | "delete": xm_delete, |
---|
2326 | "destroy": xm_destroy, |
---|
2327 | "domid": xm_domid, |
---|
2328 | "domname": xm_domname, |
---|
2329 | "dump-core": xm_dump_core, |
---|
2330 | "reboot": xm_reboot, |
---|
2331 | "rename": xm_rename, |
---|
2332 | "restore": xm_restore, |
---|
2333 | "resume": xm_resume, |
---|
2334 | "save": xm_save, |
---|
2335 | "shutdown": xm_shutdown, |
---|
2336 | "start": xm_start, |
---|
2337 | "sysrq": xm_sysrq, |
---|
2338 | "trigger": xm_trigger, |
---|
2339 | "uptime": xm_uptime, |
---|
2340 | "suspend": xm_suspend, |
---|
2341 | "list": xm_list, |
---|
2342 | # memory commands |
---|
2343 | "mem-max": xm_mem_max, |
---|
2344 | "mem-set": xm_mem_set, |
---|
2345 | # cpu commands |
---|
2346 | "vcpu-pin": xm_vcpu_pin, |
---|
2347 | "vcpu-list": xm_vcpu_list, |
---|
2348 | "vcpu-set": xm_vcpu_set, |
---|
2349 | # special |
---|
2350 | "pause": xm_pause, |
---|
2351 | "unpause": xm_unpause, |
---|
2352 | # host commands |
---|
2353 | "debug-keys": xm_debug_keys, |
---|
2354 | "dmesg": xm_dmesg, |
---|
2355 | "info": xm_info, |
---|
2356 | "log": xm_log, |
---|
2357 | "serve": xm_serve, |
---|
2358 | # scheduler |
---|
2359 | "sched-sedf": xm_sched_sedf, |
---|
2360 | "sched-credit": xm_sched_credit, |
---|
2361 | # block |
---|
2362 | "block-attach": xm_block_attach, |
---|
2363 | "block-detach": xm_block_detach, |
---|
2364 | "block-list": xm_block_list, |
---|
2365 | "block-configure": xm_block_configure, |
---|
2366 | # network (AKA vifs) |
---|
2367 | "network-attach": xm_network_attach, |
---|
2368 | "network-detach": xm_network_detach, |
---|
2369 | "network-list": xm_network_list, |
---|
2370 | # network (as in XenAPI) |
---|
2371 | "network-new": xm_network_new, |
---|
2372 | "network-del": xm_network_del, |
---|
2373 | "network-show": xm_network_show, |
---|
2374 | # vnet |
---|
2375 | "vnet-list": xm_vnet_list, |
---|
2376 | "vnet-create": xm_vnet_create, |
---|
2377 | "vnet-delete": xm_vnet_delete, |
---|
2378 | # vtpm |
---|
2379 | "vtpm-list": xm_vtpm_list, |
---|
2380 | } |
---|
2381 | |
---|
2382 | ## The commands supported by a separate argument parser in xend.xm. |
---|
2383 | IMPORTED_COMMANDS = [ |
---|
2384 | 'create', |
---|
2385 | 'new', |
---|
2386 | 'migrate', |
---|
2387 | 'labels', |
---|
2388 | 'cfgbootpolicy', |
---|
2389 | 'makepolicy', |
---|
2390 | 'loadpolicy', |
---|
2391 | 'dumppolicy', |
---|
2392 | 'addlabel', |
---|
2393 | 'rmlabel', |
---|
2394 | 'getlabel', |
---|
2395 | 'dry-run', |
---|
2396 | 'resources', |
---|
2397 | ] |
---|
2398 | |
---|
2399 | for c in IMPORTED_COMMANDS: |
---|
2400 | commands[c] = eval('lambda args: xm_importcommand("%s", args)' % c) |
---|
2401 | |
---|
2402 | aliases = { |
---|
2403 | "balloon": "mem-set", |
---|
2404 | "set-vcpus": "vcpu-set", |
---|
2405 | "vif-list": "network-list", |
---|
2406 | "vbd-create": "block-attach", |
---|
2407 | "vbd-destroy": "block-detach", |
---|
2408 | "vbd-list": "block-list", |
---|
2409 | } |
---|
2410 | |
---|
2411 | |
---|
2412 | def xm_lookup_cmd(cmd): |
---|
2413 | if commands.has_key(cmd): |
---|
2414 | return commands[cmd] |
---|
2415 | elif aliases.has_key(cmd): |
---|
2416 | deprecated(cmd,aliases[cmd]) |
---|
2417 | return commands[aliases[cmd]] |
---|
2418 | elif cmd == 'help': |
---|
2419 | longHelp() |
---|
2420 | sys.exit(0) |
---|
2421 | else: |
---|
2422 | # simulate getopt's prefix matching behaviour |
---|
2423 | if len(cmd) > 1: |
---|
2424 | same_prefix_cmds = [commands[c] for c in commands.keys() \ |
---|
2425 | if c[:len(cmd)] == cmd] |
---|
2426 | # only execute if there is only 1 match |
---|
2427 | if len(same_prefix_cmds) == 1: |
---|
2428 | return same_prefix_cmds[0] |
---|
2429 | return None |
---|
2430 | |
---|
2431 | def deprecated(old,new): |
---|
2432 | print >>sys.stderr, ( |
---|
2433 | "Command %s is deprecated. Please use xm %s instead." % (old, new)) |
---|
2434 | |
---|
2435 | def main(argv=sys.argv): |
---|
2436 | if len(argv) < 2: |
---|
2437 | usage() |
---|
2438 | |
---|
2439 | # intercept --help(-h) and output our own help |
---|
2440 | for help in ['--help', '-h']: |
---|
2441 | if help in argv[1:]: |
---|
2442 | if help == argv[1]: |
---|
2443 | longHelp() |
---|
2444 | sys.exit(0) |
---|
2445 | else: |
---|
2446 | usage(argv[1]) |
---|
2447 | |
---|
2448 | cmd_name = argv[1] |
---|
2449 | cmd = xm_lookup_cmd(cmd_name) |
---|
2450 | if cmd: |
---|
2451 | # strip off prog name and subcmd |
---|
2452 | args = argv[2:] |
---|
2453 | _, rc = _run_cmd(cmd, cmd_name, args) |
---|
2454 | sys.exit(rc) |
---|
2455 | else: |
---|
2456 | err('Subcommand %s not found!' % cmd_name) |
---|
2457 | usage() |
---|
2458 | |
---|
2459 | def _run_cmd(cmd, cmd_name, args): |
---|
2460 | global server |
---|
2461 | |
---|
2462 | try: |
---|
2463 | if server is None: |
---|
2464 | if serverType == SERVER_XEN_API: |
---|
2465 | server = XenAPI.Session(serverURI) |
---|
2466 | username, password = parseAuthentication() |
---|
2467 | server.login_with_password(username, password) |
---|
2468 | def logout(): |
---|
2469 | try: |
---|
2470 | server.xenapi.session.logout() |
---|
2471 | except: |
---|
2472 | pass |
---|
2473 | atexit.register(logout) |
---|
2474 | else: |
---|
2475 | server = ServerProxy(serverURI) |
---|
2476 | |
---|
2477 | return True, cmd(args) |
---|
2478 | except socket.error, ex: |
---|
2479 | if os.geteuid() != 0: |
---|
2480 | err("Most commands need root access. Please try again as root.") |
---|
2481 | else: |
---|
2482 | err("Unable to connect to xend: %s. Is xend running?" % ex[1]) |
---|
2483 | except KeyboardInterrupt: |
---|
2484 | print "Interrupted." |
---|
2485 | return True, '' |
---|
2486 | except IOError, ex: |
---|
2487 | if os.geteuid() != 0: |
---|
2488 | err("Most commands need root access. Please try again as root.") |
---|
2489 | else: |
---|
2490 | err("Unable to connect to xend: %s." % ex[1]) |
---|
2491 | except SystemExit, code: |
---|
2492 | return code == 0, code |
---|
2493 | except XenAPI.Failure, exn: |
---|
2494 | for line in [''] + wrap(str(exn), 80) + ['']: |
---|
2495 | print >>sys.stderr, line |
---|
2496 | except xmlrpclib.Fault, ex: |
---|
2497 | if ex.faultCode == XendClient.ERROR_INVALID_DOMAIN: |
---|
2498 | err("Domain '%s' does not exist." % ex.faultString) |
---|
2499 | else: |
---|
2500 | err(ex.faultString) |
---|
2501 | _usage(cmd_name) |
---|
2502 | except xmlrpclib.ProtocolError, ex: |
---|
2503 | if ex.errcode == -1: |
---|
2504 | print >>sys.stderr, ( |
---|
2505 | "Xend has probably crashed! Invalid or missing HTTP " |
---|
2506 | "status code.") |
---|
2507 | else: |
---|
2508 | print >>sys.stderr, ( |
---|
2509 | "Xend has probably crashed! ProtocolError(%d, %s)." % |
---|
2510 | (ex.errcode, ex.errmsg)) |
---|
2511 | except (ValueError, OverflowError): |
---|
2512 | err("Invalid argument.") |
---|
2513 | _usage(cmd_name) |
---|
2514 | except OptionError, e: |
---|
2515 | err(str(e)) |
---|
2516 | _usage(cmd_name) |
---|
2517 | print e.usage |
---|
2518 | except XenAPIUnsupportedException, e: |
---|
2519 | err(str(e)) |
---|
2520 | except Exception, e: |
---|
2521 | if serverType != SERVER_XEN_API: |
---|
2522 | from xen.util import security |
---|
2523 | if isinstance(e, security.ACMError): |
---|
2524 | err(str(e)) |
---|
2525 | return False, 1 |
---|
2526 | print "Unexpected error:", sys.exc_info()[0] |
---|
2527 | print |
---|
2528 | print "Please report to xen-devel@lists.xensource.com" |
---|
2529 | raise |
---|
2530 | |
---|
2531 | return False, 1 |
---|
2532 | |
---|
2533 | if __name__ == "__main__": |
---|
2534 | main() |
---|