1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
|
7
|
|
8
|
|
9
|
|
10
|
|
11
|
|
12
|
|
13
|
|
14
|
|
15
|
|
16
|
|
17
|
|
18
|
|
19
|
from haizea.common.config import ConfigException, Section, Option, Config, OPTTYPE_INT, OPTTYPE_FLOAT, OPTTYPE_STRING, OPTTYPE_BOOLEAN, OPTTYPE_DATETIME, OPTTYPE_TIMEDELTA
|
20
|
from haizea.common.utils import generate_config_name
|
21
|
import haizea.common.constants as constants
|
22
|
import haizea.common.defaults as defaults
|
23
|
import sys
|
24
|
from mx.DateTime import TimeDelta
|
25
|
import ConfigParser
|
26
|
|
27
|
try:
|
28
|
import xml.etree.ElementTree as ET
|
29
|
except ImportError:
|
30
|
|
31
|
import elementtree.ElementTree as ET
|
32
|
|
33
|
class HaizeaConfig(Config):
|
34
|
|
35
|
sections = []
|
36
|
|
37
|
|
38
|
|
39
|
|
40
|
|
41
|
|
42
|
|
43
|
general = Section("general", required=True,
|
44
|
doc = "This section is used for general options affecting Haizea as a whole.")
|
45
|
general.options = \
|
46
|
[
|
47
|
Option(name = "loglevel",
|
48
|
getter = "loglevel",
|
49
|
type = OPTTYPE_STRING,
|
50
|
required = False,
|
51
|
default = "INFO",
|
52
|
valid = ["STATUS","INFO","DEBUG","VDEBUG"],
|
53
|
doc = """
|
54
|
Controls the level (and amount) of
|
55
|
log messages. Valid values are:
|
56
|
|
57
|
- STATUS: Only print status messages
|
58
|
- INFO: Slightly more verbose that STATUS
|
59
|
- DEBUG: Prints information useful for debugging the scheduler.
|
60
|
- VDEBUG: Prints very verbose information
|
61
|
on the scheduler's internal data structures. Use only
|
62
|
for short runs.
|
63
|
"""),
|
64
|
|
65
|
Option(name = "logfile",
|
66
|
getter = "logfile",
|
67
|
type = OPTTYPE_STRING,
|
68
|
required = False,
|
69
|
default = "/var/tmp/haizea.log",
|
70
|
doc = """
|
71
|
When running Haizea as a daemon, this option specifies the file
|
72
|
that log messages should be written to.
|
73
|
"""),
|
74
|
|
75
|
Option(name = "mode",
|
76
|
getter = "mode",
|
77
|
type = OPTTYPE_STRING,
|
78
|
required = True,
|
79
|
valid = ["simulated","opennebula"],
|
80
|
doc = """
|
81
|
Sets the mode the scheduler will run in.
|
82
|
Currently the only valid values are "simulated" and
|
83
|
"opennebula". The "simulated" mode expects lease
|
84
|
requests to be provided through a trace file, and
|
85
|
all enactment is simulated. The "opennebula" mode
|
86
|
interacts with the OpenNebula virtual infrastructure
|
87
|
manager (http://www.opennebula.org/) to obtain lease
|
88
|
requests and to do enactment on physical resources.
|
89
|
"""),
|
90
|
|
91
|
Option(name = "lease-preparation",
|
92
|
getter = "lease-preparation",
|
93
|
type = OPTTYPE_STRING,
|
94
|
required = False,
|
95
|
default = constants.PREPARATION_UNMANAGED,
|
96
|
valid = [constants.PREPARATION_UNMANAGED,
|
97
|
constants.PREPARATION_TRANSFER],
|
98
|
doc = """
|
99
|
Sets how the scheduler will handle the
|
100
|
preparation overhead of leases. Valid values are:
|
101
|
|
102
|
- unmanaged: The scheduler can assume that there
|
103
|
is no deployment overhead, or that some
|
104
|
other entity is taking care of it (e.g., one
|
105
|
of the enactment backends)
|
106
|
- imagetransfer: A disk image has to be transferred
|
107
|
from a repository node before the lease can start.
|
108
|
"""),
|
109
|
|
110
|
Option(name = "lease-failure-handling",
|
111
|
getter = "lease-failure-handling",
|
112
|
type = OPTTYPE_STRING,
|
113
|
required = False,
|
114
|
default = constants.ONFAILURE_CANCEL,
|
115
|
valid = [constants.ONFAILURE_CANCEL,
|
116
|
constants.ONFAILURE_EXIT,
|
117
|
constants.ONFAILURE_EXIT_RAISE],
|
118
|
doc = """
|
119
|
Sets how the scheduler will handle a failure in
|
120
|
a lease. Valid values are:
|
121
|
|
122
|
- cancel: The lease is cancelled and marked as "FAILED"
|
123
|
- exit: Haizea will exit cleanly, printing relevant debugging
|
124
|
information to its log.
|
125
|
- exit-raise: Haizea will exit by raising an exception. This is
|
126
|
useful for debugging, as IDEs will recognize this as an exception
|
127
|
and will facilitate debugging it.
|
128
|
"""),
|
129
|
|
130
|
Option(name = "persistence-file",
|
131
|
getter = "persistence-file",
|
132
|
type = OPTTYPE_STRING,
|
133
|
required = False,
|
134
|
default = defaults.PERSISTENCE_LOCATION,
|
135
|
doc = """
|
136
|
This is the file where lease information, along with some
|
137
|
additional scheduling information, is persisted to. If set
|
138
|
to "none", no information will be persisted to disk, and
|
139
|
Haizea will run entirely in-memory (this is advisable
|
140
|
when running in simulation, as persisting to disk adds
|
141
|
considerable overhead, compared to running in-memory).
|
142
|
""")
|
143
|
|
144
|
]
|
145
|
|
146
|
sections.append(general)
|
147
|
|
148
|
|
149
|
|
150
|
|
151
|
|
152
|
|
153
|
|
154
|
scheduling = Section("scheduling", required=True,
|
155
|
doc = "The options in this section control how Haizea schedules leases.")
|
156
|
scheduling.options = \
|
157
|
[
|
158
|
Option(name = "mapper",
|
159
|
getter = "mapper",
|
160
|
type = OPTTYPE_STRING,
|
161
|
required = False,
|
162
|
default = "greedy",
|
163
|
doc = """
|
164
|
VM-to-physical node mapping algorithm used by Haizea. There is currently
|
165
|
only one mapper available (the greedy mapper).
|
166
|
"""),
|
167
|
|
168
|
Option(name = "policy-admission",
|
169
|
getter = "policy.admission",
|
170
|
type = OPTTYPE_STRING,
|
171
|
required = False,
|
172
|
default = "accept-all",
|
173
|
doc = """
|
174
|
Lease admission policy. This controls what leases are accepted by Haizea.
|
175
|
Take into account that this decision takes place before Haizea even
|
176
|
attempts to schedule the lease (so, you can think of lease admission as
|
177
|
"eligibility to be scheduled").
|
178
|
|
179
|
There are two built-in policies:
|
180
|
|
181
|
- accept-all: Accept all leases.
|
182
|
- no-ARs: Accept all leases except advance reservations.
|
183
|
|
184
|
See the Haizea documentation for details on how to write your own
|
185
|
policies.
|
186
|
"""),
|
187
|
|
188
|
Option(name = "policy-preemption",
|
189
|
getter = "policy.preemption",
|
190
|
type = OPTTYPE_STRING,
|
191
|
required = False,
|
192
|
default = "no-preemption",
|
193
|
doc = """
|
194
|
Lease preemption policy. Determines what leases can be preempted. There
|
195
|
are two built-in policies:
|
196
|
|
197
|
- no-preemption: Do not allow any preemptions
|
198
|
- ar-preempts-everything: Allow all ARs to preempt other leases.
|
199
|
|
200
|
See the Haizea documentation for details on how to write your own
|
201
|
policies.
|
202
|
"""),
|
203
|
|
204
|
Option(name = "policy-host-selection",
|
205
|
getter = "policy.host-selection",
|
206
|
type = OPTTYPE_STRING,
|
207
|
required = False,
|
208
|
default = "greedy",
|
209
|
doc = """
|
210
|
Physical host selection policy. controls how Haizea chooses what physical hosts
|
211
|
to map VMs to. This option is closely related to the mapper options
|
212
|
(if the greedy mapper is used, then the greedy host selection policy
|
213
|
should be used, or unexpected results will happen).
|
214
|
|
215
|
The two built-in policies are:
|
216
|
- no-policy: Choose nodes arbitrarily
|
217
|
- greedy: Apply a greedy policy that tries to minimize the number
|
218
|
of preemptions.
|
219
|
|
220
|
See the Haizea documentation for details on how to write your own
|
221
|
policies.
|
222
|
"""),
|
223
|
|
224
|
Option(name = "policy-pricing",
|
225
|
getter = "policy.pricing",
|
226
|
type = OPTTYPE_STRING,
|
227
|
required = False,
|
228
|
default = "free",
|
229
|
doc = """
|
230
|
...
|
231
|
|
232
|
See the Haizea documentation for details on how to write your own
|
233
|
policies.
|
234
|
"""),
|
235
|
|
236
|
Option(name = "wakeup-interval",
|
237
|
getter = "wakeup-interval",
|
238
|
type = OPTTYPE_TIMEDELTA,
|
239
|
required = False,
|
240
|
default = TimeDelta(seconds=60),
|
241
|
doc = """
|
242
|
Interval at which Haizea will wake up
|
243
|
to manage resources and process pending requests.
|
244
|
This option is not used when using a simulated clock,
|
245
|
since the clock will skip directly to the time where an
|
246
|
event is happening.
|
247
|
"""),
|
248
|
|
249
|
Option(name = "backfilling",
|
250
|
getter = "backfilling",
|
251
|
type = OPTTYPE_STRING,
|
252
|
required = False,
|
253
|
default = None,
|
254
|
valid = [constants.BACKFILLING_OFF,
|
255
|
constants.BACKFILLING_AGGRESSIVE,
|
256
|
constants.BACKFILLING_CONSERVATIVE,
|
257
|
constants.BACKFILLING_INTERMEDIATE],
|
258
|
doc = """
|
259
|
Backfilling algorithm to use. Valid values are:
|
260
|
|
261
|
- off: don't do backfilling
|
262
|
- aggressive: at most 1 reservation in the future
|
263
|
- conservative: unlimited reservations in the future
|
264
|
- intermediate: N reservations in the future (N is specified
|
265
|
in the backfilling-reservations option)
|
266
|
"""),
|
267
|
|
268
|
Option(name = "backfilling-reservations",
|
269
|
getter = "backfilling-reservations",
|
270
|
type = OPTTYPE_INT,
|
271
|
required = False,
|
272
|
required_if = [(("scheduling","backfilling"),constants.BACKFILLING_INTERMEDIATE)],
|
273
|
doc = """
|
274
|
Number of future reservations to allow when
|
275
|
using the "intermediate" backfilling option.
|
276
|
"""),
|
277
|
|
278
|
Option(name = "suspension",
|
279
|
getter = "suspension",
|
280
|
type = OPTTYPE_STRING,
|
281
|
required = True,
|
282
|
valid = [constants.SUSPENSION_NONE,
|
283
|
constants.SUSPENSION_SERIAL,
|
284
|
constants.SUSPENSION_ALL],
|
285
|
doc = """
|
286
|
Specifies what can be suspended. Valid values are:
|
287
|
|
288
|
- none: suspension is never allowed
|
289
|
- serial-only: only 1-node leases can be suspended
|
290
|
- all: any lease can be suspended
|
291
|
"""),
|
292
|
|
293
|
Option(name = "suspend-rate",
|
294
|
getter = "suspend-rate",
|
295
|
type = OPTTYPE_FLOAT,
|
296
|
required = False,
|
297
|
required_if = [(("scheduling","suspension"),constants.SUSPENSION_SERIAL),
|
298
|
(("scheduling","suspension"),constants.SUSPENSION_ALL)],
|
299
|
doc = """
|
300
|
Rate at which VMs are assumed to suspend (in MB of
|
301
|
memory per second)
|
302
|
"""),
|
303
|
|
304
|
Option(name = "resume-rate",
|
305
|
getter = "resume-rate",
|
306
|
type = OPTTYPE_FLOAT,
|
307
|
required = False,
|
308
|
required_if = [(("scheduling","suspension"),constants.SUSPENSION_SERIAL),
|
309
|
(("scheduling","suspension"),constants.SUSPENSION_ALL)],
|
310
|
doc = """
|
311
|
Rate at which VMs are assumed to resume (in MB of
|
312
|
memory per second)
|
313
|
"""),
|
314
|
|
315
|
Option(name = "suspendresume-exclusion",
|
316
|
getter = "suspendresume-exclusion",
|
317
|
type = OPTTYPE_STRING,
|
318
|
required = False,
|
319
|
default = constants.SUSPRES_EXCLUSION_LOCAL,
|
320
|
valid = [constants.SUSPRES_EXCLUSION_LOCAL,
|
321
|
constants.SUSPRES_EXCLUSION_GLOBAL],
|
322
|
doc = """
|
323
|
When suspending or resuming a VM, the VM's memory is dumped to a
|
324
|
file on disk. To correctly estimate the time required to suspend
|
325
|
a lease with multiple VMs, Haizea makes sure that no two
|
326
|
suspensions/resumptions happen at the same time (e.g., if eight
|
327
|
memory files were being saved at the same time to disk, the disk's
|
328
|
performance would be reduced in a way that is not as easy to estimate
|
329
|
as if only one file were being saved at a time).
|
330
|
|
331
|
Depending on whether the files are being saved to/read from a global
|
332
|
or local filesystem, this exclusion can be either global or local.
|
333
|
"""),
|
334
|
|
335
|
Option(name = "scheduling-threshold-factor",
|
336
|
getter = "scheduling-threshold-factor",
|
337
|
type = OPTTYPE_INT,
|
338
|
required = False,
|
339
|
default = 1,
|
340
|
doc = """
|
341
|
To avoid thrashing, Haizea will not schedule a lease unless all overheads
|
342
|
can be correctly scheduled (which includes image transfers, suspensions, etc.).
|
343
|
However, this can still result in situations where a lease is prepared,
|
344
|
and then immediately suspended because of a blocking lease in the future.
|
345
|
The scheduling threshold factor can be used to specify that a lease must
|
346
|
not be scheduled unless it is guaranteed to run for a minimum amount of
|
347
|
time (the rationale behind this is that you ideally don't want leases
|
348
|
to be scheduled if they're not going to be active for at least as much time
|
349
|
as was spent in overheads).
|
350
|
|
351
|
The default value is 1, meaning that the lease will be active for at least
|
352
|
as much time T as was spent on overheads (e.g., if preparing the lease requires
|
353
|
60 seconds, and we know that it will have to be suspended, requiring 30 seconds,
|
354
|
Haizea won't schedule the lease unless it can run for at least 90 minutes).
|
355
|
In other words, a scheduling factor of F required a minimum duration of
|
356
|
F*T. A value of 0 could lead to thrashing, since Haizea could end up with
|
357
|
situations where a lease starts and immediately gets suspended.
|
358
|
"""),
|
359
|
|
360
|
Option(name = "override-suspend-time",
|
361
|
getter = "override-suspend-time",
|
362
|
type = OPTTYPE_INT,
|
363
|
required = False,
|
364
|
default = None,
|
365
|
doc = """
|
366
|
Overrides the time it takes to suspend a VM to a fixed value
|
367
|
(i.e., not computed based on amount of memory, enactment overhead, etc.)
|
368
|
"""),
|
369
|
|
370
|
Option(name = "override-resume-time",
|
371
|
getter = "override-resume-time",
|
372
|
type = OPTTYPE_INT,
|
373
|
required = False,
|
374
|
default = None,
|
375
|
doc = """
|
376
|
Overrides the time it takes to suspend a VM to a fixed value
|
377
|
(i.e., not computed based on amount of memory, enactment overhead, etc.)
|
378
|
"""),
|
379
|
|
380
|
Option(name = "force-scheduling-threshold",
|
381
|
getter = "force-scheduling-threshold",
|
382
|
type = OPTTYPE_TIMEDELTA,
|
383
|
required = False,
|
384
|
doc = """
|
385
|
This option can be used to force a specific scheduling threshold time
|
386
|
to be used, instead of calculating one based on overheads.
|
387
|
"""),
|
388
|
|
389
|
Option(name = "migration",
|
390
|
getter = "migration",
|
391
|
type = OPTTYPE_STRING,
|
392
|
required = False,
|
393
|
default = constants.MIGRATE_NO,
|
394
|
valid = [constants.MIGRATE_NO,
|
395
|
constants.MIGRATE_YES,
|
396
|
constants.MIGRATE_YES_NOTRANSFER],
|
397
|
doc = """
|
398
|
Specifies whether leases can be migrated from one
|
399
|
physical node to another. Valid values are:
|
400
|
|
401
|
- no
|
402
|
- yes
|
403
|
- yes-notransfer: migration is performed without
|
404
|
transferring any files.
|
405
|
"""),
|
406
|
|
407
|
Option(name = "non-schedulable-interval",
|
408
|
getter = "non-schedulable-interval",
|
409
|
type = OPTTYPE_TIMEDELTA,
|
410
|
required = False,
|
411
|
default = TimeDelta(seconds=10),
|
412
|
doc = """
|
413
|
The minimum amount of time that must pass between
|
414
|
when a request is scheduled to when it can actually start.
|
415
|
The default should be good for most configurations, but
|
416
|
may need to be increased if you're dealing with exceptionally
|
417
|
high loads.
|
418
|
"""),
|
419
|
|
420
|
Option(name = "shutdown-time",
|
421
|
getter = "shutdown-time",
|
422
|
type = OPTTYPE_TIMEDELTA,
|
423
|
required = False,
|
424
|
default = TimeDelta(seconds=0),
|
425
|
doc = """
|
426
|
The amount of time that will be allocated for a VM to shutdown.
|
427
|
When running in OpenNebula mode, it is advisable to set this to
|
428
|
a few seconds, so no operation gets scheduled right when a
|
429
|
VM is shutting down. The most common scenario is that a VM
|
430
|
will start resuming right when another VM shuts down. However,
|
431
|
since both these activities involve I/O, it can delay the resume
|
432
|
operation and affect Haizea's estimation of how long the resume
|
433
|
will take.
|
434
|
"""),
|
435
|
|
436
|
Option(name = "enactment-overhead",
|
437
|
getter = "enactment-overhead",
|
438
|
type = OPTTYPE_TIMEDELTA,
|
439
|
required = False,
|
440
|
default = TimeDelta(seconds=0),
|
441
|
doc = """
|
442
|
The amount of time that is required to send
|
443
|
an enactment command. This value will affect suspend/resume
|
444
|
estimations and, in OpenNebula mode, will force a pause
|
445
|
of this much time between suspend/resume enactment
|
446
|
commands. When suspending/resuming many VMs at the same time
|
447
|
(which is likely to happen if suspendresume-exclusion is set
|
448
|
to "local"), it will take OpenNebula 1-2 seconds to process
|
449
|
each command (this is a small amount of time, but if 32 VMs
|
450
|
are being suspended at the same time, on in each physical node,
|
451
|
this time can compound up to 32-64 seconds, which has to be
|
452
|
taken into account when estimating when to start a suspend
|
453
|
operation that must be completed before another lease starts).
|
454
|
""")
|
455
|
|
456
|
]
|
457
|
sections.append(scheduling)
|
458
|
|
459
|
|
460
|
|
461
|
|
462
|
|
463
|
|
464
|
|
465
|
simulation = Section("simulation", required=False,
|
466
|
required_if = [(("general","mode"),"simulated")],
|
467
|
doc = "This section is used to specify options when Haizea runs in simulation" )
|
468
|
simulation.options = \
|
469
|
[
|
470
|
Option(name = "clock",
|
471
|
getter = "clock",
|
472
|
type = OPTTYPE_STRING,
|
473
|
required = False,
|
474
|
default = constants.CLOCK_REAL,
|
475
|
valid = [constants.CLOCK_REAL,
|
476
|
constants.CLOCK_SIMULATED],
|
477
|
doc = """
|
478
|
Type of clock to use in simulation:
|
479
|
|
480
|
- simulated: A simulated clock that fastforwards through
|
481
|
time. Can only use the tracefile request
|
482
|
frontend
|
483
|
- real: A real clock is used, but simulated resources and
|
484
|
enactment actions are used. Can only use the RPC
|
485
|
request frontend.
|
486
|
"""),
|
487
|
|
488
|
Option(name = "starttime",
|
489
|
getter = "starttime",
|
490
|
type = OPTTYPE_DATETIME,
|
491
|
required = False,
|
492
|
required_if = [(("simulation","clock"),constants.CLOCK_SIMULATED)],
|
493
|
doc = """
|
494
|
Time at which simulated clock will start.
|
495
|
"""),
|
496
|
|
497
|
Option(name = "resources",
|
498
|
getter = "simul.resources",
|
499
|
type = OPTTYPE_STRING,
|
500
|
required = True,
|
501
|
doc = """
|
502
|
Simulated resources. This option can take two values,
|
503
|
"in-tracefile" (which means that the description of
|
504
|
the simulated site is in the tracefile) or a string
|
505
|
specifying a site with homogeneous resources.
|
506
|
The format is:
|
507
|
|
508
|
<numnodes> [ <resource_type>:<resource_quantity>]+
|
509
|
|
510
|
For example, "4 CPU:100 Memory:1024" describes a site
|
511
|
with four nodes, each with one CPU and 1024 MB of memory.
|
512
|
"""),
|
513
|
|
514
|
Option(name = "imagetransfer-bandwidth",
|
515
|
getter = "imagetransfer-bandwidth",
|
516
|
type = OPTTYPE_INT,
|
517
|
required = True,
|
518
|
doc = """
|
519
|
Bandwidth (in Mbps) available for image transfers.
|
520
|
This would correspond to the outbound network bandwidth of the
|
521
|
node where the images are stored.
|
522
|
"""),
|
523
|
|
524
|
Option(name = "stop-when",
|
525
|
getter = "stop-when",
|
526
|
type = OPTTYPE_STRING,
|
527
|
required = False,
|
528
|
default = constants.STOPWHEN_ALLDONE,
|
529
|
valid = [constants.STOPWHEN_ALLDONE,
|
530
|
constants.STOPWHEN_BESUBMITTED,
|
531
|
constants.STOPWHEN_BEDONE,
|
532
|
constants.STOPWHEN_EXACT],
|
533
|
doc = """
|
534
|
When using the simulated clock, this specifies when the
|
535
|
simulation must end. Valid options are:
|
536
|
|
537
|
- all-leases-done: All requested leases have been completed
|
538
|
and there are no queued/pending requests.
|
539
|
- besteffort-submitted: When all best-effort leases have been
|
540
|
submitted.
|
541
|
- besteffort-done: When all best-effort leases have been
|
542
|
completed.
|
543
|
- exact: Stop at a specific time (use option stop-when-time)
|
544
|
"""),
|
545
|
|
546
|
Option(name = "stop-when-time",
|
547
|
getter = "stop-when-time",
|
548
|
type = OPTTYPE_STRING,
|
549
|
required = False,
|
550
|
required_if = [(("simulation","stop-when"),constants.STOPWHEN_EXACT)],
|
551
|
doc = """
|
552
|
A time in format DD:HH:MM:SS at which the simulation should be
|
553
|
stopped (useful for debugging)
|
554
|
"""),
|
555
|
|
556
|
Option(name = "status-message-interval",
|
557
|
getter = "status-message-interval",
|
558
|
type = OPTTYPE_INT,
|
559
|
required = False,
|
560
|
default = None,
|
561
|
doc = """
|
562
|
If specified, the simulated clock will print a status
|
563
|
message with some basic statistics. This is useful to keep track
|
564
|
of long simulations. The interval is specified in minutes.
|
565
|
"""),
|
566
|
|
567
|
Option(name = "sanity-check",
|
568
|
getter = "sanity-check",
|
569
|
type = OPTTYPE_BOOLEAN,
|
570
|
required = False,
|
571
|
default = False,
|
572
|
doc = """
|
573
|
Perform a sanity check at every timestep (only for debugging)
|
574
|
"""),
|
575
|
|
576
|
]
|
577
|
sections.append(simulation)
|
578
|
|
579
|
|
580
|
|
581
|
|
582
|
|
583
|
|
584
|
|
585
|
|
586
|
accounting = Section("accounting", required=True,
|
587
|
doc = "Haizea can collect information while running, and save that information to a file for off-line processing. This section includes options controlling this feature.")
|
588
|
|
589
|
accounting.options = \
|
590
|
[
|
591
|
Option(name = "datafile",
|
592
|
getter = "datafile",
|
593
|
type = OPTTYPE_STRING,
|
594
|
required = False,
|
595
|
default = None,
|
596
|
doc = """
|
597
|
This is the file where statistics on
|
598
|
the scheduler's run will be saved to (waiting time of leases,
|
599
|
utilization data, etc.). If omitted, no data will be saved.
|
600
|
"""),
|
601
|
|
602
|
Option(name = "probes",
|
603
|
getter = "accounting-probes",
|
604
|
type = OPTTYPE_STRING,
|
605
|
required = False,
|
606
|
doc = """
|
607
|
Accounting probes.
|
608
|
|
609
|
There are four built-in probes:
|
610
|
|
611
|
- AR: Collects information on AR leases.
|
612
|
- best-effort: Collects information on best effort leases.
|
613
|
- immediate: Collects information immediate leases.
|
614
|
- utilization: Collects information on resource utilization.
|
615
|
|
616
|
See the Haizea documentation for details on how to write your
|
617
|
own accounting probes.
|
618
|
|
619
|
"""),
|
620
|
|
621
|
Option(name = "attributes",
|
622
|
getter = "attributes",
|
623
|
type = OPTTYPE_STRING,
|
624
|
required = False,
|
625
|
doc = """
|
626
|
This option is used internally by Haizea when using
|
627
|
multiconfiguration files. See the multiconfiguration
|
628
|
documentation for more details.
|
629
|
""")
|
630
|
]
|
631
|
|
632
|
sections.append(accounting)
|
633
|
|
634
|
|
635
|
|
636
|
|
637
|
|
638
|
|
639
|
|
640
|
|
641
|
imgtransfer = Section("deploy-imagetransfer", required=False,
|
642
|
required_if = [(("general","lease-deployment"),"imagetransfer")],
|
643
|
doc = """
|
644
|
When lease deployment with disk image transfers is selected,
|
645
|
this section is used to control image deployment parameters.""")
|
646
|
imgtransfer.options = \
|
647
|
[
|
648
|
Option(name = "transfer-mechanism",
|
649
|
getter = "transfer-mechanism",
|
650
|
type = OPTTYPE_STRING,
|
651
|
required = True,
|
652
|
valid = [constants.TRANSFER_UNICAST,
|
653
|
constants.TRANSFER_MULTICAST],
|
654
|
doc = """
|
655
|
Specifies how disk images are transferred. Valid values are:
|
656
|
|
657
|
- unicast: A disk image can be transferred to just one node at a time
|
658
|
- multicast: A disk image can be multicast to multiple nodes at
|
659
|
the same time.
|
660
|
"""),
|
661
|
|
662
|
Option(name = "avoid-redundant-transfers",
|
663
|
getter = "avoid-redundant-transfers",
|
664
|
type = OPTTYPE_BOOLEAN,
|
665
|
required = False,
|
666
|
default = True,
|
667
|
doc = """
|
668
|
Specifies whether the scheduler should take steps to
|
669
|
detect and avoid redundant transfers (e.g., if two leases are
|
670
|
scheduled on the same node, and they both require the same disk
|
671
|
image, don't transfer the image twice; allow one to "piggyback"
|
672
|
on the other). There is generally no reason to set this option
|
673
|
to False.
|
674
|
"""),
|
675
|
|
676
|
Option(name = "force-imagetransfer-time",
|
677
|
getter = "force-imagetransfer-time",
|
678
|
type = OPTTYPE_TIMEDELTA,
|
679
|
required = False,
|
680
|
doc = """
|
681
|
Forces the image transfer time to a specific amount.
|
682
|
This options is intended for testing purposes.
|
683
|
"""),
|
684
|
|
685
|
Option(name = "diskimage-reuse",
|
686
|
getter = "diskimage-reuse",
|
687
|
type = OPTTYPE_STRING,
|
688
|
required = False,
|
689
|
required_if = None,
|
690
|
default = constants.REUSE_NONE,
|
691
|
valid = [constants.REUSE_NONE,
|
692
|
constants.REUSE_IMAGECACHES],
|
693
|
doc = """
|
694
|
Specifies whether disk image caches should be created
|
695
|
on the nodes, so the scheduler can reduce the number of transfers
|
696
|
by reusing images. Valid values are:
|
697
|
|
698
|
- none: No image reuse
|
699
|
- image-caches: Use image caching algorithm described in Haizea
|
700
|
publications
|
701
|
"""),
|
702
|
|
703
|
Option(name = "diskimage-cache-size",
|
704
|
getter = "diskimage-cache-size",
|
705
|
type = OPTTYPE_INT,
|
706
|
required = False,
|
707
|
required_if = [(("deploy-imagetransfer","diskimage-reuse"),True)],
|
708
|
doc = """
|
709
|
Specifies the size (in MB) of the disk image cache on
|
710
|
each physical node.
|
711
|
""")
|
712
|
]
|
713
|
sections.append(imgtransfer)
|
714
|
|
715
|
|
716
|
|
717
|
|
718
|
|
719
|
|
720
|
|
721
|
tracefile = Section("tracefile", required=False,
|
722
|
doc="""
|
723
|
When reading in requests from a tracefile, this section is used
|
724
|
to specify the tracefile and other parameters.""")
|
725
|
tracefile.options = \
|
726
|
[
|
727
|
Option(name = "tracefile",
|
728
|
getter = "tracefile",
|
729
|
type = OPTTYPE_STRING,
|
730
|
required = True,
|
731
|
doc = """
|
732
|
Path to tracefile to use.
|
733
|
"""),
|
734
|
|
735
|
Option(name = "annotationfile",
|
736
|
getter = "annotationfile",
|
737
|
type = OPTTYPE_STRING,
|
738
|
required = False,
|
739
|
doc = """
|
740
|
Path to lease annotation file.
|
741
|
"""),
|
742
|
|
743
|
Option(name = "injectionfile",
|
744
|
getter = "injectionfile",
|
745
|
type = OPTTYPE_STRING,
|
746
|
required = False,
|
747
|
doc = """
|
748
|
Path to file with leases to "inject" into the tracefile.
|
749
|
"""),
|
750
|
|
751
|
Option(name = "runtime-slowdown-overhead",
|
752
|
getter = "runtime-slowdown-overhead",
|
753
|
type = OPTTYPE_FLOAT,
|
754
|
required = False,
|
755
|
default = 0,
|
756
|
doc = """
|
757
|
Adds a runtime overhead (in %) to the lease duration.
|
758
|
"""),
|
759
|
|
760
|
Option(name = "add-overhead",
|
761
|
getter = "add-overhead",
|
762
|
type = OPTTYPE_STRING,
|
763
|
required = False,
|
764
|
default = constants.RUNTIMEOVERHEAD_NONE,
|
765
|
valid = [constants.RUNTIMEOVERHEAD_NONE,
|
766
|
constants.RUNTIMEOVERHEAD_ALL,
|
767
|
constants.RUNTIMEOVERHEAD_BE],
|
768
|
doc = """
|
769
|
Specifies what leases will have a runtime overhead added:
|
770
|
|
771
|
- none: No runtime overhead must be added.
|
772
|
- besteffort: Add only to best-effort leases
|
773
|
- all: Add runtime overhead to all leases
|
774
|
"""),
|
775
|
|
776
|
Option(name = "bootshutdown-overhead",
|
777
|
getter = "bootshutdown-overhead",
|
778
|
type = OPTTYPE_TIMEDELTA,
|
779
|
required = False,
|
780
|
default = TimeDelta(seconds=0),
|
781
|
doc = """
|
782
|
Specifies how many seconds will be alloted to
|
783
|
boot and shutdown of the lease.
|
784
|
"""),
|
785
|
|
786
|
Option(name = "override-memory",
|
787
|
getter = "override-memory",
|
788
|
type = OPTTYPE_INT,
|
789
|
required = False,
|
790
|
default = constants.NO_MEMORY_OVERRIDE,
|
791
|
doc = """
|
792
|
Overrides memory requirements specified in tracefile.
|
793
|
"""),
|
794
|
]
|
795
|
sections.append(tracefile)
|
796
|
|
797
|
|
798
|
|
799
|
|
800
|
|
801
|
|
802
|
|
803
|
opennebula = Section("opennebula", required=False,
|
804
|
required_if = [(("general","mode"),"opennebula")],
|
805
|
doc = """
|
806
|
This section is used to specify OpenNebula parameters,
|
807
|
necessary when using Haizea as an OpenNebula scheduling backend.""")
|
808
|
opennebula.options = \
|
809
|
[
|
810
|
Option(name = "host",
|
811
|
getter = "one.host",
|
812
|
type = OPTTYPE_STRING,
|
813
|
required = True,
|
814
|
doc = """
|
815
|
Host where OpenNebula is running.
|
816
|
Typically, OpenNebula and Haizea will be installed
|
817
|
on the same host, so the following option should be
|
818
|
set to 'localhost'. If they're on different hosts,
|
819
|
make sure you modify this option accordingly.
|
820
|
"""),
|
821
|
|
822
|
Option(name = "port",
|
823
|
getter = "one.port",
|
824
|
type = OPTTYPE_INT,
|
825
|
required = False,
|
826
|
default = defaults.OPENNEBULA_RPC_PORT,
|
827
|
doc = """
|
828
|
TCP port of OpenNebula's XML RPC server
|
829
|
"""),
|
830
|
|
831
|
Option(name = "stop-when-no-more-leases",
|
832
|
getter = "stop-when-no-more-leases",
|
833
|
type = OPTTYPE_BOOLEAN,
|
834
|
required = False,
|
835
|
default = False,
|
836
|
doc = """
|
837
|
This option is useful for testing and running experiments.
|
838
|
If set to True, Haizea will stop when there are no more leases
|
839
|
to process (which allows you to tun Haizea and OpenNebula unattended,
|
840
|
and count on it stopping when there are no more leases to process).
|
841
|
For now, this only makes sense if you're seeding Haizea with requests from
|
842
|
the start (otherwise, it will start and immediately stop).
|
843
|
"""),
|
844
|
|
845
|
Option(name = "dry-run",
|
846
|
getter = "dry-run",
|
847
|
type = OPTTYPE_BOOLEAN,
|
848
|
required = False,
|
849
|
default = False,
|
850
|
doc = """
|
851
|
This option is useful for testing.
|
852
|
If set to True, Haizea will fast-forward through time (note that this is
|
853
|
different that using the simulated clock, which has to be used with a tracefile;
|
854
|
with an Haizea/OpenNebula dry run, you will have to seed OpenNebula with requests
|
855
|
before starting Haizea). You will generally want to set stop-when-no-more-leases
|
856
|
when doing a dry-run.
|
857
|
|
858
|
IMPORTANT: Haizea will still send out enactment commands to OpenNebula. Make
|
859
|
sure you replace onevm with a dummy command that does nothing (or that reacts
|
860
|
in some way you want to test; e.g., by emulating a deployment failure, etc.)
|
861
|
"""),
|
862
|
|
863
|
]
|
864
|
sections.append(opennebula)
|
865
|
|
866
|
def __init__(self, config):
|
867
|
Config.__init__(self, config, self.sections)
|
868
|
|
869
|
self.attrs = {}
|
870
|
if self._options["attributes"] != None:
|
871
|
attrs = self._options["attributes"].split(",")
|
872
|
for attr in attrs:
|
873
|
(k,v) = attr.split("=")
|
874
|
self.attrs[k] = v
|
875
|
|
876
|
|
877
|
def get_attr(self, attr):
|
878
|
return self.attrs[attr]
|
879
|
|
880
|
def get_attrs(self):
|
881
|
return self.attrs.keys()
|
882
|
|
883
|
|
884
|
class HaizeaMultiConfig(Config):
|
885
|
|
886
|
MULTI_SEC = "multi"
|
887
|
COMMON_SEC = "common"
|
888
|
TRACEDIR_OPT = "tracedir"
|
889
|
TRACEFILES_OPT = "tracefiles"
|
890
|
ANNOTATIONDIR_OPT = "annotationdir"
|
891
|
ANNOTATIONFILES_OPT = "annotationfiles"
|
892
|
SKIP_NO_ANNOTATION_OPT = "skip-no-annotation"
|
893
|
INJDIR_OPT = "injectiondir"
|
894
|
INJFILES_OPT = "injectionfiles"
|
895
|
SKIP_NO_INJECTION_OPT = "skip-no-injection"
|
896
|
DATADIR_OPT = "datadir"
|
897
|
|
898
|
def __init__(self, config):
|
899
|
|
900
|
Config.__init__(self, config, [])
|
901
|
|
902
|
def get_profiles(self):
|
903
|
sections = set([s.split(":")[0] for s in self.config.sections()])
|
904
|
|
905
|
sections.difference_update([self.COMMON_SEC, self.MULTI_SEC])
|
906
|
return list(sections)
|
907
|
|
908
|
def get_trace_files(self):
|
909
|
dir = self.config.get(self.MULTI_SEC, self.TRACEDIR_OPT)
|
910
|
traces = self.config.get(self.MULTI_SEC, self.TRACEFILES_OPT).split()
|
911
|
return [dir + "/" + t for t in traces]
|
912
|
|
913
|
def get_annotation_files(self):
|
914
|
if not self.config.has_option(self.MULTI_SEC, self.ANNOTATIONDIR_OPT):
|
915
|
return [None]
|
916
|
else:
|
917
|
dir = self.config.get(self.MULTI_SEC, self.ANNOTATIONDIR_OPT)
|
918
|
annot = self.config.get(self.MULTI_SEC, self.ANNOTATIONFILES_OPT).split()
|
919
|
annot = [dir + "/" + t for t in annot]
|
920
|
annot.append(None)
|
921
|
return annot
|
922
|
|
923
|
def get_inject_files(self):
|
924
|
if not self.config.has_option(self.MULTI_SEC, self.INJDIR_OPT):
|
925
|
return [None]
|
926
|
else:
|
927
|
dir = self.config.get(self.MULTI_SEC, self.INJDIR_OPT)
|
928
|
inj = self.config.get(self.MULTI_SEC, self.INJFILES_OPT).split()
|
929
|
inj = [dir + "/" + i for i in inj]
|
930
|
inj.append(None)
|
931
|
return inj
|
932
|
|
933
|
def get_configs(self):
|
934
|
profiles = self.get_profiles()
|
935
|
tracefiles = self.get_trace_files()
|
936
|
annotationfiles = self.get_annotation_files()
|
937
|
injectfiles = self.get_inject_files()
|
938
|
|
939
|
if not self.config.has_option(self.MULTI_SEC, self.SKIP_NO_INJECTION_OPT):
|
940
|
skip_no_injection = False
|
941
|
else:
|
942
|
skip_no_injection = self.config.getboolean(self.MULTI_SEC, self.SKIP_NO_INJECTION_OPT)
|
943
|
|
944
|
if not self.config.has_option(self.MULTI_SEC, self.SKIP_NO_ANNOTATION_OPT):
|
945
|
skip_no_annotation = False
|
946
|
else:
|
947
|
skip_no_annotation = self.config.getboolean(self.MULTI_SEC, self.SKIP_NO_ANNOTATION_OPT)
|
948
|
|
949
|
no_annotations = (annotationfiles == [None])
|
950
|
no_injections = (injectfiles == [None])
|
951
|
|
952
|
configs = []
|
953
|
for profile in profiles:
|
954
|
for tracefile in tracefiles:
|
955
|
for annotationfile in annotationfiles:
|
956
|
for injectfile in injectfiles:
|
957
|
if annotationfile == None and skip_no_annotation:
|
958
|
continue
|
959
|
if injectfile == None and skip_no_injection:
|
960
|
continue
|
961
|
profileconfig = ConfigParser.ConfigParser()
|
962
|
commonsections = [s for s in self.config.sections() if s.startswith("common:")]
|
963
|
profilesections = [s for s in self.config.sections() if s.startswith(profile +":")]
|
964
|
sections = commonsections + profilesections
|
965
|
for s in sections:
|
966
|
s_noprefix = s.split(":")[1]
|
967
|
items = self.config.items(s)
|
968
|
if not profileconfig.has_section(s_noprefix):
|
969
|
profileconfig.add_section(s_noprefix)
|
970
|
for item in items:
|
971
|
profileconfig.set(s_noprefix, item[0], item[1])
|
972
|
|
973
|
|
974
|
if not profileconfig.has_section("tracefile"):
|
975
|
profileconfig.add_section("tracefile")
|
976
|
|
977
|
|
978
|
profileconfig.set("tracefile", "tracefile", tracefile)
|
979
|
|
980
|
|
981
|
if injectfile != None:
|
982
|
profileconfig.set("tracefile", "injectionfile", injectfile)
|
983
|
|
984
|
|
985
|
if annotationfile != None:
|
986
|
profileconfig.set("tracefile", "annotationfile", annotationfile)
|
987
|
|
988
|
|
989
|
datadir = self.config.get(self.MULTI_SEC, self.DATADIR_OPT)
|
990
|
datafilename = generate_config_name(profile, tracefile, annotationfile, injectfile)
|
991
|
datafile = datadir + "/" + datafilename + ".dat"
|
992
|
|
993
|
if not profileconfig.has_section("accounting"):
|
994
|
profileconfig.add_section("accounting")
|
995
|
profileconfig.set("accounting", "datafile", datafile)
|
996
|
|
997
|
|
998
|
attrs = {"profile":profile,"tracefile":tracefile,"injectfile":injectfile,"annotationfile":annotationfile}
|
999
|
|
1000
|
trace_attrs = self.__load_attributes_from_file(tracefile)
|
1001
|
attrs.update(trace_attrs)
|
1002
|
|
1003
|
if injectfile != None:
|
1004
|
inj_attrs = self.__load_attributes_from_file(injectfile)
|
1005
|
attrs.update(inj_attrs)
|
1006
|
|
1007
|
if annotationfile != None:
|
1008
|
annot_attrs = self.__load_attributes_from_file(annotationfile)
|
1009
|
attrs.update(annot_attrs)
|
1010
|
|
1011
|
attrs_str = ",".join(["%s=%s" % (k,v) for (k,v) in attrs.items()])
|
1012
|
if profileconfig.has_option("accounting", "attributes"):
|
1013
|
attrs_str += ",%s" % profileconfig.get("accounting", "attributes")
|
1014
|
profileconfig.set("accounting", "attributes", attrs_str)
|
1015
|
|
1016
|
try:
|
1017
|
c = HaizeaConfig(profileconfig)
|
1018
|
except ConfigException, msg:
|
1019
|
print >> sys.stderr, "Error in configuration file:"
|
1020
|
print >> sys.stderr, msg
|
1021
|
exit(1)
|
1022
|
configs.append(c)
|
1023
|
|
1024
|
return configs
|
1025
|
|
1026
|
def __load_attributes_from_file(self, file):
|
1027
|
attrs = {}
|
1028
|
context = ET.iterparse(file, events=("start", "end"))
|
1029
|
for event, elem in context:
|
1030
|
if event == "start" and elem.tag in ("lease-annotation", "lease-request"):
|
1031
|
break
|
1032
|
if event == "end" and elem.tag == "attributes":
|
1033
|
for attr_elem in elem:
|
1034
|
attrs[attr_elem.get("name")] = attr_elem.get("value")
|
1035
|
break
|
1036
|
return attrs
|
1037
|
|