1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import haizea.common.defaults as defaults
19 import haizea.common.constants as constants
20 from haizea.core.leases import Lease, Capacity, Duration, Timestamp, DiskImageSoftwareEnvironment
21 from haizea.common.utils import round_datetime
22 from haizea.cli.optionparser import Option
23 from haizea.cli import Command
24 import xmlrpclib
25 import sys
26 from mx.DateTime import ISO, now, DateTimeDelta, Parser
27
28 try:
29 import xml.etree.ElementTree as ET
30 except ImportError:
31
32 import elementtree.ElementTree as ET
33
36 Command.__init__(self, argv)
37 self.optparser.add_option(Option("-s", "--server", action="store", type="string", dest="server", default=defaults.RPC_URI,
38 help = """
39 Haizea RPC server URI. If not specified, the default %s is used
40 """ % defaults.RPC_URI))
41
43 return xmlrpclib.ServerProxy(server, allow_none=True)
44
46 """
47 Requests a new lease.
48 """
49
50 name = "haizea-request-lease"
51
52 START_NOW = "now"
53 START_BESTEFFORT = "best_effort"
54 DURATION_UNLIMITED = "unlimited"
55
57 RPCCommand.__init__(self, argv)
58
59 self.optparser.add_option(Option("-f", "--file", action="store", type="string", dest="file",
60 help = """
61 File containing a lease description in XML.
62 """))
63 self.optparser.add_option(Option("-t", "--start", action="store", type="string", dest="start",
64 help = """
65 Starting time. Can be an ISO timestamp, "best_effort", or "now"
66 """))
67 self.optparser.add_option(Option("-d", "--duration", action="store", type="string", dest="duration",
68 help = """
69 Duration. Can be an ISO timestamp or "unlimited"
70 """))
71 self.optparser.add_option(Option("-n", "--numnodes", action="store", type="int", dest="numnodes",
72 help = """
73 Number of nodes.
74 """))
75 self.optparser.add_option(Option("--preemptible", action="store_true", dest="preemptible",
76 help = """
77 Specifies a preemptible lease.
78 """))
79 self.optparser.add_option(Option("--non-preemptible", action="store_false", dest="preemptible",
80 help = """
81 Specifies a non-preemptible lease.
82 """))
83 self.optparser.add_option(Option("-c", "--cpu", action="store", type="int", dest="cpu",
84 help = """
85 Percentage of CPU (must be 0 < c <= 100)
86 """))
87 self.optparser.add_option(Option("-m", "--mem", action="store", type="int", dest="mem",
88 help = """
89 Memory per node (in MB)
90 """))
91 self.optparser.add_option(Option("-i", "--vmimage", action="store", type="string", dest="vmimage",
92 help = """
93 Disk image identifier.
94 """))
95 self.optparser.add_option(Option("-z", "--vmimagesize", action="store", type="int", dest="vmimagesize",
96 help = """
97 Disk image size.
98 """))
99
101 self.parse_options()
102
103 if self.opt.file != None:
104 lease_elem = ET.parse(self.opt.file).getroot()
105
106
107 exact = lease.find("start/exact")
108 if exact != None:
109 exact_time = exact.get("time")
110 exact.set("time", str(self.__absolute_time(exact_time)))
111 lease_xml_str = ET.tostring(lease_elem)
112 else:
113 if self.opt.preemptible == None:
114 preemptible = False
115 else:
116 preemptible = self.opt.preemptible
117
118 capacity = Capacity([constants.RES_CPU, constants.RES_MEM])
119 capacity.set_quantity(constants.RES_CPU, int(self.opt.cpu) * 100)
120 capacity.set_quantity(constants.RES_MEM, int(self.opt.mem))
121 requested_resources = dict([(i+1, capacity) for i in range(self.opt.numnodes)])
122 if self.opt.duration == haizea_request_lease.DURATION_UNLIMITED:
123
124
125 duration = DateTimeDelta(36500)
126 else:
127 duration = ISO.ParseTimeDelta(self.opt.duration)
128
129 if self.opt.start == haizea_request_lease.START_NOW:
130 lease = Lease(lease_id = None,
131 submit_time = None,
132 requested_resources = requested_resources,
133 start = Timestamp(Timestamp.NOW),
134 duration = Duration(duration),
135 deadline = None,
136 preemptible=preemptible,
137 software = DiskImageSoftwareEnvironment(self.opt.vmimage, self.opt.vmimagesize),
138 state = None
139 )
140 elif self.opt.start == haizea_request_lease.START_BESTEFFORT:
141 lease = Lease(lease_id = None,
142 submit_time = None,
143 requested_resources = requested_resources,
144 start = Timestamp(Timestamp.UNSPECIFIED),
145 duration = Duration(duration),
146 deadline = None,
147 preemptible=preemptible,
148 software = DiskImageSoftwareEnvironment(self.opt.vmimage, self.opt.vmimagesize),
149 state = None
150 )
151 else:
152 start = self.__absolute_time(self.opt.start)
153 lease = Lease(lease_id = None,
154 submit_time = None,
155 requested_resources = requested_resources,
156 start = Timestamp(start),
157 duration = Duration(duration),
158 deadline = None,
159 preemptible=preemptible,
160 software = DiskImageSoftwareEnvironment(self.opt.vmimage, self.opt.vmimagesize),
161 state = None
162 )
163
164 lease_xml_str = ET.tostring(lease.to_xml())
165
166 server = self.create_rpc_proxy(self.opt.server)
167
168 try:
169 lease_id = server.create_lease(lease_xml_str)
170 print "Lease submitted correctly."
171 print "Lease ID: %i" % lease_id
172 except xmlrpclib.Fault, err:
173 print >> sys.stderr, "XMLRPC fault: %s" % err.faultString
174 if self.opt.debug:
175 raise
176 except Exception, msg:
177 print >> sys.stderr, "Error: %s" % msg
178 if self.opt.debug:
179 raise
180
182 if time_str[0] == "+":
183
184 time = round_datetime(now() + ISO.ParseTime(time_str[1:]))
185 else:
186 time = Parser.ParseDateTime(time_str)
187
188 return time
189
191 """
192 Cancel a lease.
193 """
194
195 name = "haizea-cancel-lease"
196
198 RPCCommand.__init__(self, argv)
199
200 self.optparser.add_option(Option("-l", "--lease", action="store", type="int", dest="lease",
201 help = """
202 ID of lease to cancel.
203 """))
204
206 self.parse_options()
207
208 server = self.create_rpc_proxy(self.opt.server)
209
210 try:
211 code = server.cancel_lease(self.opt.lease)
212 except xmlrpclib.Fault, err:
213 print >> sys.stderr, "XMLRPC fault: %s" % err.faultString
214 if self.opt.debug:
215 raise
216 except Exception, msg:
217 print >> sys.stderr, "Error: %s" % msg
218 if self.opt.debug:
219 raise
220
221
223 """
224 List all active leases in the system (i.e., not including completed or cancelled leases)
225 """
226
227 name = "haizea-list-leases"
228
231
233 self.parse_options()
234
235 server = self.create_rpc_proxy(self.opt.server)
236
237 fields = [("id","ID", 3),
238 ("type","Type", 12),
239 ("state","State", 9),
240 ("start_req", "Starting time", 22),
241 ("duration_req", "Duration", 12),
242 ("numnodes", "Nodes", 3)]
243
244 try:
245 leases = server.get_leases()
246 leases_fields = []
247 for lease_xml in leases:
248 lease = Lease.from_xml_string(lease_xml)
249 lease_fields = {}
250 lease_fields["id"] = lease.id
251 lease_fields["type"] = Lease.type_str[lease.get_type()]
252 lease_fields["state"] = Lease.state_str[lease.get_state()]
253 lease_fields["start_req"] = lease.start.requested
254 lease_fields["duration_req"] = lease.duration.requested
255 lease_fields["numnodes"] = len(lease.requested_resources)
256 leases_fields.append(lease_fields)
257 console_table_printer(fields, leases_fields)
258 except xmlrpclib.Fault, err:
259 print >> sys.stderr, "XMLRPC fault: %s" % err.faultString
260 if self.opt.debug:
261 raise
262 except Exception, msg:
263 print >> sys.stderr, "Error: %s" % msg
264 if self.opt.debug:
265 raise
266
267
269 """
270 List hosts managed by Haizea
271 """
272
273 name = "haizea-list-hosts"
274
277
279 self.parse_options()
280
281 server = self.create_rpc_proxy(self.opt.server)
282
283 fields = [("id","ID", 3),
284 ("hostname","Hostname", 10),
285 ("cpu","CPUs", 6),
286 ("mem", "Mem", 6)]
287
288 try:
289 hosts = server.get_hosts()
290 console_table_printer(fields, hosts)
291 except xmlrpclib.Fault, err:
292 print >> sys.stderr, "XMLRPC fault: %s" % err.faultString
293 if self.opt.debug:
294 raise
295 except Exception, msg:
296 print >> sys.stderr, "Error: %s" % msg
297 if self.opt.debug:
298 raise
299
301 """
302 Show the contents of the Haizea queue
303 """
304
305 name = "haizea-show-queue"
306
309
311 self.parse_options()
312
313 server = self.create_rpc_proxy(self.opt.server)
314
315 fields = [("id","ID", 3),
316 ("type","Type", 12),
317 ("state","State", 9),
318 ("start_req", "Starting time", 22),
319 ("duration_req", "Duration", 12),
320 ("numnodes", "Nodes", 3)]
321
322 try:
323 leases = server.get_queue()
324 if len(leases) == 0:
325 print "Queue is empty."
326 else:
327 leases_fields = []
328 for lease_xml in leases:
329 lease = Lease.from_xml_string(lease_xml)
330 lease_fields = {}
331 lease_fields["id"] = lease.id
332 lease_fields["type"] = Lease.type_str[lease.get_type()]
333 lease_fields["state"] = Lease.state_str[lease.get_state()]
334 lease_fields["start_req"] = lease.start.requested
335 lease_fields["duration_req"] = lease.duration.requested
336 lease_fields["numnodes"] = len(lease.requested_resources)
337 leases_fields.append(lease_fields)
338 console_table_printer(fields, leases_fields)
339 except xmlrpclib.Fault, err:
340 print >> sys.stderr, "XMLRPC fault: %s" % err.faultString
341 if self.opt.debug:
342 raise
343 except Exception, msg:
344 print >> sys.stderr, "Error: %s" % msg
345 if self.opt.debug:
346 raise
347
348
350 print "\33[1m\33[4m",
351 for (name,pname,width) in fields:
352 width = max(len(pname),width) + 1
353 centered = pname.ljust(width)
354 print centered,
355 print "\33[0m"
356 for v in values:
357 for (name,pname,width) in fields:
358 width = max(len(name),width)
359 print " %s" % str(v[name]).ljust(width),
360 print
361