Project

General

Profile

root / branches / 1.1 / src / haizea / core / configfile.py @ 841

1
# -------------------------------------------------------------------------- #
2
# Copyright 2006-2009, University of Chicago                                 #
3
# Copyright 2008-2009, Distributed Systems Architecture Group, Universidad   #
4
# Complutense de Madrid (dsa-research.org)                                   #
5
#                                                                            #
6
# Licensed under the Apache License, Version 2.0 (the "License"); you may    #
7
# not use this file except in compliance with the License. You may obtain    #
8
# a copy of the License at                                                   #
9
#                                                                            #
10
# http://www.apache.org/licenses/LICENSE-2.0                                 #
11
#                                                                            #
12
# Unless required by applicable law or agreed to in writing, software        #
13
# distributed under the License is distributed on an "AS IS" BASIS,          #
14
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
15
# See the License for the specific language governing permissions and        #
16
# limitations under the License.                                             #
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
    # Compatibility with Python <=2.4
31
    import elementtree.ElementTree as ET 
32

    
33
class HaizeaConfig(Config):
34

    
35
    sections = []
36
    
37
    # ============================= #
38
    #                               #
39
    #        GENERAL OPTIONS        #
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
    #      SCHEDULING OPTIONS       #
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    = True,
297
            doc         = """
298
            Rate at which VMs are assumed to suspend (in MB of
299
            memory per second)                
300
            """),
301

    
302
     Option(name        = "resume-rate",
303
            getter      = "resume-rate",
304
            type        = OPTTYPE_FLOAT,
305
            required    = True,
306
            doc         = """
307
            Rate at which VMs are assumed to resume (in MB of
308
            memory per second)                
309
            """),
310

    
311
     Option(name        = "suspendresume-exclusion",
312
            getter      = "suspendresume-exclusion",
313
            type        = OPTTYPE_STRING,
314
            required    = False,
315
            default     = constants.SUSPRES_EXCLUSION_LOCAL,
316
            valid       = [constants.SUSPRES_EXCLUSION_LOCAL,
317
                           constants.SUSPRES_EXCLUSION_GLOBAL],
318
            doc         = """
319
            When suspending or resuming a VM, the VM's memory is dumped to a
320
            file on disk. To correctly estimate the time required to suspend
321
            a lease with multiple VMs, Haizea makes sure that no two 
322
            suspensions/resumptions happen at the same time (e.g., if eight
323
            memory files were being saved at the same time to disk, the disk's
324
            performance would be reduced in a way that is not as easy to estimate
325
            as if only one file were being saved at a time).
326
            
327
            Depending on whether the files are being saved to/read from a global
328
            or local filesystem, this exclusion can be either global or local.                        
329
            """),
330

    
331
     Option(name        = "scheduling-threshold-factor",
332
            getter      = "scheduling-threshold-factor",
333
            type        = OPTTYPE_INT,
334
            required    = False,
335
            default     = 1,
336
            doc         = """
337
            To avoid thrashing, Haizea will not schedule a lease unless all overheads
338
            can be correctly scheduled (which includes image transfers, suspensions, etc.).
339
            However, this can still result in situations where a lease is prepared,
340
            and then immediately suspended because of a blocking lease in the future.
341
            The scheduling threshold factor can be used to specify that a lease must
342
            not be scheduled unless it is guaranteed to run for a minimum amount of
343
            time (the rationale behind this is that you ideally don't want leases
344
            to be scheduled if they're not going to be active for at least as much time
345
            as was spent in overheads).
346
            
347
            The default value is 1, meaning that the lease will be active for at least
348
            as much time T as was spent on overheads (e.g., if preparing the lease requires
349
            60 seconds, and we know that it will have to be suspended, requiring 30 seconds,
350
            Haizea won't schedule the lease unless it can run for at least 90 minutes).
351
            In other words, a scheduling factor of F required a minimum duration of 
352
            F*T. A value of 0 could lead to thrashing, since Haizea could end up with
353
            situations where a lease starts and immediately gets suspended.               
354
            """),
355

    
356
     Option(name        = "override-suspend-time",
357
            getter      = "override-suspend-time",
358
            type        = OPTTYPE_INT,
359
            required    = False,
360
            default     = None,
361
            doc         = """
362
            Overrides the time it takes to suspend a VM to a fixed value
363
            (i.e., not computed based on amount of memory, enactment overhead, etc.)
364
            """),
