Compare commits

...

22 Commits

Author SHA1 Message Date
Julien Fontanet
d6895e7288 WiP 2023-02-09 10:31:14 +01:00
Julien Fontanet
e279ea01a2 WiP 2023-02-09 10:30:41 +01:00
Julien Fontanet
8df308aa01 feat(xen-api/{get,put}Resource): add 24h timeout 2023-02-09 10:30:01 +01:00
Julien Fontanet
a3e37eca62 fix(xo-server): disable broken requestTimeout
Fixes https://xcp-ng.org/forum/post/58146

Caused by nodejs/node#46574

It caused requests to timeout after 0-30 seconds, which broke all uploads.
2023-02-09 10:25:45 +01:00
Julien Fontanet
817911a41e fix(xen-api): fix task watchers when initially not watching events (2)
Introduced by 9f4fce9da
2023-02-08 17:11:27 +01:00
Julien Fontanet
9f4fce9daa fix(xen-api): fix task watchers when initially not watching events
Introduced by bc61dd85c
2023-02-08 12:21:56 +01:00
Julien Fontanet
9ff305d5db fix(xo-server/rest-api): fix VDI import
Introduced by ab0e411ac
2023-02-07 19:20:59 +01:00
Julien Fontanet
055c3e098f fix(xen-api/putResource): better error handling
Tested all combinaisons with the following conditions:

- success, cancelation and connection loss (ECONNRESET)
- with and without tasks watching
- with and without known length (i.e. content-length hack)
2023-02-07 17:38:01 +01:00
Julien Fontanet
bc61dd85c6 fix(xen-api): correctly handle not watching tasks 2023-02-07 17:23:57 +01:00
Julien Fontanet
db6f1405e9 chore(xo-server/rest-api): match export routes first 2023-02-07 16:36:05 +01:00
Gabriel Gunullu
3dc3376aec chore(test): replace vhd-util check (#6651) 2023-02-07 13:33:25 +01:00
Julien Fontanet
55920a58a3 feat(xo-server/recover-account): -s flag for xoa-support
Simpler process for xoa-support.

```console
$ xo-server-recover-account -s
The generated password is lXJMtCzWDGPOIg
user xoa-support has been successfully updated
```
2023-02-06 15:25:04 +01:00
Julien Fontanet
2a70ebf667 docs: uniformize code blocks
- add missing syntaxes
- don't put prompt if no command outputs to ease copy/paste and use `sh` syntax
- always use `$` as prompt and use `console` syntax
2023-02-06 11:25:12 +01:00
Julien Fontanet
2f65a86aa0 fix(xen-api/putResource): fix a number of issues
- hide `VDI_IO_ERROR` when using content-length hack
- avoid unhandled rejection in case upload fails
2023-02-06 10:40:42 +01:00
Julien Fontanet
4bf81ac33b docs(xapi): fix typo 2023-02-04 11:14:02 +01:00
Julien Fontanet
263c23ae8f docs(xapi): describe syncHookTimeout 2023-02-04 11:11:41 +01:00
Julien Fontanet
bf51b945c5 chore(vmware-explorer): fix lint issues
Introduced by 9fa15d9c8
2023-02-03 16:36:55 +01:00
Julien Fontanet
9d7a461550 feat(turbo): add dev and test tasks 2023-02-03 16:17:52 +01:00
Julien Fontanet
bbf60818eb chore: update dev deps 2023-02-03 16:17:31 +01:00
Julien Fontanet
103b22ebb2 fix(backups/importDeltaVm): resize cloned VDI if necessary
Fixes zammad#10996
2023-02-03 15:49:08 +01:00
Mathieu
cf4a1d7d40 fix(lite): update stacked ram usage message (#6650) 2023-02-02 11:50:10 +01:00
Julien Fontanet
e94f036aca chore(vmware-explorer): lower requirement to Node 14 2023-02-02 09:43:03 +01:00
84 changed files with 1672 additions and 1581 deletions

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/async-each):
```
> npm install --save @vates/async-each
```sh
npm install --save @vates/async-each
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/cached-dns.lookup):
```
> npm install --save @vates/cached-dns.lookup
```sh
npm install --save @vates/cached-dns.lookup
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/coalesce-calls):
```
> npm install --save @vates/coalesce-calls
```sh
npm install --save @vates/coalesce-calls
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/compose):
```
> npm install --save @vates/compose
```sh
npm install --save @vates/compose
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/decorate-with):
```
> npm install --save @vates/decorate-with
```sh
npm install --save @vates/decorate-with
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/disposable):
```
> npm install --save @vates/disposable
```sh
npm install --save @vates/disposable
```
## Usage

View File

@@ -8,8 +8,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/event-listeners-manager):
```
> npm install --save @vates/event-listeners-manager
```sh
npm install --save @vates/event-listeners-manager
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/multi-key-map):
```
> npm install --save @vates/multi-key-map
```sh
npm install --save @vates/multi-key-map
```
## Usage

View File

@@ -8,8 +8,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/nbd-client):
```
> npm install --save @vates/nbd-client
```sh
npm install --save @vates/nbd-client
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/otp):
```
> npm install --save @vates/otp
```sh
npm install --save @vates/otp
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/parse-duration):
```
> npm install --save @vates/parse-duration
```sh
npm install --save @vates/parse-duration
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/predicates):
```
> npm install --save @vates/predicates
```sh
npm install --save @vates/predicates
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/read-chunk):
```
> npm install --save @vates/read-chunk
```sh
npm install --save @vates/read-chunk
```
## Usage

View File

@@ -8,8 +8,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/task):
```
> npm install --save @vates/task
```sh
npm install --save @vates/task
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@vates/toggle-scripts):
```
> npm install --save @vates/toggle-scripts
```sh
npm install --save @vates/toggle-scripts
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/async-map):
```
> npm install --save @xen-orchestra/async-map
```sh
npm install --save @xen-orchestra/async-map
```
## Usage

View File

@@ -8,8 +8,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/audit-core):
```
> npm install --save @xen-orchestra/audit-core
```sh
npm install --save @xen-orchestra/audit-core
```
## Contributions

View File

@@ -8,8 +8,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/backups-cli):
```
> npm install --global @xen-orchestra/backups-cli
```sh
npm install --global @xen-orchestra/backups-cli
```
## Usage

View File

@@ -8,8 +8,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/backups):
```
> npm install --save @xen-orchestra/backups
```sh
npm install --save @xen-orchestra/backups
```
## Contributions

View File

@@ -258,6 +258,9 @@ exports.importDeltaVm = defer(async function importDeltaVm(
$defer.onFailure(() => newVdi.$destroy())
await newVdi.update_other_config(TAG_COPY_SRC, vdi.uuid)
if (vdi.virtual_size > newVdi.virtual_size) {
await newVdi.$callAsync('resize', vdi.virtual_size)
}
} else if (vdiRef === vmRecord.suspend_VDI) {
// suspendVDI has already created
newVdi = suspendVdi

View File

@@ -8,8 +8,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/cr-seed-cli):
```
> npm install --global @xen-orchestra/cr-seed-cli
```sh
npm install --global @xen-orchestra/cr-seed-cli
```
## Contributions

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/cron):
```
> npm install --save @xen-orchestra/cron
```sh
npm install --save @xen-orchestra/cron
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/defined):
```
> npm install --save @xen-orchestra/defined
```sh
npm install --save @xen-orchestra/defined
```
## Contributions

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/emit-async):
```
> npm install --save @xen-orchestra/emit-async
```sh
npm install --save @xen-orchestra/emit-async
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/fs):
```
> npm install --global @xen-orchestra/fs
```sh
npm install --global @xen-orchestra/fs
```
## Contributions

View File

@@ -71,7 +71,7 @@
"snapshot": "Snapshot",
"sort-by": "Sort by",
"stacked-cpu-usage": "Stacked CPU usage",
"stacked-ram-usage": "Stacked memory usage",
"stacked-ram-usage": "Stacked RAM usage",
"start": "Start",
"start-on-host": "Start on specific host",
"stats": "Stats",

