Compare commits

...

3 Commits

Author SHA1 Message Date
Simon Pacotte
dc568b8b45 Added missing ACL actions to doc 2026-05-12 16:21:25 +02:00
Simon Pacotte
e8ff8fd5f6 update changelog 2026-05-11 16:06:37 +02:00
Simon Pacotte
1925e08aaf feat(rest-api): connect/disable backup-repository 2026-05-11 16:01:38 +02:00
5 changed files with 84 additions and 3 deletions

View File

@@ -294,6 +294,7 @@ export type XoApp = {
name?: string
}
): void
updateRemote(id: XoBackupRepository['id'], props: { enabled?: boolean }): Promise<void>
getAllXapis(): Record<string, XapiConnection>
getObjects(opts?: { filter?: Record<string, unknown>; limit?: number }): Record<string, XapiXoRecord>
}

View File

@@ -1,3 +1,5 @@
export default {
connect: true,
disable: true,
read: true,
}

View File

@@ -1,4 +1,17 @@
import { Example, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa'
import {
Example,
Get,
Middlewares,
Path,
Post,
Query,
Request,
Response,
Route,
Security,
SuccessResponse,
Tags,
} from 'tsoa'
import { inject } from 'inversify'
import { provide } from 'inversify-binding-decorators'
import { Request as ExRequest } from 'express'
@@ -6,8 +19,10 @@ import type { XoBackupRepository } from '@vates/types'
import { acl } from '../middlewares/acl.middleware.mjs'
import {
asynchronousActionResp,
badRequestResp,
forbiddenOperationResp,
noContentResp,
notFoundResp,
unauthorizedResp,
type Unbrand,
@@ -20,6 +35,8 @@ import {
import type { SendObjects } from '../helpers/helper.type.mjs'
import { XoController } from '../abstract-classes/xo-controller.mjs'
import { RestApi } from '../rest-api/rest-api.mjs'
import type { CreateActionReturnType } from '../abstract-classes/base-controller.mjs'
import { taskLocation } from '../open-api/oa-examples/task.oa-example.mjs'
@Route('backup-repositories')
@Security('*')
@@ -87,4 +104,62 @@ export class BackupRepositoryController extends XoController<XoBackupRepository>
getRepository(@Path() id: string): Promise<Unbrand<XoBackupRepository>> {
return this.getObject(id as XoBackupRepository['id'])
}
/**
* Required privilege:
* - resource: backup-repository, action: connect
*
* @example id "c4284e12-37c9-7967-b9e8-83ef229c3e03"
*/
@Example(taskLocation)
@Post('{id}/actions/connect')
@Middlewares(
acl({
resource: 'backup-repository',
action: 'connect',
objectId: 'params.id',
getObject: ({ restApi }) => restApi.xoApp.getRemote,
})
)
@SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description)
@Response(noContentResp.status, noContentResp.description)
@Response(forbiddenOperationResp.status, forbiddenOperationResp.description)
@Response(notFoundResp.status, notFoundResp.description)
connectBackupRepository(@Path() id: string, @Query() sync?: boolean): CreateActionReturnType<void> {
const backupRepositoryId = id as XoBackupRepository['id']
return this.createAction<void>(() => this.restApi.xoApp.updateRemote(backupRepositoryId, { enabled: true }), {
statusCode: noContentResp.status,
sync,
taskProperties: { name: 'connect backup repository', objectId: backupRepositoryId },
})
}
/**
* Required privilege:
* - resource: backup-repository, action: disable
*
* @example id "c4284e12-37c9-7967-b9e8-83ef229c3e03"
*/
@Example(taskLocation)
@Post('{id}/actions/disable')
@Middlewares(
acl({
resource: 'backup-repository',
action: 'disable',
objectId: 'params.id',
getObject: ({ restApi }) => restApi.xoApp.getRemote,
})
)
@SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description)
@Response(noContentResp.status, noContentResp.description)
@Response(forbiddenOperationResp.status, forbiddenOperationResp.description)
@Response(notFoundResp.status, notFoundResp.description)
disableBackupRepository(@Path() id: string, @Query() sync?: boolean): CreateActionReturnType<void> {
const backupRepositoryId = id as XoBackupRepository['id']
return this.createAction<void>(() => this.restApi.xoApp.updateRemote(backupRepositoryId, { enabled: false }), {
statusCode: noContentResp.status,
sync,
taskProperties: { name: 'disable backup repository', objectId: backupRepositoryId },
})
}
}

View File

@@ -13,6 +13,7 @@
- [xo-web] support qcow2 format in disk > import (PR [#9817](https://github.com/vatesfr/xen-orchestra/pull/9817))
- [xo-server] support qcow2 format in `disk.importContent` and `disk.import` jsonRPC api (PR [#9817](https://github.com/vatesfr/xen-orchestra/pull/9817))
- [REST API] Expose POST `/backup-repositories/:id/actions/connect` and POST `/backup-repositories/:id/actions/disable` routes (PR [#9832](https://github.com/vatesfr/xen-orchestra/pull/9832))
### Bug fixes
@@ -36,7 +37,9 @@
<!--packages-start-->
- @xen-orchestra/rest-api patch
- @vates/types minor
- @xen-orchestra/acl minor
- @xen-orchestra/rest-api minor
- @xen-orchestra/web-core minor
- xo-server minor
- xo-web minor

View File

@@ -135,7 +135,7 @@ Actions are written using the exact string you pass in a privilege. A parent act
| `backup-job` | `read` |
| `backup-archive` | `read` |
| `backup-log` | `read` |
| `backup-repository` | `read` |
| `backup-repository` | `connect`, `disable`, `read` |
| `schedule` | `read`, `run` |
| `restore-log` | `read` |
| `proxy` | `read` |