summaryrefslogtreecommitdiffstats
path: root/source/promise.yaml
diff options
context:
space:
mode:
authorPeter Lee <peter@corenova.com>2016-01-29 15:21:56 -0800
committerGerald Kunzmann <kunzmann@docomolab-euro.com>2016-01-29 23:48:40 +0000
commit2ca7d533b6fe01a10fcc3474812183e4c4a8431e (patch)
tree644d9cb2fead71ddf00c2a83219040288e23d471 /source/promise.yaml
parentdd0fe997358220ee0999f984f0120a4aa99d3341 (diff)
added copy of github.com/opnfv/promise source into the source directory
Change-Id: Ib212302a4132aa492f7b701a7ca02f54a7d0a6af (cherry picked from commit a46af646972b6ff263fb207d28a59e7ce7417b5c)
Diffstat (limited to 'source/promise.yaml')
-rw-r--r--source/promise.yaml290
1 files changed, 290 insertions, 0 deletions
diff --git a/source/promise.yaml b/source/promise.yaml
new file mode 100644
index 0000000..125c7b7
--- /dev/null
+++ b/source/promise.yaml
@@ -0,0 +1,290 @@
+name: opnfv-promise
+description: Resource Management for Virtualized Infrastructure
+author: Peter K. Lee <peter@intercloud.net>
+license: Apache-2.0
+homepage: http://wiki.opnfv.org/promise
+repository: git://github.com/opnfv/promise.git
+yangforge: "0.11.x"
+keywords:
+ - opnfv
+ - promise
+ - vim
+ - nfvi
+ - infrastructure
+ - openstack
+ - nbi
+ - yangforge
+ - resource
+ - reservation
+ - capacity
+ - allocation
+
+schema: !yang schema/opnfv-promise.yang
+
+# below config provides default parameters
+# NOTE: uncomment locally for testing with pre-existing data
+#config: !json config/demo.json
+
+dependencies:
+ access-control-models: !yang schema/access-control-models.yang
+ nfv-infrastructure: !yang schema/nfv-infrastructure.yang
+
+# MODULE model active bindings
+module:
+ opnfv-promise:
+ # rebind to be a computed property
+ promise.capacity.total: !coffee/function |
+ (prev) -> @computed (->
+ combine = (a, b) ->
+ for k, v of b.capacity when v?
+ a[k] ?= 0
+ a[k] += v
+ return a
+ (@parent.get 'pools')
+ .filter (entry) -> entry.active is true
+ .reduce combine, {}
+ ), type: prev
+ # rebind to be a computed property
+ promise.capacity.reserved: !coffee/function |
+ (prev) -> @computed (->
+ combine = (a, b) ->
+ for k, v of b.remaining when v?
+ a[k] ?= 0
+ a[k] += v
+ return a
+ (@parent.get 'reservations')
+ .filter (entry) -> entry.active is true
+ .reduce combine, {}
+ ), type: prev
+ # rebind to be a computed property
+ promise.capacity.usage: !coffee/function |
+ (prev) -> @computed (->
+ combine = (a, b) ->
+ for k, v of b.capacity when v?
+ a[k] ?= 0
+ a[k] += v
+ return a
+ (@parent.get 'allocations')
+ .filter (entry) -> entry.active is true
+ .reduce combine, {}
+ ), type: prev
+ # rebind to be a computed property
+ promise.capacity.available: !coffee/function |
+ (prev) -> @computed (->
+ total = @get 'total'
+ reserved = @get 'reserved'
+ usage = @get 'usage'
+ for k, v of total when v?
+ total[k] -= reserved[k] if reserved[k]?
+ total[k] -= usage[k] if usage[k]?
+ total
+ ), type: prev
+
+# RPC definitions (INTENT interfaces)
+rpc: !require spec/promise-intents.coffee
+
+# COMPLEX-TYPE model active bindings (controller logic)
+complex-type:
+ ResourceElement:
+ #properties
+ id: !coffee/function |
+ (prev) -> prev.set 'default', -> @uuid()
+
+ ResourceCollection:
+ # properties
+ start: !coffee/function |
+ (prev) -> prev.set 'default', -> (new Date).toJSON()
+
+ active: !coffee/function |
+ (prev) -> @computed (->
+ now = new Date
+ start = new Date (@get 'start')
+ end = switch
+ when (@get 'end')? then new Date (@get 'end')
+ else now
+ (@get 'enabled') and (start <= now <= end)
+ ), type: prev
+
+ ResourceReservation:
+ end: !coffee/function |
+ (prev) -> prev.set 'default', ->
+ end = (new Date @get 'start')
+ max = @parent.get 'promise.policy.reservation.max-duration'
+ return unless max?
+ end.setTime (end.getTime() + (max*60*60*1000))
+ end.toJSON()
+
+ allocations: !coffee/function |
+ (prev) -> @computed (->
+ res = (@store.find 'ResourceAllocation', reservation: @id)
+ res.map (x) -> x.get 'id'
+ ), type: 'array'
+
+ remaining: !coffee/function |
+ (prev) -> @computed (->
+ total = @get 'capacity'
+ records = @store.find 'ResourceAllocation', id: (@get 'allocations'), active: true
+ for entry in records
+ usage = entry.get 'capacity'
+ for k, v of usage
+ total[k] -= v
+ total
+ ), type: prev
+
+ # methods
+ validate: !coffee/function |
+ (prev) -> (value={}, resolve, reject) ->
+ # validate that request contains sufficient data
+ for k, v of value.capacity when v? and !!v
+ hasCapacity = true
+ if (not hasCapacity) and value.elements.length is 0
+ return reject "unable to validate reservation record without anything being reserved"
+ # time range verifications
+ now = new Date
+ start = (new Date value.start) if value.start?
+ end = (new Date value.end) if value.end?
+ # if start? and start < now
+ # return reject "requested start time #{value.start} cannot be in the past"
+ if end? and end < now
+ return reject "requested end time #{value.end} cannot be in the past"
+ if start? and end? and start > end
+ retun reject "requested start time must be earlier than end time"
+ resolve this
+
+ update: !coffee/function |
+ (prev) -> (req, resolve, reject) ->
+ req.start ?= @get 'start'
+ req.end ?= @get 'end'
+
+ # TODO: should validate here...
+ @parent.invoke 'query-capacity',
+ start: req.start
+ end: req.end
+ capacity: 'available'
+ without: @id
+ .then (res) =>
+ collections = res.get 'collections'
+ unless collections.length > 0
+ return reject 'no resource capacity available during requested start/end time'
+
+ pools = collections.filter (e) -> /^ResourcePool/.test e
+ # should do some policy or check to see if more than one pool acceptable to reservee
+
+ entries = res.get 'utilization'
+ start = new Date req.start
+ end = new Date req.end
+
+ for x in [0..entries.length-1]
+ t1 = new Date entries[x].timestamp
+ break unless t1 < end
+
+ if x < entries.length-1
+ t2 = new Date entries[x+1].timestamp
+ continue unless t2 > start
+
+ available = entries[x].capacity
+ for k, v of req.capacity when v? and !!v
+ unless available[k] >= v
+ return reject "requested #{k}=#{v} exceeds available #{available[k]} between #{t1} and #{t2}"
+
+ @set req
+ @set 'pools', pools
+ resolve this
+ .catch (err) -> reject err
+
+ save: !coffee/function |
+ (prev) -> (resolve, reject) ->
+ @invoke 'validate', @get()
+ .then (res) ->
+ # should do something about this reservation record...
+ now = (new Date).toJSON()
+ unless (res.get 'created-on')?
+ res.set 'created-on', now
+ res.set 'modified-on', now
+ resolve res
+ .catch (e) -> reject e
+
+ ResourceAllocation:
+ # properties
+ priority: !coffee/function |
+ (prev) -> @computed (->
+ switch
+ when not (@get 'reservation')? then 3
+ when not (@get 'active') then 2
+ else 1
+ ), type: prev
+
+ ResourcePool:
+ save: !coffee/function |
+ (prev) -> (resolve, reject) ->
+ # validate that record contains sufficient data
+ value = @get()
+
+ for k, v of value.capacity when v? and !!v
+ hasCapacity = true
+ if (not hasCapacity) and value.elements.length is 0
+ return reject "unable to save pool record without any capacity values"
+
+ resolve this
+
+ ResourceProvider:
+ # properties
+ token: !coffee/function |
+ (prev) -> prev.set 'private', true
+
+ pools: !coffee/function |
+ (prev) -> @computed (->
+ (@store.find 'ResourcePool', source: (@get 'name')).map (x) -> x.get 'id'
+ ), type: 'array'
+
+ # methods
+ # XXX - this method is OpenStack-specific only, will need to revise later
+ update: !coffee/function |
+ (prev) -> (services=[], resolve, reject) ->
+ return reject "unable to update provider without list of services" unless services.length
+ request = @store.parent.require 'superagent'
+ services.forEach (service) =>
+ switch service.type
+ when 'compute'
+ url = service.endpoints[0].publicURL
+ @set 'services.compute.endpoint', url
+ request
+ .get "#{url}/limits"
+ .set 'X-Auth-Token', @get 'token'
+ .set 'Accept', 'application/json'
+ .end (err, res) =>
+ if err? or !res.ok
+ console.warn "request to discover capacity limits failed"
+ return
+
+ capacity = res.body.limits?.absolute
+ #console.log "\ndiscovered capacity:"
+ #console.log capacity
+
+ (@access 'capacity').set {
+ cores: capacity.maxTotalCores
+ ram: capacity.maxTotalRAMSize
+ instances: capacity.maxTotalInstances
+ addresses: capacity.maxTotalFloatingIps
+ }
+ request
+ .get "#{url}/flavors/detail"
+ .set 'X-Auth-Token', @get 'token'
+ .set 'Accept', 'application/json'
+ .end (err, res) =>
+ if err? or !res.ok
+ console.warn "request to discover compute flavors failed"
+ return
+
+ flavors = res.body.flavors
+ # console.log "\ndiscovered flavors:"
+ # console.log flavors
+ try
+ flavors = flavors.map (x) -> ResourceFlavor: x
+ (@access 'services.compute.flavors').push flavors...
+ catch er
+ console.warn "failed to update flavors into the provider due to validation errors"
+
+ # XXX - update should do promise.all
+ resolve this
+