parent
aa5b3dc426
commit
b67231c56b
@ -15,6 +15,7 @@
|
|||||||
- [Settings/acls] Add bulk deletion [#3179](https://github.com/vatesfr/xen-orchestra/issues/3179) (PR [#3536](https://github.com/vatesfr/xen-orchestra/pull/3536))
|
- [Settings/acls] Add bulk deletion [#3179](https://github.com/vatesfr/xen-orchestra/issues/3179) (PR [#3536](https://github.com/vatesfr/xen-orchestra/pull/3536))
|
||||||
- [Home] Improve search usage: raw numbers also match in names [#2906](https://github.com/vatesfr/xen-orchestra/issues/2906) (PR [#3552](https://github.com/vatesfr/xen-orchestra/pull/3552))
|
- [Home] Improve search usage: raw numbers also match in names [#2906](https://github.com/vatesfr/xen-orchestra/issues/2906) (PR [#3552](https://github.com/vatesfr/xen-orchestra/pull/3552))
|
||||||
- [Backup NG] Timeout of a job is now in hours [#3550](https://github.com/vatesfr/xen-orchestra/issues/3550) (PR [#3553](https://github.com/vatesfr/xen-orchestra/pull/3553))
|
- [Backup NG] Timeout of a job is now in hours [#3550](https://github.com/vatesfr/xen-orchestra/issues/3550) (PR [#3553](https://github.com/vatesfr/xen-orchestra/pull/3553))
|
||||||
|
- [Backup NG] Explicit error if a VM is missing [#3434](https://github.com/vatesfr/xen-orchestra/issues/3434) (PR [#3522](https://github.com/vatesfr/xen-orchestra/pull/3522))
|
||||||
|
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ export const notImplemented = create(0, () => ({
|
|||||||
|
|
||||||
export const noSuchObject = create(1, (id, type) => ({
|
export const noSuchObject = create(1, (id, type) => ({
|
||||||
data: { id, type },
|
data: { id, type },
|
||||||
message: 'no such object',
|
message: `no such ${type || 'object'} ${id}`,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
export const unauthorized = create(2, () => ({
|
export const unauthorized = create(2, () => ({
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { forEach } from 'lodash'
|
import { forEach } from 'lodash'
|
||||||
|
import { noSuchObject } from 'xo-common/api-errors'
|
||||||
|
|
||||||
const isSkippedError = error =>
|
const isSkippedError = error =>
|
||||||
error.message === 'no disks found' ||
|
error.message === 'no disks found' ||
|
||||||
error.message === 'no such object' ||
|
noSuchObject.is(error) ||
|
||||||
error.message === 'no VMs match this pattern' ||
|
error.message === 'no VMs match this pattern' ||
|
||||||
error.message === 'unhealthy VDI chain'
|
error.message === 'unhealthy VDI chain'
|
||||||
|
|
||||||
|
@ -410,6 +410,35 @@ const wrapTaskFn = <T>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const extractIdsFromSimplePattern = (pattern: mixed) => {
|
||||||
|
if (pattern === null || typeof pattern !== 'object') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let keys = Object.keys(pattern)
|
||||||
|
if (keys.length !== 1 || keys[0] !== 'id') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern = pattern.id
|
||||||
|
if (typeof pattern === 'string') {
|
||||||
|
return [pattern]
|
||||||
|
}
|
||||||
|
if (pattern === null || typeof pattern !== 'object') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
keys = Object.keys(pattern)
|
||||||
|
if (
|
||||||
|
keys.length === 1 &&
|
||||||
|
keys[0] === '__or' &&
|
||||||
|
Array.isArray((pattern = pattern.__or)) &&
|
||||||
|
pattern.every(_ => typeof _ === 'string')
|
||||||
|
) {
|
||||||
|
return pattern
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// File structure on remotes:
|
// File structure on remotes:
|
||||||
//
|
//
|
||||||
// <remote>
|
// <remote>
|
||||||
@ -471,21 +500,48 @@ export default class BackupNg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const job: BackupJob = (job_: any)
|
const job: BackupJob = (job_: any)
|
||||||
|
const vmsPattern = job.vms
|
||||||
|
|
||||||
const vms: $Dict<Vm> = app.getObjects({
|
let vms: $Dict<Vm>
|
||||||
filter: createPredicate({
|
if (
|
||||||
type: 'VM',
|
vmsId !== undefined ||
|
||||||
...(vmsId !== undefined
|
(vmsId = extractIdsFromSimplePattern(vmsPattern)) !== undefined
|
||||||
? {
|
) {
|
||||||
id: {
|
vms = vmsId
|
||||||
__or: vmsId,
|
.map(id => {
|
||||||
},
|
try {
|
||||||
}
|
return app.getObject(id, 'VM')
|
||||||
: job.vms),
|
} catch (error) {
|
||||||
}),
|
const taskId: string = logger.notice(
|
||||||
})
|
`Starting backup of ${id}. (${job.id})`,
|
||||||
if (isEmpty(vms)) {
|
{
|
||||||
throw new Error('no VMs match this pattern')
|
event: 'task.start',
|
||||||
|
parentId: runJobId,
|
||||||
|
data: {
|
||||||
|
type: 'VM',
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
logger.error(`Backuping ${id} has failed. (${job.id})`, {
|
||||||
|
event: 'task.end',
|
||||||
|
taskId,
|
||||||
|
status: 'failure',
|
||||||
|
result: serializeError(error),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(vm => vm !== undefined)
|
||||||
|
} else {
|
||||||
|
vms = app.getObjects({
|
||||||
|
filter: createPredicate({
|
||||||
|
type: 'VM',
|
||||||
|
...vmsPattern,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
if (isEmpty(vms)) {
|
||||||
|
throw new Error('no VMs match this pattern')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const jobId = job.id
|
const jobId = job.id
|
||||||
const srs = unboxIds(job.srs).map(id => {
|
const srs = unboxIds(job.srs).map(id => {
|
||||||
|
Loading…
Reference in New Issue
Block a user