1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
|
7
|
|
8
|
|
9
|
|
10
|
|
11
|
|
12
|
|
13
|
|
14
|
|
15
|
|
16
|
|
17
|
|
18
|
|
19
|
"""Haizea uses a policy manager that allows certain scheduling decisions to
|
20
|
be delegated to pluggable policies. This is done so scheduling policies
|
21
|
can be (1) modified without having to modify core components of Haizea, and
|
22
|
(2) implemented by writing a single Python class that implements a given
|
23
|
interface for pluggable policies.
|
24
|
|
25
|
Three policies are currently pluggable: lease preemptability ("Can lease X
|
26
|
preempt lease Y?"), host selection ("I want to deploy a VM, what host should
|
27
|
I select for this?") and lease admission ("Should I accept/reject this lease
|
28
|
request?"). Haizea provides several simple policy modules in the
|
29
|
haizea.policies package. The policy to use is selected in the configuration
|
30
|
file. See the Haizea Documentation for more details on how this is done.
|
31
|
|
32
|
This module provides Haizea's policy manager and the base classes for
|
33
|
pluggable policies.
|
34
|
"""
|
35
|
|
36
|
|
37
|
from haizea.common.utils import abstract
|
38
|
from haizea.core.leases import Lease
|
39
|
from mx.DateTime import DateTimeDelta
|
40
|
import operator
|
41
|
|
42
|
class PolicyManager(object):
|
43
|
"""The Policy Manager
|
44
|
|
45
|
This class manages the policy modules and provides methods to
|
46
|
access these modules.
|
47
|
|
48
|
"""
|
49
|
def __init__(self, admission, preemption, host_selection):
|
50
|
"""Constructor
|
51
|
|
52
|
Expects fully-constructed policies (these are currently
|
53
|
loaded in the Manager class, based on the config file).
|
54
|
|
55
|
Arguments:
|
56
|
admission -- A child of LeaseAdmissionPolicy
|
57
|
preemption -- A child of PreemptabilityPolicy
|
58
|
host_selection -- A child of HostSelectionPolicy
|
59
|
|
60
|
"""
|
61
|
self.admission = admission
|
62
|
self.preemption = preemption
|
63
|
self.host_selection = host_selection
|
64
|
|
65
|
def sort_leases(self, preemptor, preemptees, time):
|
66
|
"""Sorts a list of leases by their preemptability
|
67
|
|
68
|
Takes a list of leases (the "preemptees"), determines their preemptability
|
69
|
by another lease (the "preemptor"), and returns a list with the
|
70
|
leases sorted by decreasing preemptability score (most preemptable
|
71
|
leases first)
|
72
|
|
73
|
See documentation of PreemptabilityPolicy.get_lease_preemptability_score
|
74
|
for more details on the preemptability score.
|
75
|
|
76
|
Argument
|
77
|
preemptor -- Preemptor lease
|
78
|
preemptees -- List of preemptee leases
|
79
|
time -- Time at which preemption would take place
|
80
|
"""
|
81
|
leases_score = [(preemptee, self.get_lease_preemptability_score(preemptor,preemptee, time)) for preemptee in preemptees]
|
82
|
leases_score = [(preemptee,score) for preemptee,score in leases_score if score != -1]
|
83
|
leases_score.sort(key=operator.itemgetter(1), reverse=True)
|
84
|
return [preemptee for preemptee,score in leases_score]
|
85
|
|
86
|
|
87
|
def sort_hosts(self, nodes, time, lease):
|
88
|
"""Sorts a list of hosts by their score
|
89
|
|
90
|
Takes a list of hosts, determines their score, and sorts them in
|
91
|
order of decreasing score (most desireable hosts first)
|
92
|
|
93
|
See documentation of HostSelectionPolicy.get_host_score for more details.
|
94
|
|
95
|
Arguments:
|
96
|
nodes -- List of physical node (the integer identifier used in the slot table)
|
97
|
time -- Time at which the lease might be scheduled
|
98
|
lease -- Lease that is being scheduled.
|
99
|
"""
|
100
|
nodes_score = [(node, self.get_host_score(node, time, lease)) for node in nodes]
|
101
|
nodes_score.sort(key=operator.itemgetter(1), reverse=True)
|
102
|
return [node for node,score in nodes_score]
|
103
|
|
104
|
|
105
|
def accept_lease(self, lease):
|
106
|
"""Lease admission function
|
107
|
|
108
|
Returns True if the lease can be accepted, False if it should be rejected.
|
109
|
|
110
|
Argument
|
111
|
lease -- Lease request
|
112
|
"""
|
113
|
return self.admission.accept_lease(lease)
|
114
|
|
115
|
|
116
|
def get_lease_preemptability_score(self, preemptor, preemptee, time):
|
117
|
"""Computes the lease preemptability score
|
118
|
|
119
|
See documentation of PreemptabilityPolicy.get_lease_preemptability_score
|
120
|
for more details.
|
121
|
|
122
|
Arguments:
|
123
|
preemptor -- Preemptor lease
|
124
|
preemptee -- Preemptee lease
|
125
|
time -- Time at which preemption would take place
|
126
|
"""
|
127
|
return self.preemption.get_lease_preemptability_score(preemptor, preemptee, time)
|
128
|
|
129
|
|
130
|
def get_host_score(self, node, time, lease):
|
131
|
"""Computes the score of a host
|
132
|
|
133
|
See documentation of HostSelectionPolicy.get_host_score for more details.
|
134
|
|
135
|
Arguments:
|
136
|
node -- Physical node (the integer identifier used in the slot table)
|
137
|
time -- Time at which the lease might be scheduled
|
138
|
lease -- Lease that is being scheduled.
|
139
|
"""
|
140
|
return self.host_selection.get_host_score(node, time, lease)
|
141
|
|
142
|
|
143
|
|
144
|
class LeaseAdmissionPolicy(object):
|
145
|
"""Lease Admission policy
|
146
|
|
147
|
This is the parent class of lease admission policies. A lease admission
|
148
|
policy determines whether a given lease request should be accepted or not
|
149
|
by Haizea. Note that this is distinct from whether the lease can be
|
150
|
scheduled or not (although this could certainly be a part of the
|
151
|
policy); the policy simply decides whether the lease can be considered for
|
152
|
scheduling or not. For example, a user could submit an AR lease that must
|
153
|
start in 5 hours, but the policy could dictate that all ARs must be notified
|
154
|
at least 24 hours in advance (and the lease would be rejected, regardless of
|
155
|
whether there was resources available for it in 5 hours). Similarly, an
|
156
|
AR lease could be requested 48 hours in advance, be accepted by the lease
|
157
|
admission policy, but then be rejected by the scheduler if there are no
|
158
|
resources available.
|
159
|
|
160
|
"""
|
161
|
def __init__(self, slottable):
|
162
|
"""Constructor
|
163
|
|
164
|
Argument
|
165
|
slottable -- A fully constructed SlotTable
|
166
|
"""
|
167
|
self.slottable = slottable
|
168
|
|
169
|
|
170
|
def accept_lease(self, lease):
|
171
|
"""Lease admission function
|
172
|
|
173
|
Returns True if the lease can be accepted, False if it should be rejected.
|
174
|
|
175
|
Argument
|
176
|
lease -- Lease request
|
177
|
"""
|
178
|
abstract()
|
179
|
|
180
|
|
181
|
|
182
|
class PreemptabilityPolicy(object):
|
183
|
"""Lease Preemptability policy
|
184
|
|
185
|
This is the parent class of lease preemptability policies. This type of
|
186
|
policy is used to determine whether a lease can be preempted by another
|
187
|
lease at a given time. However, the policy doesn't return True or False but,
|
188
|
rather, a "preemptability score" (see get_lease_preemptability_score for
|
189
|
more details)
|
190
|
|
191
|
"""
|
192
|
def __init__(self, slottable):
|
193
|
"""Constructor
|
194
|
|
195
|
Argument
|
196
|
slottable -- A fully constructed SlotTable
|
197
|
"""
|
198
|
self.slottable = slottable
|
199
|
|
200
|
|
201
|
def get_lease_preemptability_score(self, preemptor, preemptee, time):
|
202
|
"""Computes the lease preemptability score
|
203
|
|
204
|
Given a lease that needs to preempt resources (the "preemptor"),
|
205
|
another lease (the "preemptee") that may be preempted by it, and a time,
|
206
|
this method determines the preemptability score of the preemptee or
|
207
|
"how preemptable is the preemptee by the preemptor at the given time".
|
208
|
The score can be the following:
|
209
|
|
210
|
-1 : Cannot be preempted under any circumstances
|
211
|
0.0 <= x <= 1.0: Lease can be preempted. The higher the score,
|
212
|
the "more preemptable" it is (this is a relative measure; the score
|
213
|
should be used to determine which of several leases is a better
|
214
|
candidate for preemption)
|
215
|
|
216
|
Arguments:
|
217
|
preemptor -- Preemptor lease
|
218
|
preemptee -- Preemptee lease
|
219
|
time -- Time at which preemption would take place
|
220
|
"""
|
221
|
abstract()
|
222
|
|
223
|
|
224
|
def _get_aging_factor(self, lease, time):
|
225
|
"""Returns an aging factor for the preemptability score
|
226
|
|
227
|
This is a convenience function that can be used to "age" a
|
228
|
preemptability score (allowing leases that have been submitted
|
229
|
long ago to avoid preemption). The method returns a factor
|
230
|
between 0 and 1 that can be multiplied by the score, reducing
|
231
|
the score based on the lease's "age".
|
232
|
|
233
|
Currently, this method uses a hard-coded horizon of 31 days
|
234
|
(any lease older than 7 days cannot be preempted, and leases
|
235
|
less than 7 days are assigned a factor proportional to their age)
|
236
|
|
237
|
Arguments:
|
238
|
lease -- Lease that is going to be preempted
|
239
|
time -- Time at which preemption would take place
|
240
|
"""
|
241
|
|
242
|
horizon = time - DateTimeDelta(7)
|
243
|
if lease.submit_time <= horizon:
|
244
|
return -1
|
245
|
else:
|
246
|
seconds = (time - lease.submit_time).seconds
|
247
|
horizon_seconds = DateTimeDelta(31).seconds
|
248
|
return float(horizon_seconds - seconds) / horizon_seconds
|
249
|
|
250
|
|
251
|
class HostSelectionPolicy(object):
|
252
|
"""Host Selection policy
|
253
|
|
254
|
This is the parent class of host selection policies. When mapping VMs
|
255
|
to physical hosts, this policy determines what hosts are more desireable.
|
256
|
For example, an energy-saving policy might value hosts that already have
|
257
|
VMs running (to leave as many empty machines as possible, which could then
|
258
|
be turned off), whereas another policy might prefer empty hosts to make
|
259
|
sure that VMs are spread out across nodes.
|
260
|
|
261
|
To do this, the policy will assign a score to each host. See the documentation
|
262
|
for get_host_score for more details.
|
263
|
|
264
|
"""
|
265
|
def __init__(self, slottable):
|
266
|
"""Constructor
|
267
|
|
268
|
Argument
|
269
|
slottable -- A fully constructed SlotTable
|
270
|
"""
|
271
|
self.slottable = slottable
|
272
|
|
273
|
|
274
|
def get_host_score(self, node, time, lease):
|
275
|
"""Computes the score of a host
|
276
|
|
277
|
Given a physical host, a time, and a lease we would like to
|
278
|
schedule at that time, this method returns a score indicating
|
279
|
how desireable that host is for that lease at that time.
|
280
|
The score can be between 0.0 and 1.0. The higher the score,
|
281
|
the "more desireable" the physical host is (this is a relative measure;
|
282
|
the score should be used to determine which of several physical hosts
|
283
|
is more desireable for this lease).
|
284
|
|
285
|
Arguments:
|
286
|
node -- Physical node (the integer identifier used in the slot table)
|
287
|
time -- Time at which the lease might be scheduled
|
288
|
lease -- Lease that is being scheduled.
|
289
|
"""
|
290
|
abstract()
|