265 lines
8.3 KiB
CoffeeScript
265 lines
8.3 KiB
CoffeeScript
angular = require 'angular'
|
|
|
|
filter = require 'lodash.filter'
|
|
|
|
#=====================================================================
|
|
|
|
# TODO: split into multiple modules.
|
|
module.exports = angular.module 'xoWebApp.services', [
|
|
require 'angular-animate'
|
|
|
|
require 'angular-notify-toaster'
|
|
|
|
require 'xo-api'
|
|
]
|
|
|
|
.service 'notify', (toaster) ->
|
|
notifier = (level) ->
|
|
(options) ->
|
|
if angular.isString options
|
|
options = { message: options }
|
|
else
|
|
throw new Error 'missing message' unless options.message
|
|
|
|
toaster.pop(
|
|
level
|
|
options.title ? 'Xen-Orchestra'
|
|
options.message
|
|
)
|
|
|
|
{
|
|
warning: notifier 'warning'
|
|
error: notifier 'error'
|
|
info: notifier 'info'
|
|
# TODO: It is probably a bad design to have notification for
|
|
# successful operations.
|
|
# success: notifier 'success'
|
|
}
|
|
|
|
.service 'xo', ($timeout, xoApi, notify) ->
|
|
# FIXME: default mapper should be identity.
|
|
defaultArgsMapper = (id) -> if id? then {id} else {}
|
|
|
|
action = (name, method, options) ->
|
|
unless method
|
|
return ->
|
|
notify.info {
|
|
title: name
|
|
message: 'This feature has not been implemented yet.'
|
|
}
|
|
|
|
# TODO: A (broken) promise should be returned for
|
|
# consistency.
|
|
|
|
{argsMapper, notification} = options ? {}
|
|
argsMapper ?= defaultArgsMapper
|
|
|
|
(args...) ->
|
|
xoApi.call(
|
|
method
|
|
argsMapper args...
|
|
).catch (error) ->
|
|
unless notification is false
|
|
code = error?.code
|
|
message = if code is 2
|
|
'You don\'t have the permission.'
|
|
else
|
|
'The action failed for unknown reason.'
|
|
|
|
notify.warning {
|
|
title: name
|
|
message
|
|
}
|
|
|
|
console.error error
|
|
|
|
# Re-throws the error to make it available in the promise
|
|
# chain.
|
|
throw error
|
|
|
|
# The interface.
|
|
xo = {
|
|
acl:
|
|
add: action('Adding an ACL entry', 'acl.add', {
|
|
argsMapper: (subject, object) => {subject, object},
|
|
})
|
|
get: action('Getting ACLs', 'acl.get')
|
|
remove: action('Remove an ACL entry', 'acl.remove', {
|
|
argsMapper: (subject, object) => {subject, object},
|
|
})
|
|
|
|
|
|
pool:
|
|
disconnect: action 'Disconnect pool'
|
|
new_sr: action 'New SR' #temp fix before creating SR
|
|
patch: action 'Upload patch', 'pool.patch', argsMapper: (pool) -> {pool}
|
|
|
|
host:
|
|
attach: action 'Atach host'#, 'host.attach'
|
|
detach: action 'Detach host', 'host.detach'
|
|
restart: action 'Restart host', 'host.restart'
|
|
restartToolStack: action 'Restart tool stack', 'host.restart_agent'
|
|
start: action 'Start host', 'host.start'
|
|
enable: action 'Enable host', 'host.enable'
|
|
stop: action 'Stop host', 'host.stop'
|
|
disable: action 'Disable host', 'host.disable'
|
|
new_sr: action 'New SR' #temp fix before creating SR
|
|
# TODO: attach/set
|
|
|
|
log:
|
|
delete: action 'Delete Log', 'message.delete'
|
|
|
|
message:
|
|
delete: action 'Delete message'
|
|
|
|
pbd:
|
|
delete: action 'Delete PBD'
|
|
disconnect: action 'Disconnect PBD'
|
|
|
|
server:
|
|
add: action 'Add server', 'server.add', {
|
|
argsMapper: (params) -> angular.copy(params)
|
|
}
|
|
remove: action 'Remove server', 'server.remove', argsMapper: (id) -> {id}
|
|
getAll: action 'Getting server', 'server.getAll'
|
|
set: action 'Save server', 'server.set', {
|
|
argsMapper: (params) -> angular.copy(params)
|
|
}
|
|
connect: action 'Connect to a server', 'server.connect', notification: false, argsMapper: (id) -> {id}
|
|
disconnect: action 'Disconnect from a server', 'server.disconnect', argsMapper: (id) -> {id}
|
|
|
|
task:
|
|
cancel: action 'Cancel task', 'task.cancel', argsMapper: (id) -> {id}
|
|
destroy: action 'Destroy task', 'task.destroy', argsMapper: (id) -> {id}
|
|
|
|
user:
|
|
create: action 'Create user', 'user.create', {
|
|
argsMapper: (params) -> angular.copy(params)
|
|
}
|
|
delete: action 'Delete user', 'user.delete', argsMapper: (id) -> {id}
|
|
getAll: action 'Getting users', 'user.getAll'
|
|
set: action 'Save user', 'user.set', {
|
|
argsMapper: (params) -> angular.copy(params)
|
|
}
|
|
|
|
vm:
|
|
convert: action 'Convert VM', 'vm.convert', {
|
|
argsMapper: (id) -> {id}
|
|
}
|
|
clone: action 'Copy VM', 'vm.clone', {
|
|
argsMapper: (id, name, full_copy) -> {id, name, full_copy} #todo : sr ref to choose target SR
|
|
}
|
|
createSnapshot: action 'Create VM snapshot', 'vm.snapshot', {
|
|
argsMapper: (id, name) -> {id, name}
|
|
}
|
|
export: action 'Export VM', 'vm.export', {
|
|
argsMapper: (vm, compress = true) -> {vm, compress}
|
|
}
|
|
delete: action 'Delete VM', 'vm.delete', {
|
|
argsMapper: (id, delete_disks) -> { id, delete_disks }
|
|
}
|
|
ejectCd: action 'Eject disc', 'vm.ejectCd'
|
|
insertCd: action 'Insert disc', 'vm.insertCd', {
|
|
argsMapper: (id, cd_id, force = false) -> { id, cd_id, force }
|
|
}
|
|
import: action 'Import VM', 'vm.import', {
|
|
argsMapper: (host) -> { host }
|
|
}
|
|
migrate: action 'Migrate VM', 'vm.migrate', {
|
|
argsMapper: (id, host_id) -> { id, host_id }
|
|
}
|
|
migratePool: action 'Migrate VM to another pool', 'vm.migrate_pool', {
|
|
argsMapper: (params) -> angular.copy(params)
|
|
}
|
|
restart: action 'Restart VM', 'vm.restart', {
|
|
argsMapper: (id, force = false) -> { id, force }
|
|
}
|
|
start: action 'Start VM', 'vm.start'
|
|
stop: action 'Stop VM', 'vm.stop', {
|
|
argsMapper: (id, force = false) -> { id, force }
|
|
}
|
|
revert: action 'Revert snapshot', 'vm.revert'
|
|
suspend: action 'Suspend VM', 'vm.suspend'
|
|
resume: action 'Resume VM', 'vm.resume', {
|
|
argsMapper: (id, force = true) -> { id, force }
|
|
}
|
|
refreshStats: action 'Get Stats', 'vm.stats', {
|
|
argsMapper: (id) -> {id}
|
|
}
|
|
# TODO: create/set/pause
|
|
connectPci: action 'Connect PCI device', 'vm.attachPci', {
|
|
argsMapper: (vm, pciId) -> {vm, pciId}
|
|
}
|
|
disconnectPci: action 'Disconnect PCI device', 'vm.detachPci', {
|
|
argsMapper: (vm) -> {vm}
|
|
}
|
|
|
|
vdi:
|
|
delete: action 'Delete VDI', 'vdi.delete'
|
|
migrate: action 'Migrate VDI', 'vdi.migrate', {
|
|
argsMapper: (id, sr_id) -> { id, sr_id }
|
|
}
|
|
|
|
vif:
|
|
delete: action 'Delete VIF', 'vif.delete'
|
|
disconnect: action 'Disconnect VIF', 'vif.disconnect'
|
|
connect: action 'Connect VIF', 'vif.connect'
|
|
|
|
vbd:
|
|
delete: action 'Delete VBD', 'vbd.delete'
|
|
disconnect: action 'Disconnect VBD', 'vbd.disconnect'
|
|
connect: action 'Connect VBD', 'vbd.connect'
|
|
}
|
|
|
|
# TODO: should probably be merged in the main collection in xo-lib.
|
|
currentAcls = Object.create(null)
|
|
updateCurrentAcls = () ->
|
|
xoApi.call('acl.getCurrent').then((acls) ->
|
|
currentAcls = Object.create(null)
|
|
for acl in acls
|
|
object = xoApi.get(acl.object)
|
|
if object
|
|
currentAcls[object.id] = true
|
|
|
|
$timeout(updateCurrentAcls, 1e4)
|
|
return
|
|
)
|
|
updateCurrentAcls()
|
|
|
|
# Adds the dynamic properties.
|
|
Object.defineProperties(xo, {
|
|
byTypes: { get: ->
|
|
throw new Error('use xoApi.byTypes instead');
|
|
},
|
|
get: { get: ->
|
|
throw new Error('use xoApi.get() instead');
|
|
},
|
|
|
|
currentAcls: { get: -> currentAcls },
|
|
})
|
|
|
|
xo.canAccess = (id) ->
|
|
{id} = id if id.id
|
|
|
|
return (
|
|
# Administrators can access everything.
|
|
xoApi.user and (xoApi.user.permission is 'admin') or
|
|
|
|
# Check if the id is in the ACLs table.
|
|
(id of currentAcls) or
|
|
|
|
# Check if the id is in fact not a true id (maybe a ref or a
|
|
# UUID) and if we can resolve it to an id.
|
|
(id = xoApi.get(id)?.id) and (id of currentAcls)
|
|
)
|
|
|
|
# Returns the interface.
|
|
xo
|
|
|
|
.filter 'xoHideUnauthorized', (xo) ->
|
|
{canAccess} = xo
|
|
return (objects) -> filter objects, xo.canAccess
|
|
|
|
# A module exports its name.
|
|
.name
|