365

    
366
     Option(name        = "override-resume-time",
367
            getter      = "override-resume-time",
368
            type        = OPTTYPE_INT,
369
            required    = False,
370
            default     = None,
371
            doc         = """
372
            Overrides the time it takes to suspend a VM to a fixed value
373
            (i.e., not computed based on amount of memory, enactment overhead, etc.)
374
            """),
375

    
376
     Option(name        = "force-scheduling-threshold",
377
            getter      = "force-scheduling-threshold",
378
            type        = OPTTYPE_TIMEDELTA,
379
            required    = False,
380
            doc         = """
381
            This option can be used to force a specific scheduling threshold time
382
            to be used, instead of calculating one based on overheads.                
383
            """),
384

    
385
     Option(name        = "migration",
386
            getter      = "migration",
387
            type        = OPTTYPE_STRING,
388
            required    = False,
389
            default     = constants.MIGRATE_NO,          
390
            valid       = [constants.MIGRATE_NO,
391
                           constants.MIGRATE_YES,
392
                           constants.MIGRATE_YES_NOTRANSFER],              
393
            doc         = """
394
            Specifies whether leases can be migrated from one
395
            physical node to another. Valid values are: 
396
            
397
             - no
398
             - yes
399
             - yes-notransfer: migration is performed without
400
               transferring any files. 
401
            """),
402

    
403
     Option(name        = "non-schedulable-interval",
404
            getter      = "non-schedulable-interval",
405
            type        = OPTTYPE_TIMEDELTA,
406
            required    = False,
407
            default     = TimeDelta(seconds=10),
408
            doc         = """
409
            The minimum amount of time that must pass between
410
            when a request is scheduled to when it can actually start.
411
            The default should be good for most configurations, but
412
            may need to be increased if you're dealing with exceptionally
413
            high loads.                
414
            """),
415

    
416
     Option(name        = "shutdown-time",
417
            getter      = "shutdown-time",
418
            type        = OPTTYPE_TIMEDELTA,
419
            required    = False,
420
            default     = TimeDelta(seconds=0),
421
            doc         = """
422
            The amount of time that will be allocated for a VM to shutdown.
423
            When running in OpenNebula mode, it is advisable to set this to
424
            a few seconds, so no operation gets scheduled right when a
425
            VM is shutting down. The most common scenario is that a VM
426
            will start resuming right when another VM shuts down. However,
427
            since both these activities involve I/O, it can delay the resume
428
            operation and affect Haizea's estimation of how long the resume
429
            will take.
430
            """),
431

    
432
     Option(name        = "enactment-overhead",
433
            getter      = "enactment-overhead",
434
            type        = OPTTYPE_TIMEDELTA,
435
            required    = False,
436
            default     = TimeDelta(seconds=0),
437
            doc         = """
438
            The amount of time that is required to send
439
            an enactment command. This value will affect suspend/resume
440
            estimations and, in OpenNebula mode, will force a pause
441
            of this much time between suspend/resume enactment
442
            commands. When suspending/resuming many VMs at the same time
443
            (which is likely to happen if suspendresume-exclusion is set
444
            to "local"), it will take OpenNebula 1-2 seconds to process
445
            each command (this is a small amount of time, but if 32 VMs
446
            are being suspended at the same time, on in each physical node,
447
            this time can compound up to 32-64 seconds, which has to be
448
            taken into account when estimating when to start a suspend
449
            operation that must be completed before another lease starts).
450
            """)
451

    
452
    ]
453
    sections.append(scheduling)
454
    
455
    # ============================= #
456
    #                               #
457
    #      SIMULATION OPTIONS       #
458
    #                               #
459
    # ============================= #
460
    
461
    simulation = Section("simulation", required=False,
462
                         required_if = [(("general","mode"),"simulated")],
463
                         doc = "This section is used to specify options when Haizea runs in simulation" )
464
    simulation.options = \
