2 # Author: Peter K. Lee (peter@corenova.com)
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
11 description: Resource Management for Virtualized Infrastructure
12 author: Peter K. Lee <peter@corenova.com>
14 homepage: http://wiki.opnfv.org/promise
15 repository: git://github.com/opnfv/promise.git
31 schema: !yang schema/opnfv-promise.yang
33 # below config provides default parameters
34 # NOTE: uncomment locally for testing with pre-existing data
35 #config: !json config/demo.json
38 access-control-models: !yang schema/access-control-models.yang
39 nfv-infrastructure: !yang schema/nfv-infrastructure.yang
41 # MODULE model active bindings
44 # rebind to be a computed property
45 promise.capacity.total: !coffee/function |
46 (prev) -> @computed (->
48 for k, v of b.capacity when v?
53 .filter (entry) -> entry.active is true
56 # rebind to be a computed property
57 promise.capacity.reserved: !coffee/function |
58 (prev) -> @computed (->
60 for k, v of b.remaining when v?
64 (@parent.get 'reservations')
65 .filter (entry) -> entry.active is true
68 # rebind to be a computed property
69 promise.capacity.usage: !coffee/function |
70 (prev) -> @computed (->
72 for k, v of b.capacity when v?
76 (@parent.get 'allocations')
77 .filter (entry) -> entry.active is true
80 # rebind to be a computed property
81 promise.capacity.available: !coffee/function |
82 (prev) -> @computed (->
84 reserved = @get 'reserved'
86 for k, v of total when v?
87 total[k] -= reserved[k] if reserved[k]?
88 total[k] -= usage[k] if usage[k]?
92 # RPC definitions (INTENT interfaces)
93 rpc: !require spec/promise-intents.coffee
95 # COMPLEX-TYPE model active bindings (controller logic)
99 id: !coffee/function |
100 (prev) -> prev.set 'default', -> @uuid()
104 start: !coffee/function |
105 (prev) -> prev.set 'default', -> (new Date).toJSON()
107 active: !coffee/function |
108 (prev) -> @computed (->
110 start = new Date (@get 'start')
112 when (@get 'end')? then new Date (@get 'end')
114 (@get 'enabled') and (start <= now <= end)
118 end: !coffee/function |
119 (prev) -> prev.set 'default', ->
120 end = (new Date @get 'start')
121 max = @parent.get 'promise.policy.reservation.max-duration'
123 end.setTime (end.getTime() + (max*60*60*1000))
126 allocations: !coffee/function |
127 (prev) -> @computed (->
128 res = (@store.find 'ResourceAllocation', reservation: @id)
129 res.map (x) -> x.get 'id'
132 remaining: !coffee/function |
133 (prev) -> @computed (->
134 total = @get 'capacity'
135 records = @store.find 'ResourceAllocation', id: (@get 'allocations'), active: true
137 usage = entry.get 'capacity'
144 validate: !coffee/function |
145 (prev) -> (value={}, resolve, reject) ->
146 # validate that request contains sufficient data
147 for k, v of value.capacity when v? and !!v
149 if (not hasCapacity) and value.elements.length is 0
150 return reject "unable to validate reservation record without anything being reserved"
151 # time range verifications
153 start = (new Date value.start) if value.start?
154 end = (new Date value.end) if value.end?
155 # if start? and start < now
156 # return reject "requested start time #{value.start} cannot be in the past"
157 if end? and end < now
158 return reject "requested end time #{value.end} cannot be in the past"
159 if start? and end? and start > end
160 retun reject "requested start time must be earlier than end time"
163 update: !coffee/function |
164 (prev) -> (req, resolve, reject) ->
165 req.start ?= @get 'start'
166 req.end ?= @get 'end'
168 # TODO: should validate here...
169 @parent.invoke 'query-capacity',
172 capacity: 'available'
175 collections = res.get 'collections'
176 unless collections.length > 0
177 return reject 'no resource capacity available during requested start/end time'
179 pools = collections.filter (e) -> /^ResourcePool/.test e
180 # should do some policy or check to see if more than one pool acceptable to reservee
182 entries = res.get 'utilization'
183 start = new Date req.start
184 end = new Date req.end
186 for x in [0..entries.length-1]
187 t1 = new Date entries[x].timestamp
188 break unless t1 < end
190 if x < entries.length-1
191 t2 = new Date entries[x+1].timestamp
192 continue unless t2 > start
194 available = entries[x].capacity
195 for k, v of req.capacity when v? and !!v
196 unless available[k] >= v
197 return reject "requested #{k}=#{v} exceeds available #{available[k]} between #{t1} and #{t2}"
202 .catch (err) -> reject err
204 save: !coffee/function |
205 (prev) -> (resolve, reject) ->
206 @invoke 'validate', @get()
208 # should do something about this reservation record...
209 now = (new Date).toJSON()
210 unless (res.get 'created-on')?
211 res.set 'created-on', now
212 res.set 'modified-on', now
214 .catch (e) -> reject e
218 priority: !coffee/function |
219 (prev) -> @computed (->
221 when not (@get 'reservation')? then 3
222 when not (@get 'active') then 2
227 save: !coffee/function |
228 (prev) -> (resolve, reject) ->
229 # validate that record contains sufficient data
232 for k, v of value.capacity when v? and !!v
234 if (not hasCapacity) and value.elements.length is 0
235 return reject "unable to save pool record without any capacity values"
241 token: !coffee/function |
242 (prev) -> prev.set 'private', true
244 pools: !coffee/function |
245 (prev) -> @computed (->
246 (@store.find 'ResourcePool', source: (@get 'name')).map (x) -> x.get 'id'
250 # XXX - this method is OpenStack-specific only, will need to revise later
251 update: !coffee/function |
252 (prev) -> (services=[], resolve, reject) ->
253 return reject "unable to update provider without list of services" unless services.length
254 request = @store.parent.require 'superagent'
255 services.forEach (service) =>
258 url = service.endpoints[0].publicURL
259 @set 'services.compute.endpoint', url
262 .set 'X-Auth-Token', @get 'token'
263 .set 'Accept', 'application/json'
266 console.warn "request to discover capacity limits failed"
269 capacity = res.body.limits?.absolute
270 #console.log "\ndiscovered capacity:"
271 #console.log capacity
273 (@access 'capacity').set {
274 cores: capacity.maxTotalCores
275 ram: capacity.maxTotalRAMSize
276 instances: capacity.maxTotalInstances
277 addresses: capacity.maxTotalFloatingIps
280 .get "#{url}/flavors/detail"
281 .set 'X-Auth-Token', @get 'token'
282 .set 'Accept', 'application/json'
285 console.warn "request to discover compute flavors failed"
288 flavors = res.body.flavors
289 # console.log "\ndiscovered flavors:"
290 # console.log flavors
292 flavors = flavors.map (x) -> ResourceFlavor: x
293 (@access 'services.compute.flavors').push flavors...
295 console.warn "failed to update flavors into the provider due to validation errors"
297 # XXX - update should do promise.all