Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(xo-server/rest-api/dashboard): add S3 backup repositories information #7978

Merged
merged 6 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions @xen-orchestra/backups/RemoteAdapter.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import fromEvent from 'promise-toolbox/fromEvent'
import groupBy from 'lodash/groupBy.js'
import pDefer from 'promise-toolbox/defer'
import pickBy from 'lodash/pickBy.js'
import reduce from 'lodash/reduce.js'
import tar from 'tar'
import zlib from 'zlib'

Expand Down Expand Up @@ -826,6 +827,29 @@ export class RemoteAdapter {
}
return metadata
}

#computeTotalBackupSizeRecursively(backups) {
return reduce(
backups,
(prev, backup) => {
const _backup = Array.isArray(backup) ? this.#computeTotalBackupSizeRecursively(backup) : backup
return {
onDisk: prev.onDisk + (_backup.onDisk ?? _backup.size),
}
},
{ onDisk: 0 }
)
}

async getTotalVmBackupSize() {
return this.#computeTotalBackupSizeRecursively(await this.listAllVmBackups())
}

async getTotalBackupSize() {
const vmBackupSize = await this.getTotalVmBackupSize()
// @TODO: add `getTotalXoBackupSize` and `getTotalPoolBackupSize` once `size` is implemented by fs
return vmBackupSize
}
}

Object.assign(RemoteAdapter.prototype, {
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- [V2V] Fix computation of `memory_static_max`
- **XO 6**:
- [Dashboard] Display backup issues data (PR [#7974](https://github.com/vatesfr/xen-orchestra/pull/7974))
- [REST API] Add S3 backup repository information in the `/rest/v0/dashboard` endpoint (PR [#7978](https://github.com/vatesfr/xen-orchestra/pull/7978))

### Bug fixes

Expand Down
54 changes: 29 additions & 25 deletions packages/xo-server/src/xo-mixins/rest-api.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { pipeline } from 'node:stream/promises'
import { json, Router } from 'express'
import { Readable } from 'node:stream'
import cloneDeep from 'lodash/cloneDeep.js'
import Disposable from 'promise-toolbox/Disposable'
import groupBy from 'lodash/groupBy.js'
import path from 'node:path'
import pDefer from 'promise-toolbox/defer'
Expand Down Expand Up @@ -226,35 +227,38 @@ async function _getDashboardStats(app) {
}

try {
const remotes = await app.getAllRemotes()
const remotesInfo = await app.getAllRemotesInfo()
const s3Brsize = { backups: 0 }
const otherBrSize = { available: 0, backups: 0, other: 0, total: 0, used: 0 }

const backupRepositoriesSize = remotes.reduce(
(prev, remote) => {
const { type } = parse(remote.url)
const remoteInfo = remotesInfo[remote.id]
const backupRepositories = await app.getAllRemotes()
const backupRepositoriesInfo = await app.getAllRemotesInfo()

if (!remote.enabled || type === 's3' || remoteInfo === undefined) {
return prev
}
for (const backupRepository of backupRepositories) {
const { type } = parse(backupRepository.url)
const backupRepositoryInfo = backupRepositoriesInfo[backupRepository.id]

return {
available: prev.available + remoteInfo.available,
backups: 0, // @TODO: compute the space used by backups
other: 0, // @TODO: compute the space used by everything that is not a backup
total: prev.total + remoteInfo.size,
used: prev.used + remoteInfo.used,
}
},
{
available: 0,
backups: 0,
other: 0,
total: 0,
used: 0,
if (!backupRepository.enabled || backupRepositoryInfo === undefined) {
continue
}
)
dashboard.backupRepositories = { size: backupRepositoriesSize }

const totalBackupSize = await Disposable.use(app.getBackupsRemoteAdapter(backupRepository), adapter =>
adapter.getTotalBackupSize()
)
const { available, size, used } = backupRepositoryInfo

const isS3 = type === 's3'
const target = isS3 ? s3Brsize : otherBrSize

target.backups += totalBackupSize.onDisk
if (!isS3) {
target.available += available
target.other += used - totalBackupSize.onDisk
target.total += size
target.used += used
}
}

dashboard.backupRepositories = { s3: { size: s3Brsize }, other: { size: otherBrSize } }
} catch (error) {
console.error(error)
}
Expand Down
Loading