465
    [
466
     Option(name        = "clock",
467
            getter      = "clock",
468
            type        = OPTTYPE_STRING,
469
            required    = False,
470
            default     = constants.CLOCK_REAL,
471
            valid       = [constants.CLOCK_REAL,
472
                           constants.CLOCK_SIMULATED],
473
            doc         = """
474
            Type of clock to use in simulation:
475
            
476
             - simulated: A simulated clock that fastforwards through
477
               time. Can only use the tracefile request
478
               frontend
479
             - real: A real clock is used, but simulated resources and
480
               enactment actions are used. Can only use the RPC
481
               request frontend.                
482
            """),
483

    
484
     Option(name        = "starttime",
485
            getter      = "starttime",
486
            type        = OPTTYPE_DATETIME,
487
            required    = False,
488
            required_if = [(("simulation","clock"),constants.CLOCK_SIMULATED)],
489
            doc         = """
490
            Time at which simulated clock will start.                
491
            """),             
492

    
493
     Option(name        = "resources",
494
            getter      = "simul.resources",
495
            type        = OPTTYPE_STRING,
496
            required    = True,
497
            doc         = """
498
            Simulated resources. This option can take two values,
499
            "in-tracefile" (which means that the description of
500
            the simulated site is in the tracefile) or a string 
501
            specifying a site with homogeneous resources. 
502
            The format is:
503
        
504
            <numnodes> [ <resource_type>:<resource_quantity>]+
505
        
506
            For example, "4  CPU:100 Memory:1024" describes a site
507
            with four nodes, each with one CPU and 1024 MB of memory.
508
            """),
509

    
510
     Option(name        = "imagetransfer-bandwidth",
511
            getter      = "imagetransfer-bandwidth",
512
            type        = OPTTYPE_INT,
513
            required    = True,
514
            doc         = """
515
            Bandwidth (in Mbps) available for image transfers.
516
            This would correspond to the outbound network bandwidth of the
517
            node where the images are stored.                
518
            """),
519

    
520
     Option(name        = "stop-when",
521
            getter      = "stop-when",
522
            type        = OPTTYPE_STRING,
523
            required    = False,
524
            default     = constants.STOPWHEN_ALLDONE,
525
            valid       = [constants.STOPWHEN_ALLDONE,
526
                           constants.STOPWHEN_BESUBMITTED,
527
                           constants.STOPWHEN_BEDONE,
528
                           constants.STOPWHEN_EXACT],
529
            doc         = """
530
            When using the simulated clock, this specifies when the
531
            simulation must end. Valid options are:
532
            
533
             - all-leases-done: All requested leases have been completed
534
               and there are no queued/pending requests.
535
             - besteffort-submitted: When all best-effort leases have been
536
               submitted.
537
             - besteffort-done: When all best-effort leases have been
538
               completed.    
539
             - exact: Stop at a specific time (use option stop-when-time)            
540
            """),
541

    
542
     Option(name        = "stop-when-time",
543
            getter      = "stop-when-time",
544
            type        = OPTTYPE_STRING,
545
            required    = False,
546
            required_if = [(("simulation","stop-when"),constants.STOPWHEN_EXACT)],
547
            doc         = """
548
            A time in format DD:HH:MM:SS at which the simulation should be
549
            stopped (useful for debugging)            
550
            """),
551

    
552
     Option(name        = "status-message-interval",
553
            getter      = "status-message-interval",
554
            type        = OPTTYPE_INT,
555
            required    = False,
556
            default     = None,
557
            doc         = """
558
            If specified, the simulated clock will print a status
559
            message with some basic statistics. This is useful to keep track
560
            of long simulations. The interval is specified in minutes.                
561
            """),
562

    
563
     Option(name        = "sanity-check",
564
            getter      = "sanity-check",
565
            type        = OPTTYPE_BOOLEAN,
566
            required    = False,
567
            default     = False,
568
            doc         = """
569
            Perform a sanity check at every timestep (only for debugging)
570
            """),     
571

    
572
    ]
573
    sections.append(simulation)
574
    
575

    
576
    # ============================= #
577
    #                               #
578
    #      ACCOUNTING OPTIONS       #
579
    #                               #
580
    # ============================= #