View File

@@ -71,7 +71,7 @@
"snapshot": "Instantané",
"sort-by": "Trier par",
"stacked-cpu-usage": "Utilisation CPU empilée",
"stacked-ram-usage": "Utilisation de la mémoire empilée",
"stacked-ram-usage": "Utilisation RAM empilée",
"start": "Démarrer",
"start-on-host": "Démarrer sur un hôte spécifique",
"stats": "Stats",

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/log):
```
> npm install --save @xen-orchestra/log
```sh
npm install --save @xen-orchestra/log
```
## Usage

View File

@@ -8,8 +8,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/mixin):
```
> npm install --save @xen-orchestra/mixin
```sh
npm install --save @xen-orchestra/mixin
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/mixins):
```
> npm install --save @xen-orchestra/mixins
```sh
npm install --save @xen-orchestra/mixins
```
## Contributions

View File

@@ -25,7 +25,7 @@ For safety reasons, the proxy requires authentication to be used.
Use the authentication token:
```
```console
$ cat ~/.config/xo-proxy/config.z-auto.json
{"authenticationToken":"J0BgKritQgPxoyZrBJ5ViafQfLk06YoyFwC3fmfO5wU"}
```
@@ -48,7 +48,7 @@ https://user:password@xo.company.lan
Or create a dedicated token with `xo-cli`:
```
```console
$ xo-cli --createToken xoa.company.lan admin@admin.net
Password: ********
Successfully logged with admin@admin.net

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/openflow):
```
> npm install --save @xen-orchestra/openflow
```sh
npm install --save @xen-orchestra/openflow
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/proxy-cli):
```
> npm install --global @xen-orchestra/proxy-cli
```sh
npm install --global @xen-orchestra/proxy-cli
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/self-signed):
```
> npm install --save @xen-orchestra/self-signed
```sh
npm install --save @xen-orchestra/self-signed
```
## Usage

View File

@@ -8,8 +8,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/template):
```
> npm install --save @xen-orchestra/template
```sh
npm install --save @xen-orchestra/template
```
## Usage

View File

@@ -88,35 +88,16 @@ export default class VhdEsxiSeSparse extends VhdAbstract {
async readHeaderAndFooter() {
const buffer = await this.#read(0, 2048)
strictEqual(buffer.readBigInt64LE(0), 0xcafebaben)
for (let i = 0; i < 2048 / 8; i++) {
console.log(i, '> ', buffer.readBigInt64LE(8 * i).toString(16), buffer.readBigInt64LE(8 * i))
}
strictEqual(readInt64(buffer, 1), 0x200000001) // version 2.1
const capacity = readInt64(buffer, 2)
const grain_size = readInt64(buffer, 3)
const grain_table_size = readInt64(buffer, 4)
const flags = readInt64(buffer, 5)
const grain_dir_offset = readInt64(buffer, 16)
const grain_dir_size = readInt64(buffer, 17)
const grain_tables_offset = readInt64(buffer, 18)
const grain_tables_size = readInt64(buffer, 19)
this.#grainOffset = readInt64(buffer, 24)
console.log({
capacity,
grain_size,
grain_table_size,
flags,
grain_dir_offset,
grain_dir_size,
grain_tables_offset,
grain_tables_size,
grainSize: this.#grainSize,
})
this.#grainSize = grain_size * 512 // 8 sectors / 4KB default
this.#grainTableOffset = grain_tables_offset * 512
this.#grainTableSize = grain_tables_size * 512
@@ -131,12 +112,10 @@ export default class VhdEsxiSeSparse extends VhdAbstract {
}
async readBlockAllocationTable() {
console.log('READ BLOCK ALLOCATION', this.#grainTableSize)
const CHUNK_SIZE = 64 * 512
strictEqual(this.#grainTableSize % CHUNK_SIZE, 0)
console.log(' will read ', this.#grainTableSize / CHUNK_SIZE, 'table')
for (let chunkIndex = 0, grainIndex = 0; chunkIndex < this.#grainTableSize / CHUNK_SIZE; chunkIndex++) {
process.stdin.write('.')
const start = chunkIndex * CHUNK_SIZE + this.#grainTableOffset
@@ -151,15 +130,11 @@ export default class VhdEsxiSeSparse extends VhdAbstract {
break
}
if (entry > 3n) {
const intIndex = +(((entry & 0x0fff000000000000n) >> 48n) | ((entry & 0x0000ffffffffffffn) << 12n))
let pos = intIndex * this.#grainSize + CHUNK_SIZE * chunkIndex + this.#grainOffset
console.log({ indexInChunk, grainIndex, intIndex, pos })
this.#grainMap.set(grainIndex)
grainIndex++
}
}
}
console.log('found', this.#grainMap.size)
// read grain directory and the grain tables
const nbBlocks = this.header.maxTableEntries
@@ -189,7 +164,7 @@ export default class VhdEsxiSeSparse extends VhdAbstract {
strictEqual(graintable.length, 4096 * 4)
// we have no guaranty that data are order or contiguous
// let's construct ranges to limit the number of queries
let rangeStart, offsetStart, offsetEnd, lastOffset
let rangeStart, offsetStart, offsetEnd
const changeRange = async (index, offset) => {
if (offsetStart !== undefined) {

View File

@@ -1,16 +0,0 @@
import Esxi from './esxi.mjs'
const host = '10.10.0.62'
const user = 'root'
const password = 'vateslab'
const sslVerify = false
console.log(Esxi)
const esxi = new Esxi(host, user, password, sslVerify)
console.log(esxi)
esxi.on('ready', async function () {
//const metadata = await esxi.getTransferableVmMetadata('4')
//console.log('metadata', metadata)
const res = await esxi.powerOn(9)
console.log(res)
})

View File

@@ -12,7 +12,7 @@
"vhd-lib": "^4.2.0"
},
"engines": {
"node": ">=18"
"node": ">=14"
},
"homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/@xen-orchestra/vmware-explorer",
"bugs": "https://github.com/vatesfr/xen-orchestra/issues",

View File

@@ -50,7 +50,7 @@ export default function parseVmsd(text) {
// remove the " around value
set(parsed, key.split('.'), val?.substring(1, val.length - 1))
})
if (parsed.snapshot?.current == undefined) {
if (parsed.snapshot?.current === undefined) {
return
}

View File

@@ -8,8 +8,8 @@
Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/xapi):
```
> npm install --save @xen-orchestra/xapi
```sh
npm install --save @xen-orchestra/xapi
```
## Contributions

View File

@@ -18,7 +18,7 @@ The feature is opt-in via a tag on the VM: `xo:notify-on-snapshot`.
By default, it will be an HTTPS request on the port `1727`, on the first IP address reported by the VM.
If the _VM Tools_ (i.e. management agent) are not installed on the VM or if you which to use another URL, you can specify this in the tag: `xo:notify-on-snapshot=<URL>`.
If the _VM Tools_ (i.e. management agent) are not installed on the VM or if you wish to use another URL, you can specify this in the tag: `xo:notify-on-snapshot=<URL>`.
To guarantee the request comes from XO, a secret must be provided in the `xo-server`'s (and `xo-proxy` if relevant) configuration:
@@ -27,11 +27,20 @@ To guarantee the request comes from XO, a secret must be provided in the `xo-ser
syncHookSecret = 'unique long string to ensure the request comes from XO'
```
XO will waits for the request to be answered before starting the snapshot, but will not wait longer than _1 minute_ by default. This timeout can be changed in the configuration as well:
```toml
[xapiOptions]
# Timeout in milliseconds
#
# Default: 60e3
syncHookTimeout = 300e3 # 5 minutes
```
## Specification
XO will waits for the request to be answered before starting the snapshot, but will not wait longer than _1 minute_.
If the request fails for any reason, XO will go ahead with snapshot immediately.
If the request fails for any reasons (including the timeout described in the above section), XO will go ahead with snapshot immediately.
```http
GET /sync HTTP/1.1
@@ -143,7 +152,7 @@ main().catch(console.warn)
You can run it manually for testing:
```
> node index.cjs
```console
$ node index.cjs
Server is listening on https://[::]:1727
```

