Compare commits
8 Commits
xo5/resour
...
fix_mirror
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b9e11e0ff | ||
|
|
e2d83324ac | ||
|
|
7cea445c21 | ||
|
|
b5d9d9a9e1 | ||
|
|
3a4e9b8f8e | ||
|
|
92efd28b33 | ||
|
|
a2c36c0832 | ||
|
|
2eb49cfdf1 |
@@ -218,16 +218,16 @@ export class IncrementalRemoteWriter extends MixinRemoteWriter(AbstractIncrement
|
||||
})
|
||||
transferSize += transferSizeOneDisk
|
||||
|
||||
if (isDifferencing) {
|
||||
await chainVhd(handler, parentPath, handler, path)
|
||||
}
|
||||
|
||||
// set the correct UUID in the VHD
|
||||
await Disposable.use(openVhd(handler, path), async vhd => {
|
||||
vhd.footer.uuid = packUuid(vdi.uuid)
|
||||
await vhd.readBlockAllocationTable() // required by writeFooter()
|
||||
await vhd.writeFooter()
|
||||
})
|
||||
|
||||
if (isDifferencing) {
|
||||
await chainVhd(handler, parentPath, handler, path)
|
||||
}
|
||||
},
|
||||
{
|
||||
concurrency: settings.diskPerVmConcurrency,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# ChangeLog
|
||||
|
||||
## **next**
|
||||
## **5.91.2** (2024-02-09)
|
||||
|
||||
<img id="latest" src="https://badgen.net/badge/channel/latest/yellow" alt="Channel: latest" />
|
||||
|
||||
### Enhancements
|
||||
|
||||
@@ -39,8 +41,6 @@
|
||||
|
||||
## **5.91.0** (2024-01-31)
|
||||
|
||||
<img id="latest" src="https://badgen.net/badge/channel/latest/yellow" alt="Channel: latest" />
|
||||
|
||||
### Highlights
|
||||
|
||||
- [Import/VMWare] Speed up import and make all imports thin [#7323](https://github.com/vatesfr/xen-orchestra/issues/7323)
|
||||
|
||||
@@ -7,12 +7,16 @@
|
||||
|
||||
> Users must be able to say: “Nice enhancement, I'm eager to test it”
|
||||
|
||||
- [Self service] From user POV, show used resources even when they are unlimited (PR [#7353](https://github.com/vatesfr/xen-orchestra/pull/7353))
|
||||
- Disable search engine indexing via a `robots.txt`
|
||||
|
||||
### Bug fixes
|
||||
|
||||
> Users must be able to say: “I had this issue, happy to know it's fixed”
|
||||
|
||||
- [Settings/XO Config] Sort backups from newest to oldest
|
||||
- [Plugins/audit] Don't log `tag.getAllConfigured` calls
|
||||
- [Remotes] Correctly clear error when the remote is tested with success
|
||||
|
||||
### Packages to release
|
||||
|
||||
> When modifying a package, add it here with its release type.
|
||||
@@ -29,7 +33,8 @@
|
||||
|
||||
<!--packages-start-->
|
||||
|
||||
- xo-server minor
|
||||
- xo-web minor
|
||||
- xo-server patch
|
||||
- xo-server-audit patch
|
||||
- xo-web patch
|
||||
|
||||
<!--packages-end-->
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{
|
||||
"name": "xen-orchestra",
|
||||
"version": "0.0.0",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.0.0",
|
||||
"@babel/eslint-parser": "^7.13.8",
|
||||
|
||||
@@ -72,6 +72,7 @@ const DEFAULT_BLOCKED_LIST = {
|
||||
'system.getServerTimezone': true,
|
||||
'system.getServerVersion': true,
|
||||
'system.getVersion': true,
|
||||
'tag.getAllConfigured': true,
|
||||
'test.getPermissionsForUser': true,
|
||||
'user.getAll': true,
|
||||
'user.getAuthenticationTokens': true,
|
||||
|
||||
@@ -143,6 +143,7 @@ port = 80
|
||||
requestTimeout = 0
|
||||
|
||||
[http.mounts]
|
||||
'/robots.txt' = './robots.txt'
|
||||
'/' = '../xo-web/dist/'
|
||||
'/v6' = '../../@xen-orchestra/web/dist/'
|
||||
|
||||
|
||||
2
packages/xo-server/robots.txt
Normal file
2
packages/xo-server/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow: /
|
||||
@@ -55,10 +55,10 @@ const normalize = set => ({
|
||||
limits: set.limits
|
||||
? map(set.limits, limit =>
|
||||
isObject(limit)
|
||||
? { ...limit, usage: limit.usage ?? 0 }
|
||||
? limit
|
||||
: {
|
||||
available: limit,
|
||||
total: limit,
|
||||
usage: 0,
|
||||
}
|
||||
)
|
||||
: {},
|
||||
@@ -217,32 +217,25 @@ export default class {
|
||||
if (objects) {
|
||||
set.objects = objects
|
||||
}
|
||||
|
||||
const previousLimits = set.limits
|
||||
const newLimits = {}
|
||||
forEach(limits, (quantity, id) => {
|
||||
const previous = previousLimits[id]
|
||||
if (previous !== undefined) {
|
||||
newLimits[id] = {
|
||||
total: quantity,
|
||||
usage: previous.usage,
|
||||
if (limits) {
|
||||
const previousLimits = set.limits
|
||||
set.limits = map(limits, (quantity, id) => {
|
||||
const previous = previousLimits[id]
|
||||
if (!previous) {
|
||||
return {
|
||||
available: quantity,
|
||||
total: quantity,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newLimits[id] = {
|
||||
|
||||
const { available, total } = previous
|
||||
|
||||
return {
|
||||
available: available - total + quantity,
|
||||
total: quantity,
|
||||
usage: 0,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const removedLimits = Object.keys(previousLimits).filter(key => !(key in newLimits))
|
||||
removedLimits.forEach(id => {
|
||||
newLimits[id] = {
|
||||
usage: previousLimits[id].usage ?? 0,
|
||||
}
|
||||
})
|
||||
set.limits = newLimits
|
||||
|
||||
})
|
||||
}
|
||||
if (ipPools) {
|
||||
set.ipPools = ipPools
|
||||
}
|
||||
@@ -339,16 +332,15 @@ export default class {
|
||||
forEach(limits, (quantity, id) => {
|
||||
const limit = set.limits[id]
|
||||
if (!limit) {
|
||||
set.limits[id] = { usage: quantity }
|
||||
return
|
||||
}
|
||||
|
||||
if ((limit.usage += quantity) > limit.total && !force) {
|
||||
if ((limit.available -= quantity) < 0 && !force) {
|
||||
throw notEnoughResources([
|
||||
{
|
||||
resourceSet: setId,
|
||||
resourceType: id,
|
||||
available: limit.total - (limit.usage - quantity),
|
||||
available: limit.available + quantity,
|
||||
requested: quantity,
|
||||
},
|
||||
])
|
||||
@@ -366,8 +358,8 @@ export default class {
|
||||
return
|
||||
}
|
||||
|
||||
if ((limit.usage -= quantity) < 0) {
|
||||
limit.usage = 0
|
||||
if ((limit.available += quantity) > limit.total) {
|
||||
limit.available = limit.total
|
||||
}
|
||||
})
|
||||
await this._save(set)
|
||||
@@ -379,7 +371,7 @@ export default class {
|
||||
forEach(limits, (limit, id) => {
|
||||
if (VM_RESOURCES[id] || id.startsWith('ipPool:')) {
|
||||
// only reset VMs related limits
|
||||
limit.usage = 0
|
||||
limit.available = limit.total
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -405,9 +397,7 @@ export default class {
|
||||
forEach(await this.computeResourcesUsage(this._app.getObject(object.$id)), (usage, resource) => {
|
||||
const limit = limits[resource]
|
||||
if (limit) {
|
||||
limit.usage += usage
|
||||
} else {
|
||||
limits[resource] = { usage }
|
||||
limit.available -= usage
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -31,10 +31,11 @@ export default class ResourceSetQuotas extends Component {
|
||||
|
||||
forEach(RESOURCES, resource => {
|
||||
if (limits[resource] != null) {
|
||||
const { total, usage } = limits[resource]
|
||||
const { available, total } = limits[resource]
|
||||
quotas[resource] = {
|
||||
available,
|
||||
total,
|
||||
usage,
|
||||
usage: total - available,
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -88,26 +89,22 @@ export default class ResourceSetQuotas extends Component {
|
||||
<CardBlock className='text-center'>
|
||||
{quota !== undefined ? (
|
||||
<div>
|
||||
{Number.isFinite(quota.total) ? (
|
||||
<ChartistGraph
|
||||
data={{
|
||||
labels,
|
||||
series: [quota.total - quota.usage, quota.usage],
|
||||
}}
|
||||
options={{
|
||||
donut: true,
|
||||
donutWidth: 40,
|
||||
showLabel: false,
|
||||
}}
|
||||
type='Pie'
|
||||
/>
|
||||
) : (
|
||||
<p className='text-xs-center display-1'>∞</p>
|
||||
)}
|
||||
<ChartistGraph
|
||||
data={{
|
||||
labels,
|
||||
series: [quota.available, quota.usage],
|
||||
}}
|
||||
options={{
|
||||
donut: true,
|
||||
donutWidth: 40,
|
||||
showLabel: false,
|
||||
}}
|
||||
type='Pie'
|
||||
/>
|
||||
<p className='text-xs-center'>
|
||||
{_('resourceSetQuota', {
|
||||
total: !Number.isFinite(quota.total) ? Infinity : formatSize(quota.total),
|
||||
usage: validFormat ? quota.usage?.toString() : formatSize(quota.usage),
|
||||
total: validFormat ? quota.total.toString() : formatSize(quota.total),
|
||||
usage: validFormat ? quota.usage.toString() : formatSize(quota.usage),
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1099,7 +1099,9 @@ export const SelectXoCloudConfig = makeSubscriptionSelect(
|
||||
subscriber =>
|
||||
subscribeCloudXoConfigBackups(configs => {
|
||||
const xoObjects = groupBy(
|
||||
map(configs, config => ({ ...config, type: 'xoConfig' })),
|
||||
map(configs, config => ({ ...config, type: 'xoConfig' }))
|
||||
// from newest to oldest
|
||||
.sort((a, b) => b.createdAt - a.createdAt),
|
||||
'xoaId'
|
||||
)
|
||||
subscriber({
|
||||
|
||||
@@ -1870,21 +1870,29 @@ export default class NewVm extends BaseComponent {
|
||||
{limits && (
|
||||
<Row>
|
||||
<Col size={3}>
|
||||
{cpusLimits?.total !== undefined && (
|
||||
<Limits limit={cpusLimits.total} toBeUsed={CPUs * factor} used={cpusLimits.usage} />
|
||||
{cpusLimits && (
|
||||
<Limits
|
||||
limit={cpusLimits.total}
|
||||
toBeUsed={CPUs * factor}
|
||||
used={cpusLimits.total - cpusLimits.available}
|
||||
/>
|
||||
)}
|
||||
</Col>
|
||||
<Col size={3}>
|
||||
{memoryLimits?.total !== undefined && (
|
||||
<Limits limit={memoryLimits.total} toBeUsed={_memory * factor} used={memoryLimits.usage} />
|
||||
{memoryLimits && (
|
||||
<Limits
|
||||
limit={memoryLimits.total}
|
||||
toBeUsed={_memory * factor}
|
||||
used={memoryLimits.total - memoryLimits.available}
|
||||
/>
|
||||
)}
|
||||
</Col>
|
||||
<Col size={3}>
|
||||
{diskLimits?.total !== undefined && (
|
||||
{diskLimits && (
|
||||
<Limits
|
||||
limit={diskLimits.total}
|
||||
toBeUsed={(sumBy(VDIs, 'size') + sum(map(existingDisks, disk => disk.size))) * factor}
|
||||
used={diskLimits.usage}
|
||||
used={diskLimits.total - diskLimits.available}
|
||||
/>
|
||||
)}
|
||||
</Col>
|
||||
@@ -1915,10 +1923,10 @@ export default class NewVm extends BaseComponent {
|
||||
const factor = multipleVms ? nameLabels.length : 1
|
||||
|
||||
return !(
|
||||
CPUs * factor > get(() => resourceSet.limits.cpus.total - resourceSet.limits.cpus.usage) ||
|
||||
_memory * factor > get(() => resourceSet.limits.memory.total - resourceSet.limits.memory.usage) ||
|
||||
CPUs * factor > get(() => resourceSet.limits.cpus.available) ||
|
||||
_memory * factor > get(() => resourceSet.limits.memory.available) ||
|
||||
(sumBy(VDIs, 'size') + sum(map(existingDisks, disk => disk.size))) * factor >
|
||||
get(() => resourceSet.limits.disk.total - resourceSet.limits.disk.usage)
|
||||
get(() => resourceSet.limits.disk.available)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,9 @@ import decorate from 'apply-decorators'
|
||||
import Icon from 'icon'
|
||||
import React from 'react'
|
||||
import { confirm } from 'modal'
|
||||
import { getApiApplianceInfo, subscribeCloudXoConfig, subscribeCloudXoConfigBackups } from 'xo'
|
||||
import { groupBy, sortBy } from 'lodash'
|
||||
import { injectState, provideState } from 'reaclette'
|
||||
import { SelectXoCloudConfig } from 'select-objects'
|
||||
import { subscribeCloudXoConfig, subscribeCloudXoConfigBackups } from 'xo'
|
||||
|
||||
import BackupXoConfigModal from './backup-xo-config-modal'
|
||||
import RestoreXoConfigModal from './restore-xo-config-modal'
|
||||
@@ -88,15 +87,7 @@ const CloudConfig = decorate([
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
applianceId: async () => {
|
||||
const { id } = await getApiApplianceInfo()
|
||||
return id
|
||||
},
|
||||
groupedConfigs: ({ applianceId, sortedConfigs }) =>
|
||||
sortBy(groupBy(sortedConfigs, 'xoaId'), config => (config[0].xoaId === applianceId ? -1 : 1)),
|
||||
isConfigDefined: ({ config }) => config != null,
|
||||
sortedConfigs: (_, { cloudXoConfigBackups }) =>
|
||||
cloudXoConfigBackups?.sort((config, nextConfig) => config.createdAt - nextConfig.createdAt),
|
||||
},
|
||||
}),
|
||||
injectState,
|
||||
|
||||
@@ -33,7 +33,7 @@ const formatError = error => (typeof error === 'string' ? error : JSON.stringify
|
||||
|
||||
const _changeUrlElement = (value, { remote, element }) =>
|
||||
editRemote(remote, {
|
||||
url: format({ ...remote, [element]: value === null ? undefined : value }),
|
||||
url: format({ ...parse(remote.url), [element]: value === null ? undefined : value }),
|
||||
})
|
||||
const _showError = remote => alert(_('remoteConnectionFailed'), <pre>{formatError(remote.error)}</pre>)
|
||||
const _editRemoteName = (name, { remote }) => editRemote(remote, { name })
|
||||
|
||||
Reference in New Issue
Block a user