581

    
582
    accounting = Section("accounting", required=True,
583
                      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.")
584

    
585
    accounting.options = \
586
    [
587
     Option(name        = "datafile",
588
            getter      = "datafile",
589
            type        = OPTTYPE_STRING,
590
            required    = False,
591
            default     = None,
592
            doc         = """
593
            This is the file where statistics on
594
            the scheduler's run will be saved to (waiting time of leases,
595
            utilization data, etc.). If omitted, no data will be saved.
596
            """),
597

    
598
     Option(name        = "probes",
599
            getter      = "accounting-probes",
600
            type        = OPTTYPE_STRING,
601
            required    = False,
602
            doc         = """
603
            Accounting probes.
604
            
605
            There are four built-in probes:
606
            
607
             - AR: Collects information on AR leases.
608
             - best-effort: Collects information on best effort leases.
609
             - immediate: Collects information immediate leases.
610
             - utilization: Collects information on resource utilization.
611
             
612
            See the Haizea documentation for details on how to write your
613
            own accounting probes.
614
      
615
            """),
616

    
617
     Option(name        = "attributes",
618
            getter      = "attributes",
619
            type        = OPTTYPE_STRING,
620
            required    = False,
621
            doc         = """
622
            This option is used internally by Haizea when using
623
            multiconfiguration files. See the multiconfiguration
624
            documentation for more details.        
625
            """)
626
    ]
627
    
628
    sections.append(accounting)
629

    
630
    # ============================= #
631
    #                               #
632
    #      DEPLOYMENT OPTIONS       #
633
    #     (w/ image transfers)      #
634
    #                               #
635
    # ============================= #
636

    
637
    imgtransfer = Section("deploy-imagetransfer", required=False,
638
                         required_if = [(("general","lease-deployment"),"imagetransfer")],
639
                         doc = """
640
                         When lease deployment with disk image transfers is selected,
641
                         this section is used to control image deployment parameters.""")
642
    imgtransfer.options = \
643
    [
644
     Option(name        = "transfer-mechanism",
645
            getter      = "transfer-mechanism",
646
            type        = OPTTYPE_STRING,
647
            required    = True,
648
            valid       = [constants.TRANSFER_UNICAST,
649
                           constants.TRANSFER_MULTICAST],
650
            doc         = """
651
            Specifies how disk images are transferred. Valid values are:
652
            
653
             - unicast: A disk image can be transferred to just one node at a time
654
             - multicast: A disk image can be multicast to multiple nodes at 
655
               the same time.                
656
            """),
657

    
658
     Option(name        = "avoid-redundant-transfers",
659
            getter      = "avoid-redundant-transfers",
660
            type        = OPTTYPE_BOOLEAN,
661
            required    = False,
662
            default     = True,
663
            doc         = """
664
            Specifies whether the scheduler should take steps to
665
            detect and avoid redundant transfers (e.g., if two leases are
666
            scheduled on the same node, and they both require the same disk
667
            image, don't transfer the image twice; allow one to "piggyback"
668
            on the other). There is generally no reason to set this option
669
            to False.
670
            """),
671

    
672
     Option(name        = "force-imagetransfer-time",
673
            getter      = "force-imagetransfer-time",
674
            type        = OPTTYPE_TIMEDELTA,
675
            required    = False,
676
            doc         = """
677
            Forces the image transfer time to a specific amount.
678
            This options is intended for testing purposes.                
679
            """),
680
            
681
     Option(name        = "diskimage-reuse",
682
            getter      = "diskimage-reuse",
683
            type        = OPTTYPE_STRING,
684
            required    = False,
685
            required_if = None,
686
            default     = constants.REUSE_NONE,
687
            valid       = [constants.REUSE_NONE,
688
                           constants.REUSE_IMAGECACHES],
689
            doc         = """
690
            Specifies whether disk image caches should be created
691
            on the nodes, so the scheduler can reduce the number of transfers
692
            by reusing images. Valid values are:
693
            
694
             - none: No image reuse
695
             - image-caches: Use image caching algorithm described in Haizea
696
               publications
697
            """),
698

    
699
     Option(name        = "diskimage-cache-size",
700
            getter      = "diskimage-cache-size",
701
            type        = OPTTYPE_INT,
702
            required    = False,
703
            required_if = [(("deploy-imagetransfer","diskimage-reuse"),True)],
704
            doc         = """
705
            Specifies the size (in MB) of the disk image cache on
706
            each physical node.                
707
            """)
708
    ]
709
    sections.append(imgtransfer)
710

    
711
    # ============================= #
712
    #                               #
713
    #      TRACEFILE OPTIONS        #
714
    #                               #
715
    # ============================= #
716

    
717
    tracefile = Section("tracefile", required=False, 
718
                        doc="""
719
                        When reading in requests from a tracefile, this section is used
720
                        to specify the tracefile and other parameters.""")
721
    tracefile.options = \
722
    [
723
     Option(name        = "tracefile",
724
            getter      = "tracefile",
725
            type        = OPTTYPE_STRING,
726
            required    = True,
727
            doc         = """
728
            Path to tracefile to use.                
729
            """),
730

    
731
     Option(name        = "annotationfile",
732
            getter      = "annotationfile",
733
            type        = OPTTYPE_STRING,
734
            required    = False,
735
            doc         = """
736
            Path to lease annotation file.                
737
            """),
738

    
739
     Option(name        = "injectionfile",
740
            getter      = "injectionfile",
741
            type        = OPTTYPE_STRING,
742
            required    = False,
743
            doc         = """
744
            Path to file with leases to "inject" into the tracefile.                
745
            """),      
746
               
747
     Option(name        = "runtime-slowdown-overhead",
748
            getter      = "runtime-slowdown-overhead",
749
            type        = OPTTYPE_FLOAT,
750
            required    = False,
751
            default     = 0,
752
            doc         = """
753
            Adds a runtime overhead (in %) to the lease duration.                
754
            """),
755

    
756
     Option(name        = "add-overhead",
757
            getter      = "add-overhead",
758
            type        = OPTTYPE_STRING,
759
            required    = False,
760
            default     = constants.RUNTIMEOVERHEAD_NONE,
761
            valid       = [constants.RUNTIMEOVERHEAD_NONE,
762
                           constants.RUNTIMEOVERHEAD_ALL,
763
                           constants.RUNTIMEOVERHEAD_BE],
764
            doc         = """
765
            Specifies what leases will have a runtime overhead added:
766
            
767
             - none: No runtime overhead must be added.
768
             - besteffort: Add only to best-effort leases
769
             - all: Add runtime overhead to all leases                
770
            """),
771

    
772
     Option(name        = "bootshutdown-overhead",
773
            getter      = "bootshutdown-overhead",
774
            type        = OPTTYPE_TIMEDELTA,
775
            required    = False,
776
            default     = TimeDelta(seconds=0),
777
            doc         = """
778
            Specifies how many seconds will be alloted to
779
            boot and shutdown of the lease.                
780
            """),
781
                  
782
     Option(name        = "override-memory",
783
            getter      = "override-memory",
784
            type        = OPTTYPE_INT,
785
            required    = False,
786
            default     = constants.NO_MEMORY_OVERRIDE,
787
            doc         = """
788
            Overrides memory requirements specified in tracefile.
789
            """),
790
    ]
791
    sections.append(tracefile)
792
    
793
    # ============================= #
794
    #                               #
795
    #      OPENNEBULA OPTIONS       #
796
    #                               #
797
    # ============================= #
798

    
799
    opennebula = Section("opennebula", required=False,
800
                         required_if = [(("general","mode"),"opennebula")],
801
                         doc = """
802
                         This section is used to specify OpenNebula parameters,
803
                         necessary when using Haizea as an OpenNebula scheduling backend.""")
804
    opennebula.options = \
805
    [
806
     Option(name        = "host",
807
            getter      = "one.host",
808
            type        = OPTTYPE_STRING,
809
            required    = True,
810
            doc         = """
811
            Host where OpenNebula is running.
812
            Typically, OpenNebula and Haizea will be installed
813
            on the same host, so the following option should be
814
            set to 'localhost'. If they're on different hosts,
815
            make sure you modify this option accordingly.             
816
            """),
817

    
818
     Option(name        = "port",
819
            getter      = "one.port",
820
            type        = OPTTYPE_INT,
821
            required    = False,
822
            default     = defaults.OPENNEBULA_RPC_PORT,
823
            doc         = """
824
            TCP port of OpenNebula's XML RPC server             
825
            """),
826
            
827
     Option(name        = "stop-when-no-more-leases",
828
            getter      = "stop-when-no-more-leases",
829
            type        = OPTTYPE_BOOLEAN,
830
            required    = False,
831
            default     = False,
832
            doc         = """
833
            This option is useful for testing and running experiments.
834
            If set to True, Haizea will stop when there are no more leases
835
            to process (which allows you to tun Haizea and OpenNebula unattended,
836
            and count on it stopping when there are no more leases to process).
837
            For now, this only makes sense if you're seeding Haizea with requests from
838
            the start (otherwise, it will start and immediately stop).
839
            """),            
840

    
841
     Option(name        = "dry-run",
842
            getter      = "dry-run",
843
            type        = OPTTYPE_BOOLEAN,
844
            required    = False,
845
            default     = False,
846
            doc         = """
847
            This option is useful for testing.
848
            If set to True, Haizea will fast-forward through time (note that this is
849
            different that using the simulated clock, which has to be used with a tracefile;
850
            with an Haizea/OpenNebula dry run, you will have to seed OpenNebula with requests
851
            before starting Haizea). You will generally want to set stop-when-no-more-leases
852
            when doing a dry-run.
853
            
854
            IMPORTANT: Haizea will still send out enactment commands to OpenNebula. Make
855
            sure you replace onevm with a dummy command that does nothing (or that reacts
856
            in some way you want to test; e.g., by emulating a deployment failure, etc.)
857
            """),            
858

    
859
    ]
860
    sections.append(opennebula)
861
    
862
    def __init__(self, config):
863
        Config.__init__(self, config, self.sections)
864

    
865
        self.attrs = {}
866
        if self._options["attributes"] != None:
867
            attrs = self._options["attributes"].split(",")
868
            for attr in attrs:
869
                (k,v) = attr.split("=")
870
                self.attrs[k] = v
871

    
872
        
873
    def get_attr(self, attr):
874
        return self.attrs[attr]
875
        
876
    def get_attrs(self):
877
        return self.attrs.keys()
878

    
879

    
880
class HaizeaMultiConfig(Config):
881
    
882
    MULTI_SEC = "multi"
883
    COMMON_SEC = "common"
884
    TRACEDIR_OPT = "tracedir"
885
    TRACEFILES_OPT = "tracefiles"
886
    ANNOTATIONDIR_OPT = "annotationdir"
887
    ANNOTATIONFILES_OPT = "annotationfiles"
888
    SKIP_NO_ANNOTATION_OPT = "skip-no-annotation"
889
    INJDIR_OPT = "injectiondir"
890
    INJFILES_OPT = "injectionfiles"
891
    SKIP_NO_INJECTION_OPT = "skip-no-injection"
892
    DATADIR_OPT = "datadir"
893
    
894
    def __init__(self, config):
895
        # TODO: Define "multi" section as a Section object
896
        Config.__init__(self, config, [])
897
        
898
    def get_profiles(self):
899
        sections = set([s.split(":")[0] for s in self.config.sections()])
900
        # Remove multi and common sections
901
        sections.difference_update([self.COMMON_SEC, self.MULTI_SEC])
902
        return list(sections)
903

    
904
    def get_trace_files(self):
905
        dir = self.config.get(self.MULTI_SEC, self.TRACEDIR_OPT)
906
        traces = self.config.get(self.MULTI_SEC, self.TRACEFILES_OPT).split()
907
        return [dir + "/" + t for t in traces]
908

    
909
    def get_annotation_files(self):
910
        if not self.config.has_option(self.MULTI_SEC, self.ANNOTATIONDIR_OPT):
911
            return [None]
912
        else:
913
            dir = self.config.get(self.MULTI_SEC, self.ANNOTATIONDIR_OPT)
914
            annot = self.config.get(self.MULTI_SEC, self.ANNOTATIONFILES_OPT).split()
915
            annot = [dir + "/" + t for t in annot]
916
            annot.append(None)
917
            return annot
918

    
919
    def get_inject_files(self):
920
        if not self.config.has_option(self.MULTI_SEC, self.INJDIR_OPT):
921
            return [None]
922
        else:
923
            dir = self.config.get(self.MULTI_SEC, self.INJDIR_OPT)
924
            inj = self.config.get(self.MULTI_SEC, self.INJFILES_OPT).split()
925
            inj = [dir + "/" + i for i in inj]
926
            inj.append(None)
927
            return inj
928
    
929
    def get_configs(self):
930
        profiles = self.get_profiles()
931
        tracefiles = self.get_trace_files()
932
        annotationfiles = self.get_annotation_files()
933
        injectfiles = self.get_inject_files()
934

    
935
        if not self.config.has_option(self.MULTI_SEC, self.SKIP_NO_INJECTION_OPT):
936
            skip_no_injection = False
937
        else:
938
            skip_no_injection = self.config.getboolean(self.MULTI_SEC, self.SKIP_NO_INJECTION_OPT)
939
            
940
        if not self.config.has_option(self.MULTI_SEC, self.SKIP_NO_ANNOTATION_OPT):
941
            skip_no_annotation = False
942
        else:
943
            skip_no_annotation = self.config.getboolean(self.MULTI_SEC, self.SKIP_NO_ANNOTATION_OPT)
944
        
945
        no_annotations = (annotationfiles == [None])
946
        no_injections = (injectfiles == [None])
947

    
948
        configs = []
949
        for profile in profiles:
950
            for tracefile in tracefiles:
951
                for annotationfile in annotationfiles:
952
                    for injectfile in injectfiles:
953
                        if annotationfile == None and skip_no_annotation:
954
                            continue
955
                        if injectfile == None and skip_no_injection:
956
                            continue
957
                        profileconfig = ConfigParser.ConfigParser()
958
                        commonsections = [s for s in self.config.sections() if s.startswith("common:")]
959
                        profilesections = [s for s in self.config.sections() if s.startswith(profile +":")]
960
                        sections = commonsections + profilesections
961
                        for s in sections:
962
                            s_noprefix = s.split(":")[1]
963
                            items = self.config.items(s)
964
                            if not profileconfig.has_section(s_noprefix):
965
                                profileconfig.add_section(s_noprefix)
966
                            for item in items:
967
                                profileconfig.set(s_noprefix, item[0], item[1])
968
                                
969
                        # The tracefile section may have not been created
970
                        if not profileconfig.has_section("tracefile"):
971
                            profileconfig.add_section("tracefile")
972
    
973
                        # Add tracefile option
974
                        profileconfig.set("tracefile", "tracefile", tracefile)
975
                        
976
                        # Add injected file option
977
                        if injectfile != None:
978
                            profileconfig.set("tracefile", "injectionfile", injectfile)
979
                            
980
                        # Add annotations file option
981
                        if annotationfile != None:
982
                            profileconfig.set("tracefile", "annotationfile", annotationfile)
983
    
984
                        # Add datafile option
985
                        datadir = self.config.get(self.MULTI_SEC, self.DATADIR_OPT)
986
                        datafilename = generate_config_name(profile, tracefile, annotationfile, injectfile)
987
                        datafile = datadir + "/" + datafilename + ".dat"
988
                        # The accounting section may have not been created
989
                        if not profileconfig.has_section("accounting"):
990
                            profileconfig.add_section("accounting")
991
                        profileconfig.set("accounting", "datafile", datafile)
992
                        
993
                        # Set "attributes" option (only used internally)
994
                        attrs = {"profile":profile,"tracefile":tracefile,"injectfile":injectfile,"annotationfile":annotationfile}
995
                        
996
                        trace_attrs = self.__load_attributes_from_file(tracefile)
997
                        attrs.update(trace_attrs)
998
                        
999
                        if injectfile != None:
1000
                            inj_attrs = self.__load_attributes_from_file(injectfile)
1001
                            attrs.update(inj_attrs)
1002

    
1003
                        if annotationfile != None:
1004
                            annot_attrs = self.__load_attributes_from_file(annotationfile)
1005
                            attrs.update(annot_attrs)
1006
                        
1007
                        attrs_str = ",".join(["%s=%s" % (k,v) for (k,v) in attrs.items()])
1008
                        if profileconfig.has_option("accounting", "attributes"):
1009
                            attrs_str += ",%s" % profileconfig.get("accounting", "attributes")
1010
                        profileconfig.set("accounting", "attributes", attrs_str)
1011
    
1012
                        try:
1013
                            c = HaizeaConfig(profileconfig)
1014
                        except ConfigException, msg:
1015
                            print >> sys.stderr, "Error in configuration file:"
1016
                            print >> sys.stderr, msg
1017
                            exit(1)
1018
                        configs.append(c)
1019
        
1020
        return configs
1021
    
1022
    def __load_attributes_from_file(self, file):
1023
        attrs = {}
1024
        context = ET.iterparse(file, events=("start", "end"))
1025
        for event, elem in context:
1026
            if event == "start" and elem.tag in ("lease-annotation", "lease-request"):
1027
                break                
1028
            if event == "end" and elem.tag == "attributes":
1029
                for attr_elem in elem:
1030
                    attrs[attr_elem.get("name")] = attr_elem.get("value")
1031
                break
1032
        return attrs
1033