Compare commits
33 Commits
xo-server-
...
xo-server-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abb65325b5 | ||
|
|
5757afa1d8 | ||
|
|
86e9b9c1b8 | ||
|
|
1cdd1fa00e | ||
|
|
9d12759c68 | ||
|
|
594341fab6 | ||
|
|
4e88125cbe | ||
|
|
13237180a2 | ||
|
|
f64d7e0b6e | ||
|
|
040a6930a4 | ||
|
|
c54b9189a6 | ||
|
|
8882f1b019 | ||
|
|
ae6416c4d2 | ||
|
|
8faed87656 | ||
|
|
0983f05969 | ||
|
|
d43e2544a1 | ||
|
|
ca83d11ac8 | ||
|
|
1cdcdd9b5f | ||
|
|
cc7806e35b | ||
|
|
0ee48b6623 | ||
|
|
8c02e0efbd | ||
|
|
34d3ca82bc | ||
|
|
43822d3667 | ||
|
|
f4ac73b3b4 | ||
|
|
f084b6def9 | ||
|
|
a00d101ff7 | ||
|
|
9d5900d9b6 | ||
|
|
28fb4e8216 | ||
|
|
bec4dbe652 | ||
|
|
72cc14f508 | ||
|
|
d20941cc2c | ||
|
|
9cb8a05316 | ||
|
|
dccd799f6d |
@@ -46,6 +46,7 @@
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepare": "yarn run build",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,5 +17,8 @@
|
||||
"dependencies": {
|
||||
"golike-defer": "^0.4.1",
|
||||
"xen-api": "^0.25.1"
|
||||
},
|
||||
"scripts": {
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run clean",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run clean",
|
||||
"prepare": "yarn run build"
|
||||
"prepare": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,6 +410,18 @@ export default class RemoteHandlerAbstract {
|
||||
await this._unlink(file).catch(ignoreEnoent)
|
||||
}
|
||||
|
||||
async write(
|
||||
file: File,
|
||||
buffer: Buffer,
|
||||
position: number
|
||||
): Promise<{| bytesWritten: number, buffer: Buffer |}> {
|
||||
await this._write(
|
||||
typeof file === 'string' ? normalizePath(file) : file,
|
||||
buffer,
|
||||
position
|
||||
)
|
||||
}
|
||||
|
||||
async writeFile(
|
||||
file: string,
|
||||
data: Data,
|
||||
@@ -546,6 +558,28 @@ export default class RemoteHandlerAbstract {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async _write(file: File, buffer: Buffer, position: number): Promise<void> {
|
||||
const isPath = typeof file === 'string'
|
||||
if (isPath) {
|
||||
file = await this.openFile(file, 'r+')
|
||||
}
|
||||
try {
|
||||
return await this._writeFd(file, buffer, position)
|
||||
} finally {
|
||||
if (isPath) {
|
||||
await this.closeFile(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async _writeFd(
|
||||
fd: FileDescriptor,
|
||||
buffer: Buffer,
|
||||
position: number
|
||||
): Promise<void> {
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
async _writeFile(
|
||||
file: string,
|
||||
data: Data,
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
import 'dotenv/config'
|
||||
import asyncIteratorToStream from 'async-iterator-to-stream'
|
||||
import getStream from 'get-stream'
|
||||
import { forOwn, random } from 'lodash'
|
||||
import { fromCallback } from 'promise-toolbox'
|
||||
import { pipeline } from 'readable-stream'
|
||||
import { random } from 'lodash'
|
||||
import { tmpdir } from 'os'
|
||||
|
||||
import { getHandler } from '.'
|
||||
@@ -310,5 +310,45 @@ handlers.forEach(url => {
|
||||
await handler.unlink('file')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#write()', () => {
|
||||
beforeEach(() => handler.outputFile('file', TEST_DATA))
|
||||
|
||||
const PATCH_DATA_LEN = Math.ceil(TEST_DATA_LEN / 2)
|
||||
const PATCH_DATA = unsecureRandomBytes(PATCH_DATA_LEN)
|
||||
|
||||
forOwn(
|
||||
{
|
||||
'dont increase file size': (() => {
|
||||
const offset = random(0, TEST_DATA_LEN - PATCH_DATA_LEN)
|
||||
|
||||
const expected = Buffer.from(TEST_DATA)
|
||||
PATCH_DATA.copy(expected, offset)
|
||||
|
||||
return { offset, expected }
|
||||
})(),
|
||||
'increase file size': (() => {
|
||||
const offset = random(
|
||||
TEST_DATA_LEN - PATCH_DATA_LEN + 1,
|
||||
TEST_DATA_LEN
|
||||
)
|
||||
|
||||
const expected = Buffer.alloc(offset + PATCH_DATA_LEN)
|
||||
TEST_DATA.copy(expected)
|
||||
PATCH_DATA.copy(expected, offset)
|
||||
|
||||
return { offset, expected }
|
||||
})(),
|
||||
},
|
||||
({ offset, expected }, title) => {
|
||||
describe(title, () => {
|
||||
testWithFileDescriptor('file', 'r+', async ({ file }) => {
|
||||
await handler.write(file, PATCH_DATA, offset)
|
||||
await expect(await handler.readFile('file')).toEqual(expected)
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -110,6 +110,10 @@ export default class LocalHandler extends RemoteHandlerAbstract {
|
||||
return fs.unlink(this._getFilePath(file))
|
||||
}
|
||||
|
||||
_writeFd(file, buffer, position) {
|
||||
return fs.write(file.fd, buffer, 0, buffer.length, position)
|
||||
}
|
||||
|
||||
_writeFile(file, data, { flags }) {
|
||||
return fs.writeFile(this._getFilePath(file), data, { flag: flags })
|
||||
}
|
||||
|
||||
@@ -159,6 +159,10 @@ export default class SmbHandler extends RemoteHandlerAbstract {
|
||||
return this._client.unlink(this._getFilePath(file)).catch(normalizeError)
|
||||
}
|
||||
|
||||
_writeFd(file, buffer, position) {
|
||||
return this._client.write(file.fd, buffer, 0, buffer.length, position)
|
||||
}
|
||||
|
||||
_writeFile(file, data, options) {
|
||||
return this._client
|
||||
.writeFile(this._getFilePath(file), data, options)
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
8
@xen-orchestra/multi-counter/index.js
Normal file
8
@xen-orchestra/multi-counter/index.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const handler = {
|
||||
get(target, property) {
|
||||
const value = target[property]
|
||||
return value !== undefined ? value : 0
|
||||
},
|
||||
}
|
||||
|
||||
export const create = () => new Proxy({ __proto__: null }, handler)
|
||||
14
@xen-orchestra/multi-counter/package.json
Normal file
14
@xen-orchestra/multi-counter/package.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "@xen-orchestra/multi-counter",
|
||||
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/@xen-orchestra/multi-counter",
|
||||
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",
|
||||
"repository": {
|
||||
"directory": "@xen-orchestra/multi-counter",
|
||||
"type": "git",
|
||||
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,6 +1,14 @@
|
||||
# ChangeLog
|
||||
|
||||
## **next** (2019-04-11)
|
||||
## **5.34.0** (2019-04-30)
|
||||
|
||||
### Highlights
|
||||
|
||||
- [Self/New VM] Add network config box to custom cloud-init [#3872](https://github.com/vatesfr/xen-orchestra/issues/3872) (PR [#4150](https://github.com/vatesfr/xen-orchestra/pull/4150))
|
||||
- [Metadata backup] Detailed logs [#4005](https://github.com/vatesfr/xen-orchestra/issues/4005) (PR [#4014](https://github.com/vatesfr/xen-orchestra/pull/4014))
|
||||
- [Backup reports] Support metadata backups (PR [#4084](https://github.com/vatesfr/xen-orchestra/pull/4084))
|
||||
- [VM migration] Auto select default SR and collapse optional actions [#3326](https://github.com/vatesfr/xen-orchestra/issues/3326) (PR [#4121](https://github.com/vatesfr/xen-orchestra/pull/4121))
|
||||
- Unlock basic stats on all editions [#4166](https://github.com/vatesfr/xen-orchestra/issues/4166) (PR [#4172](https://github.com/vatesfr/xen-orchestra/pull/4172))
|
||||
|
||||
### Enhancements
|
||||
|
||||
@@ -9,8 +17,11 @@
|
||||
- [Import] Avoid blocking the UI when dropping a big OVA file on the UI (PR [#4018](https://github.com/vatesfr/xen-orchestra/pull/4018))
|
||||
- [Backup NG/Overview] Make backup list title clearer [#4111](https://github.com/vatesfr/xen-orchestra/issues/4111) (PR [#4129](https://github.com/vatesfr/xen-orchestra/pull/4129))
|
||||
- [Dashboard] Hide "Report" section for non-admins [#4123](https://github.com/vatesfr/xen-orchestra/issues/4123) (PR [#4126](https://github.com/vatesfr/xen-orchestra/pull/4126))
|
||||
- [VM migration] Auto select default SR and collapse optional actions [#3326](https://github.com/vatesfr/xen-orchestra/issues/3326) (PR [#4121](https://github.com/vatesfr/xen-orchestra/pull/4121))
|
||||
- [Metadata backup] Logs [#4005](https://github.com/vatesfr/xen-orchestra/issues/4005) (PR [#4014](https://github.com/vatesfr/xen-orchestra/pull/4014))
|
||||
- [Self/New VM] Display confirmation modal when user will use a large amount of resources [#4044](https://github.com/vatesfr/xen-orchestra/issues/4044) (PR [#4127](https://github.com/vatesfr/xen-orchestra/pull/4127))
|
||||
- [VDI migration, New disk] Warning when SR host is different from the other disks [#3911](https://github.com/vatesfr/xen-orchestra/issues/3911) (PR [#4035](https://github.com/vatesfr/xen-orchestra/pull/4035))
|
||||
- [Attach disk] Display warning message when VDI SR is on different host from the other disks [#3911](https://github.com/vatesfr/xen-orchestra/issues/3911) (PR [#4117](https://github.com/vatesfr/xen-orchestra/pull/4117))
|
||||
- [Editable] Notify user when editable undo fails [#3799](https://github.com/vatesfr/xen-orchestra/issues/3799) (PR [#4150](https://github.com/vatesfr/xen-orchestra/pull/4157))
|
||||
- [XO] Add banner for sources users to clarify support conditions [#4165](https://github.com/vatesfr/xen-orchestra/issues/4165) (PR [#4167](https://github.com/vatesfr/xen-orchestra/pull/4167))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
@@ -18,13 +29,17 @@
|
||||
- [Backup NG] Only display full backup interval in case of a delta backup (PR [#4125](https://github.com/vatesfr/xen-orchestra/pull/4107))
|
||||
- [Dashboard/Health] fix 'an error has occurred' on the storage state table [#4128](https://github.com/vatesfr/xen-orchestra/issues/4128) (PR [#4132](https://github.com/vatesfr/xen-orchestra/pull/4132))
|
||||
- [Menu] XOA: Fixed empty slot when menu is collapsed [#4012](https://github.com/vatesfr/xen-orchestra/issues/4012) (PR [#4068](https://github.com/vatesfr/xen-orchestra/pull/4068)
|
||||
- [Self/New VM] Fix missing templates when refreshing page [#3265](https://github.com/vatesfr/xen-orchestra/issues/3265) (PR [#3565](https://github.com/vatesfr/xen-orchestra/pull/3565))
|
||||
- [Home] No more false positives when select Tag on Home page [#4087](https://github.com/vatesfr/xen-orchestra/issues/4087) (PR [#4112](https://github.com/vatesfr/xen-orchestra/pull/4112))
|
||||
|
||||
### Released packages
|
||||
|
||||
- xo-server-backup-reports v0.16.0
|
||||
- complex-matcher v0.6.0
|
||||
- xo-vmdk-to-vhd v0.1.7
|
||||
- vhd-lib v0.6.1
|
||||
- xo-server v5.39.0
|
||||
- xo-web v5.39.1
|
||||
- xo-server v5.40.0
|
||||
- xo-web v5.40.1
|
||||
|
||||
## **5.33.1** (2019-04-04)
|
||||
|
||||
|
||||
@@ -2,21 +2,16 @@
|
||||
|
||||
### Enhancements
|
||||
|
||||
- [Self/New VM] Display confirmation modal when user will use a large amount of resources [#4044](https://github.com/vatesfr/xen-orchestra/issues/4044) (PR [#4127](https://github.com/vatesfr/xen-orchestra/pull/4127))
|
||||
- [Home] No more false positives when select Tag on Home page [#4087](https://github.com/vatesfr/xen-orchestra/issues/4087) (PR [#4112](https://github.com/vatesfr/xen-orchestra/pull/4112))
|
||||
- [VDI migration, New disk] Warning when SR host is different from the other disks [#3911](https://github.com/vatesfr/xen-orchestra/issues/3911) (PR [#4035](https://github.com/vatesfr/xen-orchestra/pull/4035))
|
||||
- [Backup reports] Support metadata backups (PR [#4084](https://github.com/vatesfr/xen-orchestra/pull/4084))
|
||||
- [Attach disk] Display warning message when VDI SR is on different host from the other disks [#3911](https://github.com/vatesfr/xen-orchestra/issues/3911) (PR [#4117](https://github.com/vatesfr/xen-orchestra/pull/4117))
|
||||
- [Self/New VM] Add network config box to custom cloud-init [#3872](https://github.com/vatesfr/xen-orchestra/issues/3872) (PR [#4150](https://github.com/vatesfr/xen-orchestra/pull/4150))
|
||||
- [Editable] Notify user when editable undo fails [#3799](https://github.com/vatesfr/xen-orchestra/issues/3799) (PR [#4150](https://github.com/vatesfr/xen-orchestra/pull/4157))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- [Self/New VM] Fix missing templates when refreshing page [#3265](https://github.com/vatesfr/xen-orchestra/issues/3265) (PR [#3565](https://github.com/vatesfr/xen-orchestra/pull/3565))
|
||||
- [Pool/Patches] Fix "an error has occurred" in "Applied patches" [#4192](https://github.com/vatesfr/xen-orchestra/issues/4192) (PR [#4193](https://github.com/vatesfr/xen-orchestra/pull/4193))
|
||||
- [Backup NG] Fix report sent even though "Never" is selected [#4092](https://github.com/vatesfr/xen-orchestra/issues/4092) (PR [#4178](https://github.com/vatesfr/xen-orchestra/pull/4178))
|
||||
- [Remotes] Fix issues after a config import (PR [#4197](https://github.com/vatesfr/xen-orchestra/pull/4197))
|
||||
|
||||
### Released packages
|
||||
|
||||
- xo-server-backup-reports v0.16.0
|
||||
- complex-matcher v0.6.0
|
||||
- xo-server v5.40.0
|
||||
- xo-web v5.40.0
|
||||
- xo-server-backup-reports v0.16.1
|
||||
- @xen-orchestra/fs v0.9.0
|
||||
- vhd-lib v0.7.0
|
||||
- xo-server v5.41.0
|
||||
- xo-web v5.41.0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Xen Orchestra [](https://go.crisp.im/chat/embed/?website_id=-JzqzzwddSV7bKGtEyAQ) [](https://travis-ci.org/vatesfr/xen-orchestra)
|
||||
# Xen Orchestra [](https://travis-ci.org/vatesfr/xen-orchestra)
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
|
||||
# Installation
|
||||
|
||||
SSH to your XenServer and execute the following:
|
||||
SSH to your XenServer/XCP-ng host and execute the following:
|
||||
|
||||
```
|
||||
bash -c "$(curl -s http://xoa.io/deploy)"
|
||||
```
|
||||
|
||||
This will automatically download/import/start the XOA appliance. Nothing is changed on your XenServer host itself, it's 100% safe.
|
||||
This will automatically download/import/start the XOA appliance. Nothing is changed on your host itself, it's 100% safe.
|
||||
|
||||
## [More on XOA](xoa.md)
|
||||
|
||||
|
||||
@@ -1,24 +1,33 @@
|
||||
# Support
|
||||
|
||||
You can access our pro support if you subscribe to any of these plans:
|
||||
Xen Orchestra will run in a controlled/tested environment thanks to XOA ([Xen Orchestra virtual Appliance](https://xen-orchestra.com/#!/xoa)). **This is the way to get pro support**. Any account with a registered XOA can access a [dedicated support panel](https://xen-orchestra.com/#!/member/support).
|
||||
|
||||
XOA is available in multiple plans:
|
||||
|
||||
* Free
|
||||
* Starter
|
||||
* Enterprise
|
||||
* Premium
|
||||
|
||||
The better the plan, the faster the support will be with higher priority.
|
||||
Higher tier support plans include faster ticket response times (and cover more features). Paid support plans and response times are based on the plan you have, plans can be [reviewed here](https://xen-orchestra.com/#!/xo-pricing).
|
||||
|
||||
## XOA Free support
|
||||
|
||||
With the free version of the Xen Orchestra Appliance (XOA free), you can open support tickets and we will do our best to assist you, however, this support is limited and is not guaranteed in regards to response times or resolutions offered.
|
||||
|
||||
## Community support
|
||||
|
||||
If you are using Xen Orchestra via the sources, you can ask questions and try to recieve help two different ways:
|
||||
If you are using Xen Orchestra via the source and not XOA, you can ask questions and try to recieve help through a number of different ways:
|
||||
|
||||
* In our [forum](https://xen-orchestra.com/forum/)
|
||||
* In our [forum](https://xcp-ng.org/forum/category/12/xen-orchestra)
|
||||
* In our IRC - `#xen-orchestra` on `Freenode`
|
||||
|
||||
However, there's no guarantee you will receive an answer and no guaranteed response time. If you are using XO from sources, we encourage you to give back to the community by assisting other users via these two avenues as well.
|
||||
We encourage you to give back to the community by assisting other users via these two avenues as well.
|
||||
|
||||
If you are using Xen Orchestra in production, please subscribe to a plan.
|
||||
Lastly while Xen Orchestra is free and Open Source software, supporting and developing it takes a lot of effort. If you are considering using Xen Orchestra in production, please subscribe for one of our [professional support plans](https://xen-orchestra.com/#!/xo-pricing).
|
||||
|
||||
> Note: support from the sources is harder, because Xen Orchestra can potentially run on any Linux distro (or even FreeBSD and Windows!). Always try to double check that you followed our guide on how to [install it from the sources](https://xen-orchestra.com/docs/from_the_sources.html) before going further.
|
||||
|
||||
## Open a ticket
|
||||
|
||||
If you have a subscription, you can open a ticket describing your issue directly from your personal account page [here](https://xen-orchestra.com/#!/member/support)
|
||||
If you have a subscription (or at least a registered free XOA), you can open a ticket describing your issue directly from your personal account page [here](https://xen-orchestra.com/#!/member/support)
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
"eslint-plugin-react": "^7.6.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"exec-promise": "^0.7.0",
|
||||
"flow-bin": "^0.97.0",
|
||||
"flow-bin": "^0.98.0",
|
||||
"globby": "^9.0.0",
|
||||
"husky": "^1.2.1",
|
||||
"husky": "^2.2.0",
|
||||
"jest": "^24.1.0",
|
||||
"lodash": "^4.17.4",
|
||||
"prettier": "^1.10.2",
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepare": "yarn run build",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "rimraf dist/ && index-modules --cjs-lazy src/commands",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepare": "yarn run build"
|
||||
"prepare": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run clean",
|
||||
"prepare": "yarn run build"
|
||||
"prepare": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import assert from 'assert'
|
||||
import { fromEvent } from 'promise-toolbox'
|
||||
|
||||
import checkFooter from './_checkFooter'
|
||||
import checkHeader from './_checkHeader'
|
||||
import constantStream from './_constant-stream'
|
||||
import getFirstAndLastBlocks from './_getFirstAndLastBlocks'
|
||||
import { fuFooter, fuHeader, checksumStruct, unpackField } from './_structs'
|
||||
import { set as mapSetBit, test as mapTestBit } from './_bitmap'
|
||||
@@ -232,24 +230,11 @@ export default class Vhd {
|
||||
// Write functions.
|
||||
// =================================================================
|
||||
|
||||
// Write a buffer/stream at a given position in a vhd file.
|
||||
// Write a buffer at a given position in a vhd file.
|
||||
async _write(data, offset) {
|
||||
debug(
|
||||
`_write offset=${offset} size=${
|
||||
Buffer.isBuffer(data) ? data.length : '???'
|
||||
}`
|
||||
)
|
||||
// TODO: could probably be merged in remote handlers.
|
||||
const stream = await this._handler.createOutputStream(this._path, {
|
||||
flags: 'r+',
|
||||
start: offset,
|
||||
})
|
||||
return Buffer.isBuffer(data)
|
||||
? new Promise((resolve, reject) => {
|
||||
stream.on('error', reject)
|
||||
stream.end(data, resolve)
|
||||
})
|
||||
: fromEvent(data.pipe(stream), 'finish')
|
||||
assert(Buffer.isBuffer(data))
|
||||
debug(`_write offset=${offset} size=${data.length}`)
|
||||
return this._handler.write(this._path, data, offset)
|
||||
}
|
||||
|
||||
async _freeFirstBlockSpace(spaceNeededBytes) {
|
||||
@@ -306,7 +291,7 @@ export default class Vhd {
|
||||
`ensureBatSize: extend BAT ${prevMaxTableEntries} -> ${maxTableEntries}`
|
||||
)
|
||||
await this._write(
|
||||
constantStream(BUF_BLOCK_UNUSED, maxTableEntries - prevMaxTableEntries),
|
||||
Buffer.alloc(maxTableEntries - prevMaxTableEntries, BUF_BLOCK_UNUSED),
|
||||
header.tableOffset + prevBat.length
|
||||
)
|
||||
await this.writeHeader()
|
||||
@@ -331,10 +316,7 @@ export default class Vhd {
|
||||
|
||||
await Promise.all([
|
||||
// Write an empty block and addr in vhd file.
|
||||
this._write(
|
||||
constantStream([0], this.fullBlockSize),
|
||||
sectorsToBytes(blockAddr)
|
||||
),
|
||||
this._write(Buffer.alloc(this.fullBlockSize), sectorsToBytes(blockAddr)),
|
||||
|
||||
this._setBatEntry(blockId, blockAddr),
|
||||
])
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
"plot": "gnuplot -p memory-test.gnu",
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,5 +25,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"xo-common": "^0.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
"lint": "tslint 'src/*.ts'",
|
||||
"posttest": "yarn run lint",
|
||||
"prepublishOnly": "yarn run build",
|
||||
"start": "node dist/index.js"
|
||||
"start": "node dist/index.js",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"node": ">=6"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsonrpc-websocket-client": "^0.4.1",
|
||||
"jsonrpc-websocket-client": "^0.5.0",
|
||||
"lodash": "^4.17.2",
|
||||
"make-error": "^1.0.4"
|
||||
},
|
||||
@@ -49,6 +49,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepare": "yarn run build"
|
||||
"prepare": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,5 +41,6 @@
|
||||
"build": "NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
|
||||
"dev": "NODE_DEV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -49,5 +49,6 @@
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -55,5 +55,6 @@
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -50,5 +50,6 @@
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -58,5 +58,6 @@
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -245,6 +245,9 @@ class BackupReportsXoPlugin {
|
||||
if (
|
||||
!force &&
|
||||
(reportWhen === 'never' ||
|
||||
// Handle improper value introduced by:
|
||||
// https://github.com/vatesfr/xen-orchestra/commit/753ee994f2948bbaca9d3161eaab82329a682773#diff-9c044ab8a42ed6576ea927a64c1ec3ebR105
|
||||
reportWhen === 'Never' ||
|
||||
(reportWhen === 'failure' && log.status === 'success'))
|
||||
) {
|
||||
return
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"http-request-plus": "^0.8.0",
|
||||
"jsonrpc-websocket-client": "^0.4.1"
|
||||
"jsonrpc-websocket-client": "^0.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.0.0",
|
||||
@@ -49,5 +49,6 @@
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -44,5 +44,6 @@
|
||||
"build": "NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
|
||||
"dev": "NODE_DEV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -42,5 +42,6 @@
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -50,5 +50,6 @@
|
||||
"prebuild": "rimraf dist/",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -49,5 +49,6 @@
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -50,5 +50,6 @@
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -50,5 +50,6 @@
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -59,5 +59,6 @@
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run prebuild",
|
||||
"prepublishOnly": "yarn run build"
|
||||
}
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "xo-server",
|
||||
"version": "5.40.0",
|
||||
"license": "AGPL-3.0",
|
||||
@@ -91,6 +92,7 @@
|
||||
"make-error": "^1",
|
||||
"micromatch": "^3.1.4",
|
||||
"minimist": "^1.2.0",
|
||||
"mnemonist": "^0.27.2",
|
||||
"moment-timezone": "^0.5.14",
|
||||
"ms": "^2.1.1",
|
||||
"multikey-hash": "^1.0.4",
|
||||
@@ -109,7 +111,7 @@
|
||||
"readable-stream": "^3.2.0",
|
||||
"redis": "^2.8.0",
|
||||
"schema-inspector": "^1.6.8",
|
||||
"semver": "^5.4.1",
|
||||
"semver": "^6.0.0",
|
||||
"serve-static": "^1.13.1",
|
||||
"split-lines": "^2.0.0",
|
||||
"stack-chain": "^2.0.0",
|
||||
|
||||
5
packages/xo-server/src/_XenStore.js
Normal file
5
packages/xo-server/src/_XenStore.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import fromCallback from 'promise-toolbox/fromCallback'
|
||||
import { execFile } from 'child_process'
|
||||
|
||||
export const read = key =>
|
||||
fromCallback(cb => execFile('xenstore-read', [key], cb))
|
||||
@@ -1,6 +1,6 @@
|
||||
import createLogger from '@xen-orchestra/log'
|
||||
import pump from 'pump'
|
||||
import { format } from 'json-rpc-peer'
|
||||
import { format, JsonRpcError } from 'json-rpc-peer'
|
||||
import { noSuchObject } from 'xo-common/api-errors'
|
||||
|
||||
import { parseSize } from '../utils'
|
||||
@@ -128,7 +128,7 @@ async function handleImportContent(req, res, { xapi, id }) {
|
||||
res.end(format.response(0, true))
|
||||
} catch (e) {
|
||||
res.writeHead(500)
|
||||
res.end(format.error(0, new Error(e.message)))
|
||||
res.end(format.error(0, new JsonRpcError(e.message)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { format } from 'json-rpc-peer'
|
||||
import { format, JsonRpcError } from 'json-rpc-peer'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
@@ -248,7 +248,7 @@ async function handleInstallSupplementalPack(req, res, { hostId }) {
|
||||
res.end(format.response(0))
|
||||
} catch (e) {
|
||||
res.writeHead(500)
|
||||
res.end(format.error(0, new Error(e.message)))
|
||||
res.end(format.error(0, new JsonRpcError(e.message)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { format } from 'json-rpc-peer'
|
||||
import { format, JsonRPcError } from 'json-rpc-peer'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
@@ -234,7 +234,7 @@ async function handleInstallSupplementalPack(req, res, { poolId }) {
|
||||
res.end(format.response(0))
|
||||
} catch (e) {
|
||||
res.writeHead(500)
|
||||
res.end(format.error(0, new Error(e.message)))
|
||||
res.end(format.error(0, new JsonRPcError(e.message)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import defer from 'golike-defer'
|
||||
import { format } from 'json-rpc-peer'
|
||||
import { format, JsonRpcError } from 'json-rpc-peer'
|
||||
import { ignoreErrors } from 'promise-toolbox'
|
||||
import { assignWith, concat } from 'lodash'
|
||||
import {
|
||||
@@ -1203,7 +1203,7 @@ async function handleVmImport(req, res, { data, srId, type, xapi }) {
|
||||
res.end(format.response(0, vm.$id))
|
||||
} catch (e) {
|
||||
res.writeHead(500)
|
||||
res.end(format.error(0, new Error(e.message)))
|
||||
res.end(format.error(0, new JsonRpcError(e.message)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -417,6 +417,7 @@ const setUpProxies = (express, opts, xo) => {
|
||||
}
|
||||
|
||||
const proxy = createProxyServer({
|
||||
changeOrigin: true,
|
||||
ignorePath: true,
|
||||
}).on('error', error => console.error(error))
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ import Collection from '../collection/redis'
|
||||
import Model from '../model'
|
||||
import { forEach } from '../utils'
|
||||
|
||||
import { parseProp } from './utils'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
export default class Remote extends Model {}
|
||||
@@ -14,12 +16,21 @@ export class Remotes extends Collection {
|
||||
async get(properties) {
|
||||
const remotes = await super.get(properties)
|
||||
forEach(remotes, remote => {
|
||||
remote.benchmarks =
|
||||
remote.benchmarks !== undefined
|
||||
? JSON.parse(remote.benchmarks)
|
||||
: undefined
|
||||
remote.benchmarks = parseProp('remote', remote, 'benchmarks')
|
||||
remote.enabled = remote.enabled === 'true'
|
||||
})
|
||||
return remotes
|
||||
}
|
||||
|
||||
_update(remotes) {
|
||||
return super._update(
|
||||
remotes.map(remote => {
|
||||
const { benchmarks } = remote
|
||||
if (benchmarks !== undefined) {
|
||||
remote.benchmarks = JSON.stringify(benchmarks)
|
||||
}
|
||||
return remote
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -633,7 +633,7 @@ const TRANSFORMS = {
|
||||
description: poolPatch.name_description,
|
||||
name: poolPatch.name_label,
|
||||
pool_patch: poolPatch.$ref,
|
||||
size: poolPatch.size,
|
||||
size: +poolPatch.size,
|
||||
guidance: poolPatch.after_apply_guidance,
|
||||
time: toTimestamp(obj.timestamp_applied),
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import * as MultiCounter from '@xen-orchestra/multi-counter'
|
||||
import aclResolver from 'xo-acl-resolver'
|
||||
import { forEach, includes, map } from 'lodash'
|
||||
|
||||
@@ -6,9 +7,11 @@ import { Acls } from '../models/acl'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// TODO add cache per user
|
||||
export default class {
|
||||
constructor(xo) {
|
||||
this._xo = xo
|
||||
this._cacheByObjectByUser = { __proto__: null }
|
||||
|
||||
const aclsDb = (this._acls = new Acls({
|
||||
connection: xo._redis,
|
||||
@@ -16,6 +19,20 @@ export default class {
|
||||
indexes: ['subject', 'object'],
|
||||
}))
|
||||
|
||||
const nSessionsByUser = MultiCounter.create()
|
||||
xo.on('session.open', session => {
|
||||
const userId = session.get('user_id')
|
||||
if (nSessionsByUser[userId]++ === 0) {
|
||||
this._cacheByObjectByUser[userId] = { __proto__: null }
|
||||
}
|
||||
})
|
||||
xo.on('session.close', session => {
|
||||
const userId = session.get('user_id')
|
||||
if (--nSessionsByUser[userId] === 0) {
|
||||
delete this._cacheByObjectByUser[userId]
|
||||
}
|
||||
})
|
||||
|
||||
xo.on('start', () => {
|
||||
xo.addConfigManager(
|
||||
'acls',
|
||||
|
||||
@@ -168,7 +168,7 @@ export default class {
|
||||
}
|
||||
|
||||
@synchronized()
|
||||
async _updateRemote(id, { benchmarks, url, ...props }) {
|
||||
async _updateRemote(id, { url, ...props }) {
|
||||
const remote = await this._getRemote(id)
|
||||
|
||||
// url is handled separately to take care of obfuscated values
|
||||
@@ -176,13 +176,6 @@ export default class {
|
||||
remote.url = format(sensitiveValues.merge(parse(url), parse(remote.url)))
|
||||
}
|
||||
|
||||
if (
|
||||
benchmarks !== undefined ||
|
||||
(benchmarks = remote.benchmarks) !== undefined
|
||||
) {
|
||||
remote.benchmarks = JSON.stringify(benchmarks)
|
||||
}
|
||||
|
||||
patch(remote, props)
|
||||
|
||||
return (await this._remotes.update(remote)).properties
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ignoreErrors } from 'promise-toolbox'
|
||||
import { hash, needsRehash, verify } from 'hashy'
|
||||
import { invalidCredentials, noSuchObject } from 'xo-common/api-errors'
|
||||
|
||||
import * as XenStore from '../_XenStore'
|
||||
import { Groups } from '../models/group'
|
||||
import { Users } from '../models/user'
|
||||
import { forEach, isEmpty, lightSet, mapToArray } from '../utils'
|
||||
@@ -68,8 +69,12 @@ export default class {
|
||||
)
|
||||
|
||||
if (!(await usersDb.exists())) {
|
||||
const email = 'admin@admin.net'
|
||||
const password = 'admin'
|
||||
const {
|
||||
email = 'admin@admin.net',
|
||||
password = 'admin',
|
||||
} = await XenStore.read('vm-data/admin-account')
|
||||
.then(JSON.parse)
|
||||
.catch(() => ({}))
|
||||
|
||||
await this.createUser({ email, password, permission: 'admin' })
|
||||
log.info(`Default user created: ${email} with password ${password}`)
|
||||
|
||||
75
packages/xo-server/src/xo-mixins/subscriptions.js
Normal file
75
packages/xo-server/src/xo-mixins/subscriptions.js
Normal file
@@ -0,0 +1,75 @@
|
||||
import BloomFilter from 'mnemonist/bloom-filter'
|
||||
import forOwn from 'lodash/forOwn'
|
||||
import iteratee from 'lodash/iteratee'
|
||||
|
||||
const BLOOM_FILTER_CAPACITY = 50
|
||||
|
||||
export default class Subscriptions {
|
||||
constructor(app) {
|
||||
this._app = app
|
||||
|
||||
this._permCacheByUser = { __proto__: null }
|
||||
this._objCacheBySession = { __proto__: null }
|
||||
this._predicatesBySession = { __proto__: null }
|
||||
}
|
||||
|
||||
async subscribe(sessionId, userId, filter) {
|
||||
const predicatesBySession = this._predicatesBySession
|
||||
const predicates =
|
||||
predicatesBySession[sessionId] ??
|
||||
(predicatesBySession[sessionId] = { __proto__: null })
|
||||
|
||||
const subscriptionId = Math.random()
|
||||
.toString(36)
|
||||
.slice(2)
|
||||
const predicate = iteratee(filter)
|
||||
predicates[subscriptionId] = predicate
|
||||
|
||||
const objCacheBySession = this._objCacheBySession
|
||||
const objCache =
|
||||
objCacheBySession[sessionId] ??
|
||||
(objCacheBySession[sessionId] = { __proto__: null })
|
||||
|
||||
const objects = this.getObjects()
|
||||
const ids = Object.keys(objects)
|
||||
await Promise.all(
|
||||
ids.map(async id => {
|
||||
if (!(await this.hasPermissions(userId, [[id, 'view']]))) {
|
||||
// user cannot see this object
|
||||
return
|
||||
}
|
||||
|
||||
const cache =
|
||||
objCache[id] ??
|
||||
(objCache[id] = new BloomFilter(BLOOM_FILTER_CAPACITY))
|
||||
cache.add(subscriptionId)
|
||||
})
|
||||
)
|
||||
|
||||
return subscriptionId
|
||||
}
|
||||
|
||||
unsubscribe(sessionId, userId, subscriptionId) {
|
||||
const predicates = this._predicatesBySession[sessionId]
|
||||
if (predicates === undefined || !(subscriptionId in predicates)) {
|
||||
return
|
||||
}
|
||||
delete predicates[subscriptionId]
|
||||
|
||||
const objCache = this._objCacheBySession[sessionId]
|
||||
forOwn(objCache, (cache, id) => {
|
||||
if (!cache.test(subscriptionId)) {
|
||||
// not handled by this subscription
|
||||
return
|
||||
}
|
||||
|
||||
const object = this.getObject(id)
|
||||
cache = objCache[id] = new BloomFilter(BLOOM_FILTER_CAPACITY)
|
||||
forOwn(predicates, (predicate, subscriptionId) => {
|
||||
if (predicate(object)) {
|
||||
cache.add(subscriptionId)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { fibonacci } from 'iterable-backoff'
|
||||
import { noSuchObject } from 'xo-common/api-errors'
|
||||
import { pDelay, ignoreErrors } from 'promise-toolbox'
|
||||
|
||||
import * as XenStore from '../_XenStore'
|
||||
import Xapi from '../xapi'
|
||||
import xapiObjectToXo from '../xapi-object-to-xo'
|
||||
import XapiStats from '../xapi-stats'
|
||||
@@ -64,8 +65,19 @@ export default class {
|
||||
servers => serversDb.update(servers)
|
||||
)
|
||||
|
||||
// Connects to existing servers.
|
||||
const servers = await serversDb.get()
|
||||
|
||||
// Add servers in XenStore
|
||||
if (servers.length === 0) {
|
||||
const xenStoreServers = await XenStore.read('vm-data/xen-servers')
|
||||
.then(JSON.parse)
|
||||
.catch(() => [])
|
||||
for (const server of xenStoreServers) {
|
||||
servers.push(await this.registerXenServer(server))
|
||||
}
|
||||
}
|
||||
|
||||
// Connects to existing servers.
|
||||
for (const server of servers) {
|
||||
if (server.enabled) {
|
||||
this.connectXenServer(server.id).catch(error => {
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
||||
"prebuild": "yarn run clean",
|
||||
"predev": "yarn run clean",
|
||||
"prepare": "yarn run build"
|
||||
"prepare": "yarn run build",
|
||||
"postversion": "npm publish"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": false,
|
||||
"private": true,
|
||||
"name": "xo-web",
|
||||
"version": "5.39.1",
|
||||
"version": "5.40.1",
|
||||
"license": "AGPL-3.0",
|
||||
"description": "Web interface client for Xen-Orchestra",
|
||||
"keywords": [
|
||||
@@ -100,7 +100,7 @@
|
||||
"prop-types": "^15.6.0",
|
||||
"qrcode": "^1.3.2",
|
||||
"random-password": "^0.1.2",
|
||||
"reaclette": "^0.7.0",
|
||||
"reaclette": "^0.8.0",
|
||||
"react": "^15.4.1",
|
||||
"react-addons-shallow-compare": "^15.6.2",
|
||||
"react-addons-test-utils": "^15.6.2",
|
||||
|
||||
@@ -87,3 +87,5 @@ export const DEFAULT_NETWORK_CONFIG_TEMPLATE = `#network:
|
||||
# name: eth0
|
||||
# subnets:
|
||||
# - type: dhcp`
|
||||
|
||||
export const CAN_CLOUD_INIT = +process.env.XOA_PLAN > 3
|
||||
|
||||
@@ -3411,7 +3411,7 @@ export default {
|
||||
|
||||
// Original text: "This version is not bundled with any support nor updates. Use it with caution for critical tasks."
|
||||
disclaimerText3:
|
||||
'Esta versión no está creada para recibir soporte ni actualizaciones. Úsala con precaución para tareas críticas.',
|
||||
'Esta versión no está creada para recibir soporte ni actualizaciones. Úsala con precaución.',
|
||||
|
||||
// Original text: "Connect PIF"
|
||||
connectPif: 'Conectar PIF',
|
||||
|
||||
@@ -3497,7 +3497,7 @@ export default {
|
||||
|
||||
// Original text: "This version is not bundled with any support nor updates. Use it with caution for critical tasks."
|
||||
disclaimerText3:
|
||||
"Cette version n'est fournie avec aucun support ni aucune mise à jour. Soyez prudent en cas d'utilisation pour des tâches importantes.",
|
||||
"Cette version n'est fournie avec aucun support ni aucune mise à jour. Utilisez-la avec précaution.",
|
||||
|
||||
// Original text: "Connect PIF"
|
||||
connectPif: 'Connecter la PIF',
|
||||
|
||||
@@ -3248,7 +3248,7 @@ export default {
|
||||
|
||||
// Original text: "This version is not bundled with any support nor updates. Use it with caution for critical tasks."
|
||||
disclaimerText3:
|
||||
'This Verzió is not bundled with any support nor upDates. Use it with caution for critical tasks.',
|
||||
'This Verzió is not bundled with any support nor upDates. Use it with caution.',
|
||||
|
||||
// Original text: "Connect PIF"
|
||||
connectPif: 'Csatlakozás PIF',
|
||||
|
||||
@@ -2958,7 +2958,7 @@ export default {
|
||||
|
||||
// Original text: "This version is not bundled with any support nor updates. Use it with caution for critical tasks."
|
||||
disclaimerText3:
|
||||
'This version is not bundled with any support nor updates. Use it with caution for critical tasks.',
|
||||
'This version is not bundled with any support nor updates. Use it with caution.',
|
||||
|
||||
// Original text: "Connect PIF"
|
||||
connectPif: 'Connect PIF',
|
||||
|
||||
@@ -2944,7 +2944,7 @@ export default {
|
||||
|
||||
// Original text: "This version is not bundled with any support nor updates. Use it with caution for critical tasks."
|
||||
disclaimerText3:
|
||||
'Esta versão não está vinculada a qualquer tipo de suporte nem atualizações. Use-a com cuidado em se tratando de tarefas críticas.',
|
||||
'Esta versão não está vinculada a qualquer tipo de suporte nem atualizações. Use-a com cuidado.',
|
||||
|
||||
// Original text: "Connect PIF"
|
||||
connectPif: 'Conectar PIF',
|
||||
|
||||
@@ -4294,7 +4294,7 @@ export default {
|
||||
|
||||
// Original text: "This version is not bundled with any support nor updates. Use it with caution for critical tasks."
|
||||
disclaimerText3:
|
||||
'Bu sürüm herhangi bir destek veya güncellemeyle birlikte verilmez. Kritik görevler için dikkatli kullanın.',
|
||||
'Bu sürüm herhangi bir destek veya güncellemeyle birlikte verilmez. Dikkatli kullanın.',
|
||||
|
||||
// Original text: "Connect PIF"
|
||||
connectPif: "PIF'e bağlan",
|
||||
|
||||
@@ -2236,7 +2236,7 @@ export default {
|
||||
disclaimerText2: '如果你是一个公司,建议使用我们的设备结合专业的支持',
|
||||
|
||||
// Original text: "This version is not bundled with any support nor updates. Use it with caution for critical tasks."
|
||||
disclaimerText3: '这个版本没有绑定任何支持或更新,在紧急任务下,请谨慎使用',
|
||||
disclaimerText3: '这个版本没有绑定任何支持或更新,请谨慎使用',
|
||||
|
||||
// Original text: "Connect PIF"
|
||||
connectPif: '连接物理网卡',
|
||||
|
||||
@@ -1321,6 +1321,7 @@ const messages = {
|
||||
newVmSshKey: 'SSH key',
|
||||
noConfigDrive: 'No config drive',
|
||||
newVmCustomConfig: 'Custom config',
|
||||
premiumOnly: 'Only available in Premium',
|
||||
availableTemplateVarsInfo:
|
||||
'Click here to see the available template variables',
|
||||
availableTemplateVarsTitle: 'Available template variables',
|
||||
@@ -1868,7 +1869,7 @@ const messages = {
|
||||
disclaimerText2:
|
||||
"If you are a company, it's better to use it with our appliance + pro support included:",
|
||||
disclaimerText3:
|
||||
'This version is not bundled with any support nor updates. Use it with caution for critical tasks.',
|
||||
'This version is not bundled with any support nor updates. Use it with caution.',
|
||||
notRegisteredDisclaimerInfo:
|
||||
'You are not registered. Your XOA may not be up to date.',
|
||||
notRegisteredDisclaimerCreateAccount: 'Click here to create an account.',
|
||||
|
||||
@@ -37,7 +37,9 @@ export class TooltipViewer extends Component {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
show ? styles.tooltipEnabled : styles.tooltipDisabled,
|
||||
show && content !== undefined
|
||||
? styles.tooltipEnabled
|
||||
: styles.tooltipDisabled,
|
||||
className
|
||||
)}
|
||||
style={{
|
||||
|
||||
@@ -88,7 +88,7 @@ export default class About extends Component {
|
||||
<p className='text-muted'>{_('bugTrackerText')}</p>
|
||||
</Col>
|
||||
<Col mediumSize={6}>
|
||||
<a href='https://xen-orchestra.com/forum/'>
|
||||
<a href='https://xcp-ng.org/forum/category/12/xen-orchestra'>
|
||||
<Icon icon='group' size={4} />
|
||||
<h4>{_('community')}</h4>
|
||||
</a>
|
||||
|
||||
@@ -126,7 +126,7 @@ const REPORT_WHEN_FILTER_OPTIONS = [
|
||||
},
|
||||
{
|
||||
label: 'reportWhenNever',
|
||||
value: 'Never',
|
||||
value: 'never',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import Component from 'base-component'
|
||||
import Icon from 'icon'
|
||||
import React from 'react'
|
||||
import Tooltip from 'tooltip'
|
||||
import Upgrade from 'xoa-upgrade'
|
||||
import { Container, Row, Col } from 'grid'
|
||||
import { Toggle } from 'form'
|
||||
import { fetchHostStats } from 'xo'
|
||||
@@ -105,7 +104,7 @@ export default class HostStats extends Component {
|
||||
|
||||
return !stats ? (
|
||||
<p>No stats.</p>
|
||||
) : process.env.XOA_PLAN > 2 ? (
|
||||
) : (
|
||||
<Container>
|
||||
<Row>
|
||||
<Col mediumSize={5}>
|
||||
@@ -179,10 +178,6 @@ export default class HostStats extends Component {
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
) : (
|
||||
<Container>
|
||||
<Upgrade place='hostStats' available={3} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,6 +222,17 @@ export default class XoApp extends Component {
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
{+process.env.XOA_PLAN === 5 && (
|
||||
<div className='alert alert-danger mb-0'>
|
||||
<a
|
||||
href='https://xen-orchestra.com/#!/xoa?pk_campaign=xo_source_banner'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
{_('disclaimerText3')}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
<div style={CONTAINER_STYLE}>
|
||||
<Shortcuts
|
||||
name='XoApp'
|
||||
|
||||
@@ -16,6 +16,7 @@ import Tooltip from 'tooltip'
|
||||
import Wizard, { Section } from 'wizard'
|
||||
import {
|
||||
AvailableTemplateVars,
|
||||
CAN_CLOUD_INIT,
|
||||
DEFAULT_CLOUD_CONFIG_TEMPLATE,
|
||||
DEFAULT_NETWORK_CONFIG_TEMPLATE,
|
||||
NetworkConfigInfo,
|
||||
@@ -1163,13 +1164,18 @@ export default class NewVm extends BaseComponent {
|
||||
<br />
|
||||
<LineItem>
|
||||
<label>
|
||||
<input
|
||||
checked={installMethod === 'SSH'}
|
||||
name='installMethod'
|
||||
onChange={this._linkState('installMethod')}
|
||||
type='radio'
|
||||
value='SSH'
|
||||
/>
|
||||
<Tooltip
|
||||
content={CAN_CLOUD_INIT ? undefined : _('premiumOnly')}
|
||||
>
|
||||
<input
|
||||
checked={installMethod === 'SSH'}
|
||||
disabled={!CAN_CLOUD_INIT}
|
||||
name='installMethod'
|
||||
onChange={this._linkState('installMethod')}
|
||||
type='radio'
|
||||
value='SSH'
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
{_('newVmSshKey')}
|
||||
</label>
|
||||
@@ -1201,13 +1207,18 @@ export default class NewVm extends BaseComponent {
|
||||
<br />
|
||||
<LineItem>
|
||||
<label>
|
||||
<input
|
||||
checked={installMethod === 'customConfig'}
|
||||
name='installMethod'
|
||||
onChange={this._linkState('installMethod')}
|
||||
type='radio'
|
||||
value='customConfig'
|
||||
/>
|
||||
<Tooltip
|
||||
content={CAN_CLOUD_INIT ? undefined : _('premiumOnly')}
|
||||
>
|
||||
<input
|
||||
checked={installMethod === 'customConfig'}
|
||||
disabled={!CAN_CLOUD_INIT}
|
||||
name='installMethod'
|
||||
onChange={this._linkState('installMethod')}
|
||||
type='radio'
|
||||
value='customConfig'
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
{_('newVmCustomConfig')}
|
||||
</label>
|
||||
|
||||
@@ -4,7 +4,6 @@ import getEventValue from 'get-event-value'
|
||||
import Icon from 'icon'
|
||||
import React from 'react'
|
||||
import Tooltip from 'tooltip'
|
||||
import Upgrade from 'xoa-upgrade'
|
||||
import { Container, Row, Col } from 'grid'
|
||||
import { Toggle } from 'form'
|
||||
import { fetchHostStats } from 'xo'
|
||||
@@ -96,100 +95,91 @@ export default class PoolStats extends Component {
|
||||
useCombinedValues,
|
||||
} = this.state
|
||||
|
||||
return process.env.XOA_PLAN > 2 ? (
|
||||
stats ? (
|
||||
<Container>
|
||||
<Row>
|
||||
<Col mediumSize={5}>
|
||||
<div className='form-group'>
|
||||
<Tooltip content={_('useStackedValuesOnStats')}>
|
||||
<Toggle
|
||||
value={useCombinedValues}
|
||||
onChange={this.linkState('useCombinedValues')}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Col>
|
||||
<Col mediumSize={1}>
|
||||
{selectStatsLoading && (
|
||||
<div className='text-xs-right'>
|
||||
<Icon icon='loading' size={2} />
|
||||
</div>
|
||||
)}
|
||||
</Col>
|
||||
<Col mediumSize={6}>
|
||||
<div className='btn-tab'>
|
||||
<select
|
||||
className='form-control'
|
||||
onChange={this._handleSelectStats}
|
||||
defaultValue={granularity}
|
||||
>
|
||||
{_('statLastTenMinutes', message => (
|
||||
<option value='seconds'>{message}</option>
|
||||
))}
|
||||
{_('statLastTwoHours', message => (
|
||||
<option value='minutes'>{message}</option>
|
||||
))}
|
||||
{_('statLastWeek', message => (
|
||||
<option value='hours'>{message}</option>
|
||||
))}
|
||||
{_('statLastYear', message => (
|
||||
<option value='days'>{message}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='cpu' /> {_('statsCpu')}
|
||||
</h5>
|
||||
<PoolCpuLineChart addSumSeries={useCombinedValues} data={stats} />
|
||||
</Col>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='memory' /> {_('statsMemory')}
|
||||
</h5>
|
||||
<PoolMemoryLineChart
|
||||
addSumSeries={useCombinedValues}
|
||||
data={stats}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<br />
|
||||
<hr />
|
||||
<Row>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='network' /> {_('statsNetwork')}
|
||||
</h5>
|
||||
{/* key: workaround that unmounts and re-mounts the chart to make sure the legend updates when toggling "stacked values"
|
||||
FIXME: remove key prop once this issue is fixed: https://github.com/CodeYellowBV/chartist-plugin-legend/issues/5 */}
|
||||
<PoolPifLineChart
|
||||
key={useCombinedValues ? 'stacked' : 'unstacked'}
|
||||
addSumSeries={useCombinedValues}
|
||||
data={stats}
|
||||
/>
|
||||
</Col>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='disk' /> {_('statLoad')}
|
||||
</h5>
|
||||
<PoolLoadLineChart
|
||||
addSumSeries={useCombinedValues}
|
||||
data={stats}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
) : (
|
||||
<p>{_('poolNoStats')}</p>
|
||||
)
|
||||
) : (
|
||||
return stats ? (
|
||||
<Container>
|
||||
<Upgrade place='hostStats' available={3} />
|
||||
<Row>
|
||||
<Col mediumSize={5}>
|
||||
<div className='form-group'>
|
||||
<Tooltip content={_('useStackedValuesOnStats')}>
|
||||
<Toggle
|
||||
value={useCombinedValues}
|
||||
onChange={this.linkState('useCombinedValues')}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Col>
|
||||
<Col mediumSize={1}>
|
||||
{selectStatsLoading && (
|
||||
<div className='text-xs-right'>
|
||||
<Icon icon='loading' size={2} />
|
||||
</div>
|
||||
)}
|
||||
</Col>
|
||||
<Col mediumSize={6}>
|
||||
<div className='btn-tab'>
|
||||
<select
|
||||
className='form-control'
|
||||
onChange={this._handleSelectStats}
|
||||
defaultValue={granularity}
|
||||
>
|
||||
{_('statLastTenMinutes', message => (
|
||||
<option value='seconds'>{message}</option>
|
||||
))}
|
||||
{_('statLastTwoHours', message => (
|
||||
<option value='minutes'>{message}</option>
|
||||
))}
|
||||
{_('statLastWeek', message => (
|
||||
<option value='hours'>{message}</option>
|
||||
))}
|
||||
{_('statLastYear', message => (
|
||||
<option value='days'>{message}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='cpu' /> {_('statsCpu')}
|
||||
</h5>
|
||||
<PoolCpuLineChart addSumSeries={useCombinedValues} data={stats} />
|
||||
</Col>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='memory' /> {_('statsMemory')}
|
||||
</h5>
|
||||
<PoolMemoryLineChart
|
||||
addSumSeries={useCombinedValues}
|
||||
data={stats}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<br />
|
||||
<hr />
|
||||
<Row>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='network' /> {_('statsNetwork')}
|
||||
</h5>
|
||||
{/* key: workaround that unmounts and re-mounts the chart to make sure the legend updates when toggling "stacked values"
|
||||
FIXME: remove key prop once this issue is fixed: https://github.com/CodeYellowBV/chartist-plugin-legend/issues/5 */}
|
||||
<PoolPifLineChart
|
||||
key={useCombinedValues ? 'stacked' : 'unstacked'}
|
||||
addSumSeries={useCombinedValues}
|
||||
data={stats}
|
||||
/>
|
||||
</Col>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='disk' /> {_('statLoad')}
|
||||
</h5>
|
||||
<PoolLoadLineChart addSumSeries={useCombinedValues} data={stats} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
) : (
|
||||
<p>{_('poolNoStats')}</p>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import Component from 'base-component'
|
||||
import Icon from 'icon'
|
||||
import React from 'react'
|
||||
import Tooltip from 'tooltip'
|
||||
import Upgrade from 'xoa-upgrade'
|
||||
import { Container, Row, Col } from 'grid'
|
||||
import { fetchSrStats } from 'xo'
|
||||
import { get } from 'lodash'
|
||||
@@ -85,81 +84,79 @@ export default class SrStats extends Component {
|
||||
return data === undefined ? (
|
||||
<span>{_('srNoStats')}</span>
|
||||
) : (
|
||||
<Upgrade place='srStats' available={3}>
|
||||
<Container>
|
||||
<Row>
|
||||
<Col mediumSize={5}>
|
||||
<div className='form-group'>
|
||||
<Tooltip content={_('useStackedValuesOnStats')}>
|
||||
<Toggle
|
||||
value={useCombinedValues}
|
||||
onChange={this.linkState('useCombinedValues')}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Container>
|
||||
<Row>
|
||||
<Col mediumSize={5}>
|
||||
<div className='form-group'>
|
||||
<Tooltip content={_('useStackedValuesOnStats')}>
|
||||
<Toggle
|
||||
value={useCombinedValues}
|
||||
onChange={this.linkState('useCombinedValues')}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Col>
|
||||
<Col mediumSize={1}>
|
||||
{selectStatsLoading && (
|
||||
<div className='text-xs-right'>
|
||||
<Icon icon='loading' size={2} />
|
||||
</div>
|
||||
</Col>
|
||||
<Col mediumSize={1}>
|
||||
{selectStatsLoading && (
|
||||
<div className='text-xs-right'>
|
||||
<Icon icon='loading' size={2} />
|
||||
</div>
|
||||
)}
|
||||
</Col>
|
||||
<Col mediumSize={6}>
|
||||
<div className='btn-tab'>
|
||||
<select
|
||||
className='form-control'
|
||||
onChange={this._onGranularityChange}
|
||||
defaultValue={granularity}
|
||||
>
|
||||
{_('statLastTenMinutes', message => (
|
||||
<option value='seconds'>{message}</option>
|
||||
))}
|
||||
{_('statLastTwoHours', message => (
|
||||
<option value='minutes'>{message}</option>
|
||||
))}
|
||||
{_('statLastWeek', message => (
|
||||
<option value='hours'>{message}</option>
|
||||
))}
|
||||
{_('statLastYear', message => (
|
||||
<option value='days'>{message}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='iops' size={1} /> {_('statsIops')}
|
||||
</h5>
|
||||
<IopsLineChart addSumSeries={useCombinedValues} data={data} />
|
||||
</Col>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='disk' size={1} /> {_('statsIoThroughput')}
|
||||
</h5>
|
||||
<IoThroughputChart addSumSeries={useCombinedValues} data={data} />
|
||||
</Col>
|
||||
</Row>
|
||||
<br />
|
||||
<hr />
|
||||
<Row>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='latency' size={1} /> {_('statsLatency')}
|
||||
</h5>
|
||||
<LatencyChart addSumSeries={useCombinedValues} data={data} />
|
||||
</Col>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='iowait' size={1} /> {_('statsIowait')}
|
||||
</h5>
|
||||
<IowaitChart addSumSeries={useCombinedValues} data={data} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</Upgrade>
|
||||
)}
|
||||
</Col>
|
||||
<Col mediumSize={6}>
|
||||
<div className='btn-tab'>
|
||||
<select
|
||||
className='form-control'
|
||||
onChange={this._onGranularityChange}
|
||||
defaultValue={granularity}
|
||||
>
|
||||
{_('statLastTenMinutes', message => (
|
||||
<option value='seconds'>{message}</option>
|
||||
))}
|
||||
{_('statLastTwoHours', message => (
|
||||
<option value='minutes'>{message}</option>
|
||||
))}
|
||||
{_('statLastWeek', message => (
|
||||
<option value='hours'>{message}</option>
|
||||
))}
|
||||
{_('statLastYear', message => (
|
||||
<option value='days'>{message}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='iops' size={1} /> {_('statsIops')}
|
||||
</h5>
|
||||
<IopsLineChart addSumSeries={useCombinedValues} data={data} />
|
||||
</Col>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='disk' size={1} /> {_('statsIoThroughput')}
|
||||
</h5>
|
||||
<IoThroughputChart addSumSeries={useCombinedValues} data={data} />
|
||||
</Col>
|
||||
</Row>
|
||||
<br />
|
||||
<hr />
|
||||
<Row>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='latency' size={1} /> {_('statsLatency')}
|
||||
</h5>
|
||||
<LatencyChart addSumSeries={useCombinedValues} data={data} />
|
||||
</Col>
|
||||
<Col mediumSize={6}>
|
||||
<h5 className='text-xs-center'>
|
||||
<Icon icon='iowait' size={1} /> {_('statsIowait')}
|
||||
</h5>
|
||||
<IowaitChart addSumSeries={useCombinedValues} data={data} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import Component from 'base-component'
|
||||
import Icon from 'icon'
|
||||
import React from 'react'
|
||||
import Tooltip from 'tooltip'
|
||||
import Upgrade from 'xoa-upgrade'
|
||||
import { fetchVmStats } from 'xo'
|
||||
import { Toggle } from 'form'
|
||||
import { injectIntl } from 'react-intl'
|
||||
@@ -105,7 +104,7 @@ export default injectIntl(
|
||||
|
||||
return !stats ? (
|
||||
<p>No stats.</p>
|
||||
) : process.env.XOA_PLAN > 2 ? (
|
||||
) : (
|
||||
<Container>
|
||||
<Row>
|
||||
<Col mediumSize={6}>
|
||||
@@ -177,10 +176,6 @@ export default injectIntl(
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
) : (
|
||||
<Container>
|
||||
<Upgrade place='vmStats' available={3} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
if [ $# -eq 0 ] || [ "$1" = "-h" ]
|
||||
then
|
||||
echo "Usage: $0 <package> <version>"
|
||||
|
||||
@@ -28,6 +28,10 @@ require('exec-promise')(() =>
|
||||
url: 'https://github.com/vatesfr/xen-orchestra.git',
|
||||
}
|
||||
|
||||
if (!('version' in pkg)) {
|
||||
pkg.version = '0.0.0'
|
||||
}
|
||||
|
||||
delete pkg.standard
|
||||
|
||||
deleteProperties(pkg, 'config', ['commitizen'])
|
||||
@@ -54,16 +58,26 @@ require('exec-promise')(() =>
|
||||
])
|
||||
deleteProperties(pkg, 'scripts', ['commitmsg', 'cz'])
|
||||
|
||||
const { scripts } = pkg
|
||||
if (scripts !== undefined) {
|
||||
const prepublish = scripts.prepublish
|
||||
if (prepublish !== undefined && !('prepublishOnly' in scripts)) {
|
||||
delete scripts.prepublish
|
||||
scripts.prepublishOnly = prepublish
|
||||
pkg.scripts = sortedObject(scripts)
|
||||
let { scripts = {} } = pkg
|
||||
const originalScripts = scripts
|
||||
|
||||
if (!pkg.private && !('postversion' in scripts)) {
|
||||
scripts = { ...scripts, postversion: 'npm publish' }
|
||||
}
|
||||
|
||||
const prepublish = scripts.prepublish
|
||||
if (prepublish !== undefined && !('prepublishOnly' in scripts)) {
|
||||
scripts = {
|
||||
...scripts,
|
||||
prepublishOnly: prepublish,
|
||||
prepublish: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
if (scripts !== originalScripts) {
|
||||
pkg.scripts = sortedObject(scripts)
|
||||
}
|
||||
|
||||
return Promise.all([
|
||||
writeFile(`${dir}/package.json`, JSON.stringify(pkg, null, 2) + '\n'),
|
||||
unlink(`${dir}/.editorconfig`),
|
||||
|
||||
Reference in New Issue
Block a user