View File

@@ -11,6 +11,10 @@
> Users must be able to say: “I had this issue, happy to know it's fixed”
- [Continuous Replication] Fix `VDI_IO_ERROR` when after a VDI has been resized
- [REST API] Fix VDI import
- Fix failing imports (REST API and web UI) [Forum#58146](https://xcp-ng.org/forum/post/58146)
### Packages to release
> When modifying a package, add it here with its release type.
@@ -27,4 +31,8 @@
<!--packages-start-->
- @xen-orchestra/backups patch
- xen-api patch
- xo-server patch
<!--packages-end-->

View File

@@ -4,7 +4,7 @@ FROM ubuntu:xenial
# https://qastack.fr/programming/25899912/how-to-install-nvm-in-docker
RUN apt-get update
RUN apt-get install -y curl qemu-utils blktap-utils vmdk-stream-converter git libxml2-utils libfuse2 nbdkit
RUN apt-get install -y curl qemu-utils vmdk-stream-converter git libxml2-utils libfuse2 nbdkit
ENV NVM_DIR /usr/local/nvm
RUN mkdir -p /usr/local/nvm
RUN cd /usr/local/nvm

View File

@@ -134,8 +134,8 @@ This CLI is mainly used as a debug tool, there's no 100% guarantee on its stabil
### Usage
```
> xo-cli --help
```console
$ xo-cli --help
Usage:
xo-cli --register [--allowUnauthorized] [--expiresIn duration] <XO-Server URL> <username> [<password>]
@@ -177,8 +177,8 @@ Usage:
#### Register your XO instance
```
> xo-cli --register http://xo.my-company.net admin@admin.net admin
```console
$ xo-cli --register http://xo.my-company.net admin@admin.net admin
Successfully logged with admin@admin.net
```
@@ -188,27 +188,27 @@ Note: only a token will be saved in the configuration file.
Prints all objects:
```
> xo-cli --list-objects
```sh
xo-cli --list-objects
```
It is possible to filter on object properties, for instance to print
all VM templates:
```
> xo-cli --list-objects type=VM-template
```sh
xo-cli --list-objects type=VM-template
```
#### List available commands
```
> xo-cli --list-commands
```sh
xo-cli --list-commands
```
Commands can be filtered using patterns:
```
> xo-cli --list-commands '{user,group}.*'
```sh
xo-cli --list-commands '{user,group}.*'
```
#### Execute a command
@@ -217,8 +217,8 @@ The same syntax is used for all commands: `xo-cli <command> <param name>=<value>
E.g., adding a new server:
```
> xo-cli server.add host=my.server.net username=root password=secret-password
```console
$ xo-cli server.add host=my.server.net username=root password=secret-password
42
```
@@ -228,20 +228,20 @@ Parameters (except `true` and `false` which are correctly parsed as
booleans) are assumed to be strings. For other types, you may use JSON
encoding by prefixing with `json:`:
```
> xo-cli foo.bar baz='json:[1, 2, 3]'
```sh
xo-cli foo.bar baz='json:[1, 2, 3]'
```
##### VM export
```
> xo-cli vm.export vm=a01667e0-8e29-49fc-a550-17be4226783c @=vm.xva
```sh
xo-cli vm.export vm=a01667e0-8e29-49fc-a550-17be4226783c @=vm.xva
```
##### VM import
```
> xo-cli vm.import sr=60a6939e-8b0a-4352-9954-5bde44bcdf7d @=vm.xva
```sh
xo-cli vm.import sr=60a6939e-8b0a-4352-9954-5bde44bcdf7d @=vm.xva
```
> Note: `xo-cli` only supports the import of XVA files. It will not import OVA files. To import OVA images, you must use the XOA web UI or use `xo-upload-ova` [available here](https://github.com/vatesfr/xen-orchestra/blob/master/@xen-orchestra/upload-ova/README.md#xo-upload-ova).

View File

@@ -116,7 +116,7 @@ Create the following file:
Add the following lines:
```
```toml
# XOA Support - Work-around HTTP timeout issue during backups
[xapiOptions]
httpInactivityTimeout = 1800000 # 30 mins

View File

@@ -248,7 +248,7 @@ First, after your disk is attached to XOA, you'll have to find the new disk name
Then, create a filesystem on it:
```
```sh
mkfs.ext4 /dev/xvdb
```

View File

@@ -70,16 +70,16 @@ If you use certificates signed by an in-house CA for your XCP-ng or XenServer ho
To enable this option in your XOA, create `/etc/systemd/system/xo-server.service.d/ca.conf` with the following content:
```
```ini
[Service]
Environment=NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/my-cert.crt
```
Don't forget to reload `systemd` conf and restart `xo-server`:
```
# systemctl daemon-reload
# systemctl restart xo-server.service
```sh
systemctl daemon-reload
systemctl restart xo-server.service
```
> For XO Proxy, the process is almost the same except the file to create is `/etc/systemd/system/xo-proxy.service.d/ca.conf` and the service to restart is `xo-proxy.service`.

View File

@@ -82,14 +82,14 @@ The XOA backup system requires metadata to correctly associate the source snapsh
First install the tool (all the following is done from the XOA VM CLI):
```
```sh
sudo npm i -g --unsafe-perm @xen-orchestra/cr-seed-cli
```
Here is an example of how the utility expects the UUIDs and info passed to it:
```
xo-cr-seed
```console
$ xo-cr-seed
Usage: xo-cr-seed <source XAPI URL> <source snapshot UUID> <target XAPI URL> <target VM UUID> <backup job id> <backup schedule id>
xo-cr-seed v0.2.0
@@ -97,8 +97,8 @@ xo-cr-seed v0.2.0
Putting it altogether and putting our values and UUID's into the command, it will look like this (it is a long command):
```
xo-cr-seed https://root:password@xen1.company.tld 4a21c1cd-e8bd-4466-910a-f7524ecc07b1 https://root:password@xen2.company.tld 5aaf86ca-ae06-4a4e-b6e1-d04f0609e64d 90d11a94-a88f-4a84-b7c1-ed207d3de2f9 369a26f0-da77-41ab-a998-fa6b02c69b9a
```console
$ xo-cr-seed https://root:password@xen1.company.tld 4a21c1cd-e8bd-4466-910a-f7524ecc07b1 https://root:password@xen2.company.tld 5aaf86ca-ae06-4a4e-b6e1-d04f0609e64d 90d11a94-a88f-4a84-b7c1-ed207d3de2f9 369a26f0-da77-41ab-a998-fa6b02c69b9a
```
:::warning
@@ -106,8 +106,8 @@ If the username or the password for your XCP-ng/XenServer hosts contains special
An easy way to do this with Node in command line:
```
> node -p 'encodeURIComponent(process.argv[1])' -- 'password with special chars :#@'
```console
$ node -p 'encodeURIComponent(process.argv[1])' -- 'password with special chars :#@'
password%20with%20special%20chars%20%3A%23%40
```

View File

@@ -4,7 +4,7 @@
If you think you have a problem with your XOA, start by typing`xoa check`command in your terminal:
```
```console
$ xoa check
✔ Node version
✔ Disk space for /var

View File

@@ -87,7 +87,7 @@ XO needs Node.js. **Please always use latest Node LTS**.
We'll consider at this point that you've got a working node on your box. E.g:
```
```console
$ node -v
v16.14.0
```
@@ -106,21 +106,21 @@ XO needs the following packages to be installed. Redis is used as a database by
For example, on Debian/Ubuntu:
```
$ apt-get install build-essential redis-server libpng-dev git python3-minimal libvhdi-utils lvm2 cifs-utils
```sh
apt-get install build-essential redis-server libpng-dev git python3-minimal libvhdi-utils lvm2 cifs-utils
```
On Fedora/CentOS like:
```
$ dnf install redis libpng-devel git libvhdi-utils lvm2 cifs-utils make automake gcc gcc-c++
```sh
dnf install redis libpng-devel git libvhdi-utils lvm2 cifs-utils make automake gcc gcc-c++
```
### Fetching the Code
You need to use the `git` source code manager to fetch the code. Ideally, you should run XO as a non-root user, and if you choose to, you need to set up `sudo` to be able to mount NFS remotes. As your chosen non-root (or root) user, run the following:
```
```sh
git clone -b master https://github.com/vatesfr/xen-orchestra
```
@@ -132,18 +132,18 @@ git clone -b master https://github.com/vatesfr/xen-orchestra
Now that you have the code, you can enter the `xen-orchestra` directory and use `yarn` to install other dependencies. Then finally build it using `yarn build`. Be sure to run `yarn` commands as the same user you will be using to run Xen Orchestra:
```
$ cd xen-orchestra
$ yarn
$ yarn build
```sh
cd xen-orchestra
yarn
yarn build
```
Now you have to create a config file for `xo-server`:
```
$ cd packages/xo-server
$ mkdir -p ~/.config/xo-server
$ cp sample.config.toml ~/.config/xo-server/config.toml
```sh
cd packages/xo-server
mkdir -p ~/.config/xo-server
cp sample.config.toml ~/.config/xo-server/config.toml
```
> Note: If you're installing `xo-server` as a global service, you may want to copy the file to `/etc/xo-server/config.toml` instead.
@@ -152,7 +152,7 @@ In this config file, you can change default ports (80 and 443) for xo-server. If
You can try to start xo-server to see if it works. You should have something like this:
```
```console
$ yarn start
WebServer listening on localhost:80
[INFO] Default user: "admin@admin.net" with password "admin"
@@ -162,8 +162,8 @@ WebServer listening on localhost:80
The only part you need to launch is xo-server, which is quite easy to do. From the `xen-orchestra/packages/xo-server` directory, run the following:
```
$ yarn start
```sh
yarn start
```
That's it! Use your browser to visit the xo-server IP address, and it works! :)
@@ -172,13 +172,13 @@ That's it! Use your browser to visit the xo-server IP address, and it works! :)
If you would like to update your current version, enter your `xen-orchestra` directory and run the following:
```
```sh
# This will clear any changes you made in the repository!!
$ git checkout .
git checkout .
$ git pull --ff-only
$ yarn
$ yarn build
git pull --ff-only
yarn
yarn build
```
Then restart Xen Orchestra if it was running.
@@ -187,33 +187,36 @@ Then restart Xen Orchestra if it was running.
- You can use [forever](https://github.com/nodejitsu/forever) to have the process always running:
```
```sh
yarn global add forever
# Run the below as the user owning XO
forever start dist/cli.mjs
```
- Or you can use [forever-service](https://github.com/zapty/forever-service) to install XO as a system service, so it starts automatically at boot. Run the following as root:
```
```sh
yarn global add forever
yarn global add forever-service
# Be sure to edit the path below to where your install is located!
cd /home/username/xen-orchestra/packages/xo-server/
# Change the username below to the user owning XO
forever-service install orchestra -r username -s dist/cli.mjs
```
The forever-service command above must be run in the xo-server bin directory. Now you can manage the service, and it will start on boot with the machine:
```
```sh
service orchestra start
service orchestra status
```
If you need to delete the service:
```
```sh
forever-service delete orchestra
```
@@ -245,7 +248,7 @@ If you have problems during the building phase, follow these steps in your `xen-
If you are using FreeBSD, you need to install these packages:
```
```sh
pkg install gmake redis python git npm node autoconf
```
@@ -253,25 +256,25 @@ You can update `npm` itself right now with a `npm update -g`
A few of the npm packages look for system binaries as part of their installation, and if missing will try to build it themselves. Installing these will save some time and allow for easier upgrades later:
```
```sh
pkg install jpeg-turbo optipng gifsicle
```
Because FreeBSD is shipped with CLANG and not GCC, you need to do this:
```
```sh
ln -s /usr/bin/clang++ /usr/local/bin/g++
```
To enable redis on boot, add this in your `/etc/rc.conf`:
```
```sh
redis_enable="YES"
```
Don't forget to start redis if you don't reboot now:
```
```sh
service redis start
```
@@ -281,45 +284,45 @@ service redis start
If you are using OpenBSD, you need to install these packages:
```
```sh
pkg_add gmake redis python--%2.7 git node autoconf yarn
```
A few of the npm packages look for system binaries as part of their installation, and if missing will try to build it themselves. Installing these will save some time and allow for easier upgrades later:
```
```sh
pkg_add jpeg optipng gifsicle
```
Because OpenBSD is shipped with CLANG and not GCC, you need to do this:
```
```sh
export CC=/usr/bin/clang
export CXX=/usr/bin/clang++
```
You will need to update the number of allowed open files and make `node` available to `npm` :
```
```sh
ulimit -n 10240
ln -s /usr/local/bin/node /tmp/node
```
If `yarn` cannot find Python, give it an hand :
```
```sh
PYTHON=/usr/local/bin/python2 yarn
```
Enable redis on boot with:
```
```sh
rcctl enable redis
```
Don't forget to start redis if you don't reboot now:
```
```sh
rcctl start redis
```
@@ -327,7 +330,7 @@ rcctl start redis
If you are running `xo-server` as a non-root user, you need to use `sudo` to be able to mount NFS remotes. You can do this by editing `xo-server` configuration file and setting `useSudo = true`. It's near the end of the file:
```
```toml
useSudo = true
```

View File

@@ -684,7 +684,7 @@ To run Docker as non-root, please add the user you want inside the "Docker" grou
Now you need to access your host (Dom0) and use the following command:
```
```sh
xscontainer-prepare-vm -v <VM_UUID> -u <username>
```

View File

@@ -60,7 +60,7 @@ While creating a standard backup job from your main Xen Orchestra appliance, you
Login is disabled by default on proxy appliances.
If you need to login for some reason, you need to set a password for the xoa user via the XenStore of the VM. The following is to be ran on your XCP-ng host:
```
```sh
xe vm-param-set uuid=<UUID> xenstore-data:vm-data/system-account-xoa-password=<password>
```
@@ -77,7 +77,7 @@ After adding the VIF you will need to set an IP for the new NIC, for that you wi
Then set the new IP:
```
```console
$ xoa network static eth1
? Static IP for this machine 192.168.100.120
? Network mask (eg 255.255.255.0) 255.255.255.0
@@ -85,8 +85,8 @@ $ xoa network static eth1
If you want to set a static address.
```
$ xoa network dhcp eth1
```sh
xoa network dhcp eth1
```
If you prefer using DHCP.

View File

@@ -80,10 +80,10 @@ Content-Type: application/json
Here is an example with `curl`:
```bash
curl \
-b authenticationToken=0OQIKwb1WjeHtch25Ls \
http://xoa.example.com/rest/v0/vms?fields=name_label,power_state
```console
$ curl \
-b authenticationToken=0OQIKwb1WjeHtch25Ls \
http://xoa.example.com/rest/v0/vms?fields=name_label,power_state
[
{
"name_label": "FreeNAS",
@@ -125,7 +125,7 @@ Content-Type: application/x-ndjson
> This feature is restricted to `name_label` and `name_description` at the moment.
```bash
```sh
curl \
-X PATCH \
-b authenticationToken=KQxQdm2vMiv7jBIK0hgkmgxKzemd8wSJ7ugFGKFkTbs \
@@ -139,7 +139,7 @@ curl \
For a VM:
```bash
```sh
curl \
-X DELETE \
-b authenticationToken=KQxQdm2vMiv7jBIK0hgkmgxKzemd8wSJ7ugFGKFkTbs \
@@ -148,7 +148,7 @@ curl \
For a VDI:
```bash
```sh
curl \
-X DELETE \
-b authenticationToken=KQxQdm2vMiv7jBIK0hgkmgxKzemd8wSJ7ugFGKFkTbs \
@@ -159,7 +159,7 @@ curl \
VDI export and VM export are supported by the API. Below is a simple example to export a VM with `zstd` compression into a `myVM.xva` file:
```bash
```sh
curl \
-b authenticationToken=KQxQdm2vMiv7jFEAZXOAGKFkTbs \
'https://xoa.example.org/rest/v0/vms/770aa52a-fd42-8faf-f167-8c5c4a237a12.xva?compress=zstd' \
@@ -168,7 +168,7 @@ curl \
A VDI can be exported in VHD format at `/rest/v0/vdis/<uuid>.vhd` or the raw content at `/rest/v0/vdis/<uuid>.raw`.
```bash
```sh
curl \
-b authenticationToken=KQxQdm2vMiv7FkTbs \
'https://xoa.example.org/rest/v0/vdis/1a269782-ea93-4c4c-897a-475365f7b674.vhd' \
@@ -179,7 +179,7 @@ curl \
A VHD or a raw export can be imported on an SR to create a new VDI at `/rest/v0/srs/<sr uuid>/vdis`.
```bash
```sh
curl \
-X POST \
-b authenticationToken=KQxQdm2vMiv7jBIK0hgkmgxKzemd8wSJ7ugFGKFkTbs \

View File

@@ -20,7 +20,7 @@ XOA uses HVM mode. If your physical host doesn't support virtualization extensio
As no password is set for the xoa system user by default, you will need to set your own. This can be done via the XenStore data of the VM. The following is to be ran on your XCP-ng host:
```
```sh
xe vm-param-set uuid=<UUID> xenstore-data:vm-data/system-account-xoa-password=<password>
```
@@ -49,7 +49,6 @@ By default, XOA has a static max memory set to 16GiB. Sometimes you can have tro
```
"Failed","Migrating VM 'XOA' from '<origin_hostname>' to '<destination_hostname>'
Internal error: Xenops_interface.Internal_error("Domain.Xenguest_failure(\"Error while waiting for suspend notification: xenguest: xc_domain_save: [1] Save failed (0 = Success)\")")
```
In this case, it means you need to reduce the static max memory field to a lower value, and try again.
@@ -77,23 +76,23 @@ All XOA logs are stored in `/var/log/syslog` (on the XO Appliance).
To filter only what you need, you can use `journalctl`. Below is an example to filter only logs for `xo-server`:
```
$ journalctl -u xo-server -f -n 50
```sh
journalctl -u xo-server -f -n 50
```
This will return the 50 last lines and tail the file. If you have an error message in your application, start this command and try to reproduce the issue. You'll see clearly what the problem is.
You can also filter for the updater program:
```
$ journalctl -u xoa-updater -f -n 50
```sh
journalctl -u xoa-updater -f -n 50
```
## Configuration
XOA is a virtual appliance running Debian with Xen Orchestra installed. If you have any problems, the first thing to do is to use our check service by running the `xoa check` command in a terminal:
```
```console
$ xoa check
✔ Node version
✔ Disk space for /var
@@ -146,9 +145,9 @@ You should leave ~512MB for the debian OS itself. Meaning if your VM has 4096MB
The last step is to refresh and restart the service:
```
$ systemctl daemon-reload
$ systemctl restart xo-server
```sh
systemctl daemon-reload
systemctl restart xo-server
```
### Behind a transparent proxy
@@ -157,11 +156,11 @@ If you're behind a transparent proxy, you'll probably have issues with the updat
Run the following commands to allow the updater to work:
```
$ sudo -s
$ echo NODE_TLS_REJECT_UNAUTHORIZED=0 >> /etc/xo-appliance/env
$ npm config -g set strict-ssl=false
$ systemctl restart xoa-updater
```sh
sudo -s
echo NODE_TLS_REJECT_UNAUTHORIZED=0 >> /etc/xo-appliance/env
npm config -g set strict-ssl=false
systemctl restart xoa-updater
```
Now try running an update again.
@@ -172,20 +171,20 @@ If the provided certificate is expired, you may want to create a new one.
Connect to your appliance via SSH, then as root execute these commands:
```
$ cd /etc/ssl
$ cp cert.pem cert.pem-old
$ cp key.pem key.pem-old
$ openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -nodes -days 360
$ systemctl restart xo-server.service
```sh
cd /etc/ssl
cp cert.pem cert.pem-old
cp key.pem key.pem-old
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -nodes -days 360
systemctl restart xo-server.service
```
### Logs
The system logs are visible by using this command:
```
$ tail -f /var/log/syslog
```sh
tail -f /var/log/syslog
```
You can read more about logs [in the dedicated logs chapter](troubleshooting.md#logs).

View File

@@ -77,8 +77,8 @@ If your interface is not accessible, or you just prefer to use CLIs commands, it
#### Register
```
# xoa-updater --register
```console
$ xoa-updater --register
Successfully connected to xoa-updater-service
Please enter your xen-orchestra.com identifiers to register your XOA:
@@ -90,21 +90,20 @@ Please enter your xen-orchestra.com identifiers to register your XOA:
#### Check for new versions
```
# xoa-updater
```console
$ xoa-updater
Successfully connected to xoa-updater-service
Checking new versions...ok ✔
New versions available:
xo-server 4.8.1
xoa-updater may be run again to upgrade packages
```
#### Upgrade
```
# xoa-updater --upgrade
```console
$ xoa-updater --upgrade
Successfully connected to xoa-updater-service
Checking new versions...ok ✔
New versions available:
@@ -114,7 +113,6 @@ Downloading packages...
Installing new packages...
✔ Your XOA has been successfully updated.
```
## Troubleshooting

View File

@@ -28,7 +28,7 @@ Open a secure support tunnel so our team can remotely investigate on your XOA. F
If your web UI is not working, you can also open the secure support tunnel from the CLI. To open a private tunnel (we are the only one with the private key), you can use the command `xoa support tunnel` like below:
```
```console
$ xoa support tunnel
The support tunnel has been created.
@@ -60,7 +60,7 @@ Please only use this if you have issues with [the default way to deploy XOA](ins
Alternatively, you can deploy it by connecting to your XenServer host and executing the following:
```
```sh
bash -c "$(wget -qO- https://xoa.io/deploy)"
```
@@ -77,7 +77,7 @@ curl: (35) error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protoc
It means that the secure HTTPS protocol is not supported, you can bypass this using the unsecure command instead:
```
```sh
bash -c "$(wget -qO- http://xoa.io/deploy)"
```
@@ -107,7 +107,7 @@ If you connect via SSH or console for the first time without using our [web depl
Next, you can replace `<UUID>` with the UUID you found previously, and `<password>` with your password:
```
```sh
xe vm-param-set uuid=<UUID> xenstore-data:vm-data/system-account-xoa-password=<password>
```
@@ -123,8 +123,8 @@ You can now connect with the `xoa` username and password you defined in the prev
To avoid typing `sudo` for any admin command, you can have a root shell with `sudo -s`:
```
[05:24 27] xoa@xoa:~$ sudo -s
```console
$ sudo -s
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
@@ -134,15 +134,14 @@ Administrator. It usually boils down to these three things:
#3) With great power comes great responsibility.
[sudo] password for xoa:
[05:24 27] xoa:xoa$
$
```
## Network configuration
XOA uses **DHCP** by default, so if you need to configure the IP address, please run the command `xoa network static`. It will ask you network details:
```
```console
$ xoa network static
? Static IP for this machine 192.168.100.120
? Network mask (eg 255.255.255.0) 255.255.255.0
@@ -160,7 +159,7 @@ If you want to go back in DHCP, just run `xoa network dhcp`
If you need to configure other interfaces than `eth0`, you can use the same commands with the name of the interface to configure as supplementary argument:
```
```console
$ xoa network static eth1
? Static IP for this machine 192.168.100.120
? Network mask (eg 255.255.255.0) 255.255.255.0

View File

@@ -27,7 +27,7 @@
"promise-toolbox": "^0.21.0",
"semver": "^7.3.6",
"sorted-object": "^2.0.1",
"turbo": "^1.6.3",
"turbo": "^1.7.2",
"vue": "^2.7.14",
"vuepress": "^1.4.1"
},

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/complex-matcher):
```
> npm install --save complex-matcher
```sh
npm install --save complex-matcher
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/value-matcher):
```
> npm install --save value-matcher
```sh
npm install --save value-matcher
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/vhd-cli):
```
> npm install --global vhd-cli
```sh
npm install --global vhd-cli
```
## Contributions

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/vhd-lib):
```
> npm install --save vhd-lib
```sh
npm install --save vhd-lib
```
## Contributions

View File

@@ -0,0 +1,40 @@
'use strict'
/* eslint-env jest */
const fs = require('fs-extra')
const rimraf = require('rimraf')
const tmp = require('tmp')
const { getSyncedHandler } = require('@xen-orchestra/fs')
const { pFromCallback } = require('promise-toolbox')
const { checkFile, createRandomFile, convertFromRawToVhd } = require('./utils')
let tempDir = null
let disposeHandler
beforeEach(async () => {
tempDir = await pFromCallback(cb => tmp.dir(cb))
const d = await getSyncedHandler({ url: `file://${tempDir}` })
disposeHandler = d.dispose
})
afterEach(async () => {
await rimraf(tempDir)
disposeHandler()
})
test('checkFile fails with unvalid VHD file', async () => {
const initalSizeInMB = 4
const rawFileName = `${tempDir}/randomfile`
await createRandomFile(rawFileName, initalSizeInMB)
const vhdFileName = `${tempDir}/vhdFile.vhd`
await convertFromRawToVhd(rawFileName, vhdFileName)
await checkFile(vhdFileName)
const sizeToTruncateInByte = 250000
await fs.truncate(vhdFileName, sizeToTruncateInByte)
await expect(async () => await checkFile(vhdFileName)).rejects.toThrow()
})

View File

@@ -5,6 +5,7 @@ const { pipeline } = require('readable-stream')
const asyncIteratorToStream = require('async-iterator-to-stream')
const execa = require('execa')
const fs = require('fs-extra')
const fsPromise = require('node:fs/promises')
const { randomBytes } = require('crypto')
const createRandomStream = asyncIteratorToStream(function* (size) {
@@ -21,7 +22,11 @@ async function createRandomFile(name, sizeMB) {
exports.createRandomFile = createRandomFile
async function checkFile(vhdName) {
await execa('vhd-util', ['check', '-p', '-b', '-t', '-n', vhdName])
// Since the qemu-img check command isn't compatible with vhd format, we use
// the convert command to do a check by conversion. Indeed, the conversion will
// fail if the source file isn't a proper vhd format.
await execa('qemu-img', ['convert', '-fvpc', '-Oqcow2', vhdName, 'outputFile.qcow2'])
await fsPromise.unlink('./outputFile.qcow2')
}
exports.checkFile = checkFile

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/xapi-explore-sr):
```
> npm install --global xapi-explore-sr
```sh
npm install --global xapi-explore-sr
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/xen-api):
```
> npm install --save xen-api
```sh
npm install --save xen-api
```
## Usage

View File

@@ -39,7 +39,12 @@ defer(async ($defer, argv) => {
$defer(() => xapi.disconnect())
const { cancel, token } = CancelToken.source()
process.on('SIGINT', cancel)
process.once('SIGINT', () => {
cancel()
process.once('SIGINT', () => {
process.exit(1)
})
})
let input = createInputStream(opts._[1])
$defer.onFailure(() => input.destroy())
@@ -75,7 +80,5 @@ defer(async ($defer, argv) => {
},
})
if (result !== undefined) {
console.log(result)
}
console.log(result !== undefined ? result : 'ok')
})(process.argv.slice(2)).catch(console.error.bind(console, 'error'))

View File

@@ -11,8 +11,18 @@ import { coalesceCalls } from '@vates/coalesce-calls'
import { Collection } from 'xo-collection'
import { EventEmitter } from 'events'
import { Index } from 'xo-collection/index'
import { cancelable, defer, fromCallback, fromEvents, ignoreErrors, pDelay, pRetry, pTimeout } from 'promise-toolbox'
import { limitConcurrency } from 'limit-concurrency-decorator'
import {
cancelable,
CancelToken,
defer,
fromCallback,
fromEvent,
ignoreErrors,
pDelay,
pRetry,
pTimeout,
} from 'promise-toolbox'
import autoTransport from './transports/auto'
import debug from './_debug'
@@ -90,6 +100,7 @@ export class Xapi extends EventEmitter {
opts.syncStackTraces ?? process.env.NODE_ENV === 'development' ? addSyncStackTrace : identity
this._callTimeout = makeCallSetting(opts.callTimeout, 60 * 60 * 1e3) // 1 hour but will be reduced in the future
this._httpInactivityTimeout = opts.httpInactivityTimeout ?? 5 * 60 * 1e3 // 5 mins
this._httpTimeout = opts.httpTimeout ?? 24 * 60 * 60 * 1e3 // 24 hours
this._eventPollDelay = opts.eventPollDelay ?? 60 * 1e3 // 1 min
this._pool = null
this._readOnly = Boolean(opts.readOnly)
@@ -152,13 +163,14 @@ export class Xapi extends EventEmitter {
this._resolveObjectsFetched = resolve
})
this._eventWatchers = { __proto__: null }
this._taskWatchers = { __proto__: null }
this._taskWatchers = undefined // set in _watchEvents
this._watchedTypes = undefined
const { watchEvents } = opts
if (watchEvents !== false) {
if (Array.isArray(watchEvents)) {
this._watchedTypes = watchEvents
}
this.watchEvents()
}
}
@@ -368,6 +380,13 @@ export class Xapi extends EventEmitter {
@cancelable
async getResource($cancelToken, pathname, { host, query, task } = {}) {
const timeout = this._httpTimeout
if (timeout !== 0) {
const source = CancelToken.source([$cancelToken])
setTimeout(source.cancel, timeout)
$cancelToken = source.token
}
const taskRef = await this._autoTask(task, `Xapi#getResource ${pathname}`)
query = { ...query, session_id: this.sessionId }
@@ -430,6 +449,13 @@ export class Xapi extends EventEmitter {
throw new Error('cannot put resource in read only mode')
}
const timeout = this._httpTimeout
if (timeout !== 0) {
const source = CancelToken.source([$cancelToken])
setTimeout(source.cancel, timeout)
$cancelToken = source.token
}
const taskRef = await this._autoTask(task, `Xapi#putResource ${pathname}`)
query = { ...query, session_id: this.sessionId }
@@ -518,26 +544,48 @@ export class Xapi extends EventEmitter {
)
: doRequest(url.href)
)
const responseEnd = fromEvent(response, 'end')
responseEnd.catch(noop)
console.log({ useHack })
if (pTaskResult !== undefined) {
pTaskResult = pTaskResult.catch(error => {
error.url = response.url
throw error
})
}
if (useHack) {
// In case of the hack, ignore (but log) the very probably `VDI_IO_ERROR` because it is usually irrelevant
pTaskResult = pTaskResult.catch(error => {
console.warn(this._humanId, 'Xapi#putResource', pathname, error)
})
} else {
pTaskResult = pTaskResult.catch(error => {
error.url = response.url
throw error
})
if (!useHack) {
// consume the response
response.resume()
return pTaskResult
// avoid unhandled rejection in case the upload fails
pTaskResult.catch(noop)
}
}
const { req } = response
if (!req.finished) {
await fromEvents(req, ['close', 'finish'])
console.log('waiting for request to finish')
await new Promise((resolve, reject) => {
req.on('finish', resolve).on('error', reject)
response.on('error', reject)
})
console.log('request finished')
}
response.cancel()
if (useHack) {
response.cancel()
} else {
// consume the response
response.resume()
await new Promise((resolve, reject) => {
response.on('end', resolve).on('error', reject)
})
}
return pTaskResult
}
@@ -949,7 +997,7 @@ export class Xapi extends EventEmitter {
}
const taskWatchers = this._taskWatchers
const taskWatcher = taskWatchers[ref]
const taskWatcher = taskWatchers?.[ref]
if (taskWatcher !== undefined) {
const result = getTaskResult(object)
if (result !== undefined) {
@@ -1051,7 +1099,7 @@ export class Xapi extends EventEmitter {
}
const taskWatchers = this._taskWatchers
const taskWatcher = taskWatchers[ref]
const taskWatcher = taskWatchers?.[ref]
if (taskWatcher !== undefined) {
const error = new Error('task has been destroyed before completion')
error.task = object
@@ -1069,6 +1117,13 @@ export class Xapi extends EventEmitter {
_watchEvents = coalesceCalls(this._watchEvents)
// eslint-disable-next-line no-dupe-class-members
async _watchEvents() {
{
const watchedTypes = this._watchedTypes
if (this._taskWatchers === undefined && (watchedTypes === undefined || watchedTypes.includes('task'))) {
this._taskWatchers = { __proto__: null }
}
}
// eslint-disable-next-line no-labels
mainLoop: while (true) {
if (this._resolveObjectsFetched === undefined) {

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/xo-acl-resolver):
```
> npm install --save xo-acl-resolver
```sh
npm install --save xo-acl-resolver
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/xo-cli):
```
> npm install --global xo-cli
```sh
npm install --global xo-cli
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/xo-collection):
```
> npm install --save xo-collection
```sh
npm install --save xo-collection
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/xo-common):
```
> npm install --save xo-common
```sh
npm install --save xo-common
```
## Contributions

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/xo-import-servers-csv):
```
> npm install --global xo-import-servers-csv
```sh
npm install --global xo-import-servers-csv
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/xo-lib):
```
> npm install --save xo-lib
```sh
npm install --save xo-lib
```
## Usage

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/xo-remote-parser):
```
> npm install --save xo-remote-parser
```sh
npm install --save xo-remote-parser
```
## Contributions

View File

@@ -132,7 +132,10 @@ port = 80
#
# This breaks a number of XO use cases, for instance uploading a VDI via the
# REST API, therefore it's changed to 1 day.
requestTimeout = 86400000
#
# Completely disabled for now because it appears to be broken:
# https://github.com/nodejs/node/issues/46574
requestTimeout = 0
[http.mounts]
'/' = '../xo-web/dist'

View File

@@ -2,10 +2,10 @@
## Expose VHD disk as block device
```
> mkdir /tmp/vhd-mount
> vhdimount 20201008T074128Z.vhd /tmp/vhd-mount
> ls /tmp/vhd-mount
```console
$ mkdir /tmp/vhd-mount
$ vhdimount 20201008T074128Z.vhd /tmp/vhd-mount
$ ls /tmp/vhd-mount
vhdi1
vhdi2
```
@@ -14,30 +14,30 @@ vhdi2
When device no longer necessary:
```
> fusermount -uz /tmp/vhd-mount
> rmdir /tmp/vhd-mount
```console
$ fusermount -uz /tmp/vhd-mount
$ rmdir /tmp/vhd-mount
```
## List available partitions
Partitionned disk:
```
> partx --bytes --output=NR,START,SIZE,NAME,UUID,TYPE --pairs /tmp/vhd-mount/vhdi2
```console
$ partx --bytes --output=NR,START,SIZE,NAME,UUID,TYPE --pairs /tmp/vhd-mount/vhdi2
NR="1" START="2048" SIZE="254803968" NAME="" UUID="c8d70417-01" TYPE="0x83"
NR="2" START="501758" SIZE="8331985920" NAME="" UUID="c8d70417-02" TYPE="0x5"
NR="5" START="501760" SIZE="8331984896" NAME="" UUID="c8d70417-05" TYPE="0x8e"
> echo $?
$ echo $?
0
```
Non-partionned disk:
```
> partx --bytes --output=NR,START,SIZE,NAME,UUID,TYPE --pairs /tmp/vhd-mount/vhdi2
```console
$ partx --bytes --output=NR,START,SIZE,NAME,UUID,TYPE --pairs /tmp/vhd-mount/vhdi2
partx: /tmp/vhd-mount/vhdi2: failed to read partition table
> echo $?
$ echo $?
1
```
@@ -45,58 +45,58 @@ partx: /tmp/vhd-mount/vhdi2: failed to read partition table
> Tip: `offset` and `sizelimit` are only required on a partionned disk
```
> losetup -o $(($START * 512)) --sizelimit $(($SIZE)) --show -f /tmp/vhd-mount/vhdi2
```console
$ losetup -o $(($START * 512)) --sizelimit $(($SIZE)) --show -f /tmp/vhd-mount/vhdi2
/dev/loop0
> pvscan --cache /dev/loop0
$ pvscan --cache /dev/loop0
```
When logical volumes no longer necessary:
```
> pvs --noheading --nosuffix --nameprefixes --unbuffered --units b -o vg_name /dev/loop0
```console
$ pvs --noheading --nosuffix --nameprefixes --unbuffered --units b -o vg_name /dev/loop0
LVM2_VG_NAME='debian-vg'
> vgchange -an debian-vg
> losetup -d /dev/loop0
$ vgchange -an debian-vg
$ losetup -d /dev/loop0
```
## List available LVM logical volumes
```
> pvs --noheading --nosuffix --nameprefixes --unbuffered --units b -o lv_name,lv_path,lv_size,vg_name /dev/loop0
```console
$ pvs --noheading --nosuffix --nameprefixes --unbuffered --units b -o lv_name,lv_path,lv_size,vg_name /dev/loop0
LVM2_LV_NAME='root' LVM2_LV_PATH='/dev/debian-vg/root' LVM2_LV_SIZE='7935623168' LVM2_VG_NAME='debian-vg'
LVM2_LV_NAME='swap_1' LVM2_LV_PATH='/dev/debian-vg/swap_1' LVM2_LV_SIZE='394264576' LVM2_VG_NAME='debian-vg'
```
## Mount LVM logical volume
```
> vgchange -ay debian-vg
> lvs --noheading --nosuffix --nameprefixes --unbuffered --units b -o lv_name,lv_path
```console
$ vgchange -ay debian-vg
$ lvs --noheading --nosuffix --nameprefixes --unbuffered --units b -o lv_name,lv_path
LVM2_LV_NAME='root' LVM2_LV_PATH='/dev/debian-vg/root'
LVM2_LV_NAME='swap_1' LVM2_LV_PATH='/dev/debian-vg/swap_1'
```
When logical volume no longer necessary:
```
> vgchange -an debian-vg
```sh
vgchange -an debian-vg
```
## Mount block device
> Tip: `offset` and `sizelimit` are only required on a partionned disk
```
> mkdir /tmp/block-mount
> mount --options=loop,ro,norecovery,offset=$(($START * 512)),sizelimit=$(($SIZE)) --source=/tmp/vhd-mount/vhdi2 --target=/tmp/block-mount
> ls /tmp/block-mount
```console
$ mkdir /tmp/block-mount
$ mount --options=loop,ro,norecovery,offset=$(($START * 512)),sizelimit=$(($SIZE)) --source=/tmp/vhd-mount/vhdi2 --target=/tmp/block-mount
$ ls /tmp/block-mount
bin boot dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys @System.solv tmp usr var
```
When mountpoint no longer necessary:
```
> umount --lazy /tmp/block-mount
> rmdir /tmp/block-mount
```sh
umount --lazy /tmp/block-mount
rmdir /tmp/block-mount
```

View File

@@ -33,7 +33,7 @@ Set-Cookie: authenticationToken=KQxQdm2vMiv7jBIK0hgkmgxKzemd8wSJ7ugFGKFkTbs
Usage with cURL:
```bash
```sh
curl -b \
authenticationToken=KQxQdm2vMiv7jBIK0hgkmgxKzemd8wSJ7ugFGKFkTbs \
https://xo.company.lan/rest/v0/
@@ -41,7 +41,7 @@ curl -b \
You can use `xo-cli` to create an authentication token:
```bash
```sh
$ xo-cli --createToken xoa.company.lan admin@admin.net
Password: ********
Successfully logged with admin@admin.net
@@ -118,7 +118,7 @@ Content-Type: application/x-ndjson
> This feature is restricted to `name_label` and `name_description` at the moment.
```bash
```sh
curl \
-X PATCH \
-b authenticationToken=KQxQdm2vMiv7jBIK0hgkmgxKzemd8wSJ7ugFGKFkTbs \
@@ -130,7 +130,7 @@ curl \
## VM destruction
```bash
```sh
curl \
-X DELETE \
-b authenticationToken=KQxQdm2vMiv7jBIK0hgkmgxKzemd8wSJ7ugFGKFkTbs \
@@ -146,7 +146,7 @@ By default, the XVA is not compressed, however the `compress` query parameter su
- `gzip`: use [gzip](https://en.wikipedia.org/wiki/Gzip) compression (very slow)
- `zstd`: use [Zstandard](https://en.wikipedia.org/wiki/Zstd) compression (fast, only supported on XCP-ng)
```bash
```sh
curl \
-b authenticationToken=KQxQdm2vMiv7jBIK0hgkmgxKzemd8wSJ7ugFGKFkTbs \
'https://xo.company.lan/rest/v0/vms/770aa52a-fd42-8faf-f167-8c5c4a237cac.xva?compress=zstd' \
@@ -155,7 +155,7 @@ curl \
## VDI destruction
```bash
```sh
curl \
-X DELETE \
-b authenticationToken=KQxQdm2vMiv7jBIK0hgkmgxKzemd8wSJ7ugFGKFkTbs \
@@ -166,7 +166,7 @@ curl \
A VDI can be exported in VHD format at `/rest/v0/vdis/<uuid>.vhd` or the raw content at `/rest/v0/vdis/<uuid>.raw`.
```bash
```sh
curl \
-b authenticationToken=KQxQdm2vMiv7jBIK0hgkmgxKzemd8wSJ7ugFGKFkTbs \
'https://xo.company.lan/rest/v0/vdis/1a269782-ea93-4c4c-897a-475365f7b674.vhd' \
@@ -177,7 +177,7 @@ curl \
A VHD or a raw export can be imported on an SR to create a new VDI at `/rest/v0/srs/<sr uuid>/vdis`.
```bash
```sh
curl \
-X POST \
-b authenticationToken=KQxQdm2vMiv7jBIK0hgkmgxKzemd8wSJ7ugFGKFkTbs \

View File

@@ -17,10 +17,17 @@ xo-server-recover-account <user name or email>
`
}
let password = await new Promise(resolve => {
process.stdout.write('Password (leave empty for random): ')
pw(resolve)
})
const support = name === '-s'
if (support) {
name = 'xoa-support'
}
let password = support
? ''
: await new Promise(resolve => {
process.stdout.write('Password (leave empty for random): ')
pw(resolve)
})
if (password === '') {
password = await generateToken(10)

View File

@@ -150,6 +150,32 @@ export default class RestApi {
)
})
)
// should go before routes /:collection/:object because they will match but
// will not work due to the extension being included in the object identifer
api.get(
'/:collection(vdis|vdi-snapshots)/:object.:format(vhd|raw)',
wrap(async (req, res) => {
const stream = await req.xapiObject.$exportContent({ format: req.params.format })
stream.headers['content-disposition'] = 'attachment'
res.writeHead(stream.statusCode, stream.statusMessage != null ? stream.statusMessage : '', stream.headers)
await fromCallback(pipeline, stream, res)
})
)
api.get(
'/:collection(vms|vm-snapshots|vm-templates)/:object.xva',
wrap(async (req, res) => {
const stream = await req.xapiObject.$export({ compress: req.query.compress })
stream.headers['content-disposition'] = 'attachment'
res.writeHead(stream.statusCode, stream.statusMessage != null ? stream.statusMessage : '', stream.headers)
await fromCallback(pipeline, stream, res)
})
)
api.get('/:collection/:object', (req, res) => {
res.json(req.xoObject)
})
@@ -173,7 +199,7 @@ export default class RestApi {
)
api.post(
'/srs/:object/vdis',
'/:collection(srs)/:object/vdis',
wrap(async (req, res) => {
const sr = req.xapiObject
req.length = +req.headers['content-length']
@@ -196,29 +222,5 @@ export default class RestApi {
res.sendStatus(200)
})
)
api.get(
'/:collection(vdis|vdi-snapshots)/:object.:format(vhd|raw)',
wrap(async (req, res) => {
const stream = await req.xapiObject.$exportContent({ format: req.params.format })
stream.headers['content-disposition'] = 'attachment'
res.writeHead(stream.statusCode, stream.statusMessage != null ? stream.statusMessage : '', stream.headers)
await fromCallback(pipeline, stream, res)
})
)
api.get(
'/:collection(vms|vm-snapshots|vm-templates)/:object.xva',
wrap(async (req, res) => {
const stream = await req.xapiObject.$export({ compress: req.query.compress })
stream.headers['content-disposition'] = 'attachment'
res.writeHead(stream.statusCode, stream.statusMessage != null ? stream.statusMessage : '', stream.headers)
await fromCallback(pipeline, stream, res)
})
)
}
}

View File

@@ -10,8 +10,8 @@
Installation of the [npm package](https://npmjs.org/package/xo-vmdk-to-vhd):
```
> npm install --save xo-vmdk-to-vhd
```sh
npm install --save xo-vmdk-to-vhd
```
## Usage

View File

@@ -12,6 +12,7 @@ import { vmdkToVhd, readVmdkGrainTable } from '.'
import VMDKDirectParser from './vmdk-read'
import { generateVmdkData } from './vmdk-generate'
import asyncIteratorToStream from 'async-iterator-to-stream'
import fs from 'fs'
const initialDir = process.cwd()
jest.setTimeout(100000)
@@ -36,6 +37,14 @@ function bufferToArray(buffer) {
return res
}
async function checkFile(vhdName) {
// Since the qemu-img check command isn't compatible with vhd format, we use
// the convert command to do a check by conversion. Indeed, the conversion will
// fail if the source file isn't a proper vhd format.
await execa('qemu-img', ['convert', '-fvpc', '-Oqcow2', vhdName, 'outputFile.qcow2'])
await fs.promises.unlink('./outputFile.qcow2')
}
function createFileAccessor(file) {
return async (start, end) => {
if (start < 0 || end < 0) {
@@ -71,7 +80,7 @@ test('VMDK to VHD can convert a random data file with VMDKDirectParser', async (
)
).pipe(createWriteStream(vhdFileName))
await fromEvent(pipe, 'finish')
await execa('vhd-util', ['check', '-p', '-b', '-t', '-n', vhdFileName])
await checkFile(vhdFileName)
await execa('qemu-img', ['convert', '-fvmdk', '-Oraw', vmdkFileName, reconvertedFromVmdk])
await execa('qemu-img', ['convert', '-fvpc', '-Oraw', vhdFileName, reconvertedFromVhd])
await execa('qemu-img', ['compare', inputRawFileName, vhdFileName])

View File

@@ -15,8 +15,8 @@
Installation of the [npm package](https://npmjs.org/package/{{pkg.name}}):
```
> npm install --{{#if pkg.preferGlobal}}global{{^}}save{{/if}} {{pkg.name}}
```sh
npm install --{{#if pkg.preferGlobal}}global{{^}}save{{/if}} {{pkg.name}}
```
{{/unless}}

View File

@@ -2,7 +2,17 @@
"$schema": "https://turborepo.org/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"]
"dependsOn": ["^build"],
"outputMode": "errors-only",
"outputs": ["dist/**"]
},
"dev": {
"dependsOn": ["^build"],
"persistent": true
},
"test": {
"dependsOn": ["build"],
"outputMode": "errors-only"
}
}
}

2393
yarn.lock

File diff suppressed because it is too large Load Diff