ia64/xen-unstable

view tools/python/xen/xend/XendClient.py @ 1770:1331621fe269

bitkeeper revision 1.1076 (40f3f7b4Cj4P09-PODiTO2MMFlKicw)

Add device create and device destroy for an existing domain.
author mjw@wray-m-3.hpl.hp.com
date Tue Jul 13 14:54:44 2004 +0000 (2004-07-13)
parents 1858589ab205
children e4a326567073
line source
1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
2 """Client API for the HTTP interface on xend.
3 Callable as a script - see main().
5 This API is the 'control-plane' for xend.
6 The 'data-plane' is done separately. For example, consoles
7 are accessed via sockets on xend, but the list of consoles
8 is accessible via this API.
9 """
10 import sys
11 import httplib
12 import types
13 from StringIO import StringIO
14 import urlparse
16 from encode import *
17 import sxp
18 import PrettyPrint
20 DEBUG = 0
22 class XendError(RuntimeError):
23 pass
25 class Foo(httplib.HTTPResponse):
27 def begin(self):
28 fin = self.fp
29 while(1):
30 buf = fin.readline()
31 print "***", buf
32 if buf == '':
33 print
34 sys.exit()
37 def sxprio(sxpr):
38 """Convert an sxpr to a string.
39 """
40 io = StringIO()
41 sxp.show(sxpr, out=io)
42 print >> io
43 io.seek(0)
44 return io
46 def fileof(val):
47 """Converter for passing configs.
48 Handles lists, files directly.
49 Assumes a string is a file name and passes its contents.
50 """
51 if isinstance(val, types.ListType):
52 return sxprio(val)
53 if isinstance(val, types.StringType):
54 return file(val)
55 if hasattr(val, 'readlines'):
56 return val
58 # todo: need to sort of what urls/paths are using for objects.
59 # e.g. for domains at the moment return '0'.
60 # should probably return abs path w.r.t. server, e.g. /xend/domain/0.
61 # As an arg, assume abs path is obj uri, otherwise just id.
63 # Function to convert to full url: Xend.uri(path), e.g.
64 # maps /xend/domain/0 to http://wray-m-3.hpl.hp.com:8000/xend/domain/0
65 # And should accept urls for ids?
67 def urljoin(location, root, prefix='', rest=''):
68 prefix = str(prefix)
69 rest = str(rest)
70 base = 'http://' + location + root + prefix
71 url = urlparse.urljoin(base, rest)
72 return url
74 def nodeurl(location, root, id=''):
75 return urljoin(location, root, 'node/', id)
77 def domainurl(location, root, id=''):
78 return urljoin(location, root, 'domain/', id)
80 def consoleurl(location, root, id=''):
81 return urljoin(location, root, 'console/', id)
83 def deviceurl(location, root, id=''):
84 return urljoin(location, root, 'device/', id)
86 def vneturl(location, root, id=''):
87 return urljoin(location, root, 'vnet/', id)
89 def eventurl(location, root, id=''):
90 return urljoin(location, root, 'event/', id)
92 def dmesgurl(location, root, id=''):
93 return urljoin(location, root, 'node/dmesg/', id)
95 def xend_request(url, method, data=None):
96 """Make a request to xend.
98 url xend request url
99 method http method: POST or GET
100 data request argument data (dict)
101 """
102 urlinfo = urlparse.urlparse(url)
103 (uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo
104 if DEBUG: print url, urlinfo
105 if uproto != 'http':
106 raise StandardError('Invalid protocol: ' + uproto)
107 if DEBUG: print '>xend_request', ulocation, upath, method, data
108 (hdr, args) = encode_data(data)
109 if data and method == 'GET':
110 upath += '?' + args
111 args = None
112 if method == "POST" and upath.endswith('/'):
113 upath = upath[:-1]
114 if DEBUG: print "ulocation=", ulocation, "upath=", upath, "args=", args
115 #hdr['User-Agent'] = 'Mozilla'
116 #hdr['Accept'] = 'text/html,text/plain'
117 conn = httplib.HTTPConnection(ulocation)
118 #conn.response_class = Foo
119 if DEBUG: conn.set_debuglevel(1)
120 conn.request(method, upath, args, hdr)
121 resp = conn.getresponse()
122 if DEBUG: print resp.status, resp.reason
123 if DEBUG: print resp.msg.headers
124 if resp.status in [204, 404]:
125 return None
126 if resp.status not in [200, 201, 202, 203]:
127 raise XendError(resp.reason)
128 pin = sxp.Parser()
129 data = resp.read()
130 if DEBUG: print "***data" , data
131 if DEBUG: print "***"
132 pin.input(data);
133 pin.input_eof()
134 conn.close()
135 val = pin.get_val()
136 #if isinstance(val, types.ListType) and sxp.name(val) == 'val':
137 # val = val[1]
138 if isinstance(val, types.ListType) and sxp.name(val) == 'err':
139 raise XendError(val[1])
140 if DEBUG: print '**val='; sxp.show(val); print
141 return val
143 def xend_get(url, args=None):
144 """Make a xend request using GET.
145 Requests using GET are 'safe' and may be repeated without
146 nasty side-effects.
147 """
148 return xend_request(url, "GET", args)
150 def xend_call(url, data):
151 """Make xend request using POST.
152 Requests using POST potentially cause side-effects and should
153 not be repeated unless it really is wanted to do the side
154 effect again.
155 """
156 return xend_request(url, "POST", data)
158 class Xend:
160 """Default location of the xend server."""
161 SRV_DEFAULT = "localhost:8000"
163 """Default path to the xend root on the server."""
164 ROOT_DEFAULT = "/xend/"
166 def __init__(self, srv=None, root=None):
167 self.bind(srv, root)
169 def bind(self, srv=None, root=None):
170 """Bind to a given server.
172 srv server location (host:port)
173 root server xend root path
174 """
175 if srv is None: srv = self.SRV_DEFAULT
176 if root is None: root = self.ROOT_DEFAULT
177 if not root.endswith('/'): root += '/'
178 self.location = srv
179 self.root = root
181 def nodeurl(self, id=''):
182 return nodeurl(self.location, self.root, id)
184 def domainurl(self, id=''):
185 return domainurl(self.location, self.root, id)
187 def consoleurl(self, id=''):
188 return consoleurl(self.location, self.root, id)
190 def deviceurl(self, id=''):
191 return deviceurl(self.location, self.root, id)
193 def vneturl(self, id=''):
194 return vneturl(self.location, self.root, id)
196 def eventurl(self, id=''):
197 return eventurl(self.location, self.root, id)
199 def dmesgurl(self, id=''):
200 return dmesgurl(self.location, self.root, id)
202 def xend(self):
203 return xend_get(urljoin(self.location, self.root))
205 def xend_node(self):
206 return xend_get(self.nodeurl())
208 def xend_node_cpu_rrobin_slice_set(self, slice):
209 return xend_call(self.nodeurl(),
210 {'op' : 'cpu_rrobin_slice_set',
211 'slice' : slice })
213 def xend_node_cpu_bvt_slice_set(self, ctx_allow):
214 return xend_call(self.nodeurl(),
215 {'op' : 'cpu_bvt_slice_set',
216 'ctx_allow' : ctx_allow })
218 def xend_node_cpu_fbvt_slice_set(self, ctx_allow):
219 return xend_call(self.nodeurl(),
220 {'op' : 'cpu_fbvt_slice_set',
221 'ctx_allow' : ctx_allow })
223 def xend_domains(self):
224 return xend_get(self.domainurl())
226 def xend_domain_create(self, conf):
227 return xend_call(self.domainurl(),
228 {'op' : 'create',
229 'config' : fileof(conf) })
231 def xend_domain_restore(self, filename):
232 return xend_call(self.domainurl(),
233 {'op' : 'restore',
234 'file' : filename })
236 def xend_domain_configure(self, id, config):
237 return xend_call(self.domainurl(id),
238 {'op' : 'configure',
239 'config' : fileof(conf) })
241 def xend_domain(self, id):
242 return xend_get(self.domainurl(id))
244 def xend_domain_unpause(self, id):
245 return xend_call(self.domainurl(id),
246 {'op' : 'unpause' })
248 def xend_domain_pause(self, id):
249 return xend_call(self.domainurl(id),
250 {'op' : 'pause' })
252 def xend_domain_shutdown(self, id, reason):
253 return xend_call(self.domainurl(id),
254 {'op' : 'shutdown',
255 'reason' : reason })
257 def xend_domain_destroy(self, id):
258 return xend_call(self.domainurl(id),
259 {'op' : 'destroy' })
261 def xend_domain_save(self, id, filename):
262 return xend_call(self.domainurl(id),
263 {'op' : 'save',
264 'file' : filename })
266 def xend_domain_migrate(self, id, dst):
267 return xend_call(self.domainurl(id),
268 {'op' : 'migrate',
269 'destination': dst })
271 def xend_domain_pincpu(self, id, cpu):
272 return xend_call(self.domainurl(id),
273 {'op' : 'pincpu',
274 'cpu' : cpu })
276 def xend_domain_cpu_bvt_set(self, id, mcuadv, warp, warpl, warpu):
277 return xend_call(self.domainurl(id),
278 {'op' : 'cpu_bvt_set',
279 'mcuadv' : mcuadv,
280 'warp' : warp,
281 'warpl' : warpl,
282 'warpu' : warpu })
284 def xend_domain_cpu_fbvt_set(self, id, mcuadv, warp, warpl, warpu):
285 return xend_call(self.domainurl(id),
286 {'op' : 'cpu_fbvt_set',
287 'mcuadv' : mcuadv,
288 'warp' : warp,
289 'warpl' : warpl,
290 'warpu' : warpu })
293 def xend_domain_cpu_atropos_set(self, id, period, slice, latency, xtratime):
294 return xend_call(self.domainurl(id),
295 {'op' : 'cpu_atropos_set',
296 'period' : period,
297 'slice' : slice,
298 'latency' : latency,
299 'xtratime': xtratime })
301 def xend_domain_vifs(self, id):
302 return xend_get(self.domainurl(id),
303 { 'op' : 'vifs' })
305 def xend_domain_vif(self, id, vif):
306 return xend_get(self.domainurl(id),
307 { 'op' : 'vif',
308 'vif' : vif })
310 def xend_domain_vbds(self, id):
311 return xend_get(self.domainurl(id),
312 {'op' : 'vbds'})
314 def xend_domain_vbd(self, id, vbd):
315 return xend_get(self.domainurl(id),
316 {'op' : 'vbd',
317 'vbd' : vbd })
319 def xend_domain_device_create(self, id, config):
320 return xend_call(self.domainurl(id),
321 {'op' : 'device_create',
322 'config' : fileof(config) })
324 def xend_domain_device_destroy(self, id, type, idx):
325 return xend_call(self.domainurl(id),
326 {'op' : 'device_destroy',
327 'type' : type,
328 'index' : idx })
330 def xend_consoles(self):
331 return xend_get(self.consoleurl())
333 def xend_console(self, id):
334 return xend_get(self.consoleurl(id))
336 def xend_vnets(self):
337 return xend_get(self.vneturl())
339 def xend_vnet_create(self, conf):
340 return xend_call(self.vneturl(),
341 {'op': 'create', 'config': fileof(conf) })
343 def xend_vnet(self, id):
344 return xend_get(self.vneturl(id))
346 def xend_vnet_delete(self, id):
347 return xend_call(self.vneturl(id),
348 {'op': 'delete' })
350 def xend_event_inject(self, sxpr):
351 val = xend_call(self.eventurl(),
352 {'op': 'inject', 'event': fileof(sxpr) })
354 def xend_dmesg(self):
355 return xend_get(self.dmesgurl())
358 def main(argv):
359 """Call an API function:
361 python XendClient.py fn args...
363 The leading 'xend_' on the function can be omitted.
364 Example:
366 > python XendClient.py domains
367 (domain 0 8)
368 > python XendClient.py domain 0
369 (domain (id 0) (name Domain-0) (memory 128))
370 """
371 server = Xend()
372 fn = argv[1]
373 if not fn.startswith('xend'):
374 fn = 'xend_' + fn
375 args = argv[2:]
376 val = getattr(server, fn)(*args)
377 PrettyPrint.prettyprint(val)
378 print
380 if __name__ == "__main__":
381 main(sys.argv)
382 else:
383 server = Xend()