vagrant-xapi 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +83 -0
- data/LICENSE +21 -0
- data/README.md +460 -4
- data/docs/architecture.md +1420 -0
- data/docs/operations.md +531 -0
- data/lib/vagrant-xapi/action/base.rb +103 -0
- data/lib/vagrant-xapi/action/cloud_init.rb +130 -0
- data/lib/vagrant-xapi/action/create.rb +127 -0
- data/lib/vagrant-xapi/action/destroy.rb +68 -0
- data/lib/vagrant-xapi/action/network.rb +229 -0
- data/lib/vagrant-xapi/action/package.rb +103 -0
- data/lib/vagrant-xapi/action/power.rb +185 -0
- data/lib/vagrant-xapi/action/snapshots.rb +43 -0
- data/lib/vagrant-xapi/action.rb +317 -0
- data/lib/vagrant-xapi/api/client.rb +393 -0
- data/lib/vagrant-xapi/api/errors.rb +98 -0
- data/lib/vagrant-xapi/api/http_transfer.rb +332 -0
- data/lib/vagrant-xapi/api/redactor.rb +77 -0
- data/lib/vagrant-xapi/api/session_registry.rb +59 -0
- data/lib/vagrant-xapi/api/task.rb +156 -0
- data/lib/vagrant-xapi/api/transport.rb +249 -0
- data/lib/vagrant-xapi/cap.rb +90 -0
- data/lib/vagrant-xapi/command/adopt.rb +92 -0
- data/lib/vagrant-xapi/command/base.rb +79 -0
- data/lib/vagrant-xapi/command/console.rb +87 -0
- data/lib/vagrant-xapi/command/diff.rb +267 -0
- data/lib/vagrant-xapi/command/hosts.rb +63 -0
- data/lib/vagrant-xapi/command/info.rb +94 -0
- data/lib/vagrant-xapi/command/marked.rb +85 -0
- data/lib/vagrant-xapi/command/orphans.rb +96 -0
- data/lib/vagrant-xapi/command/root.rb +55 -0
- data/lib/vagrant-xapi/command/templates.rb +91 -0
- data/lib/vagrant-xapi/config.rb +333 -0
- data/lib/vagrant-xapi/errors.rb +113 -0
- data/lib/vagrant-xapi/extensions.rb +80 -0
- data/lib/vagrant-xapi/glue.rb +330 -0
- data/lib/vagrant-xapi/legacy/plugin.rb +61 -0
- data/lib/vagrant-xapi/legacy/xenapi.rb +129 -0
- data/lib/vagrant-xapi/plugin.rb +58 -0
- data/lib/vagrant-xapi/provider.rb +135 -0
- data/lib/vagrant-xapi/services/adoption.rb +73 -0
- data/lib/vagrant-xapi/services/base.rb +242 -0
- data/lib/vagrant-xapi/services/box_source.rb +218 -0
- data/lib/vagrant-xapi/services/console.rb +115 -0
- data/lib/vagrant-xapi/services/content_diff.rb +96 -0
- data/lib/vagrant-xapi/services/destroyer.rb +104 -0
- data/lib/vagrant-xapi/services/diff_disks.rb +346 -0
- data/lib/vagrant-xapi/services/differ.rb +382 -0
- data/lib/vagrant-xapi/services/disk_image.rb +122 -0
- data/lib/vagrant-xapi/services/disks.rb +281 -0
- data/lib/vagrant-xapi/services/exporter.rb +128 -0
- data/lib/vagrant-xapi/services/file_diff.rb +249 -0
- data/lib/vagrant-xapi/services/guest_files.rb +730 -0
- data/lib/vagrant-xapi/services/hosts.rb +55 -0
- data/lib/vagrant-xapi/services/image_upload.rb +172 -0
- data/lib/vagrant-xapi/services/inventory.rb +225 -0
- data/lib/vagrant-xapi/services/ip_detector.rb +107 -0
- data/lib/vagrant-xapi/services/lock.rb +293 -0
- data/lib/vagrant-xapi/services/lookup.rb +181 -0
- data/lib/vagrant-xapi/services/networks.rb +248 -0
- data/lib/vagrant-xapi/services/power.rb +108 -0
- data/lib/vagrant-xapi/services/rfb.rb +129 -0
- data/lib/vagrant-xapi/services/snapshots.rb +81 -0
- data/lib/vagrant-xapi/services/template_cache.rb +263 -0
- data/lib/vagrant-xapi/services/tunnels.rb +217 -0
- data/lib/vagrant-xapi/services/vm_builder.rb +215 -0
- data/lib/vagrant-xapi/version.rb +7 -0
- data/lib/vagrant-xapi/xenserver/config.rb +69 -0
- data/lib/vagrant-xapi/xenserver/migrate.rb +103 -0
- data/lib/vagrant-xapi/xenserver/plugin.rb +96 -0
- data/lib/vagrant-xapi/xenserver/provider.rb +22 -0
- data/lib/vagrant-xapi/xenserver/takeover.rb +79 -0
- data/lib/vagrant-xapi.rb +21 -2
- data/lib/xenapi.rb +22 -0
- data/locales/en.yml +517 -0
- data/locales/legacy.en.yml +6 -0
- metadata +86 -5
data/docs/operations.md
ADDED
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
# Operations
|
|
2
|
+
|
|
3
|
+
How to run vagrant-xapi against a pool, keep the pool clean, find out what
|
|
4
|
+
went wrong, and work on the plugin itself. For the design behind it see
|
|
5
|
+
[architecture.md](architecture.md); for the provider options see the
|
|
6
|
+
[README](../README.md).
|
|
7
|
+
|
|
8
|
+
## 1. What is needed
|
|
9
|
+
|
|
10
|
+
On the local machine:
|
|
11
|
+
|
|
12
|
+
| Tool | Needed for |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| Vagrant 2.4.x | everything |
|
|
15
|
+
| `ssh` | `vagrant ssh`, port forwarding tunnels, `ssh_via_host` |
|
|
16
|
+
| `rsync` | rsync synced folders |
|
|
17
|
+
| `qemu-img` | qcow2 boxes on a host that cannot import qcow2, and qcow2 images with compressed clusters (most cloud images and many libvirt boxes), which XAPI cannot import directly (`brew install qemu`, `apt install qemu-utils`) |
|
|
18
|
+
| `mkisofs`/`genisoimage` (Linux) or `hdiutil` (macOS) | cloud-init; Vagrant's `create_iso` host capability uses them |
|
|
19
|
+
| a VNC viewer | `vagrant xapi console`; macOS Screen Sharing works (it gets the one-time password in the URL) |
|
|
20
|
+
|
|
21
|
+
On the pool:
|
|
22
|
+
|
|
23
|
+
- XenServer 8 or XCP-ng 8.3.
|
|
24
|
+
- A default SR, or `sr` set in the Vagrantfile.
|
|
25
|
+
- The template `Other install media` (present on every standard install);
|
|
26
|
+
needed to import disk-image boxes.
|
|
27
|
+
- For `snapshot_memory` and `suspend`: a suspend SR and PV drivers or a guest
|
|
28
|
+
agent in the guest.
|
|
29
|
+
- For `vtpm`: a version with the `VTPM` class (XAPI is checked at login).
|
|
30
|
+
|
|
31
|
+
## 2. Connecting
|
|
32
|
+
|
|
33
|
+
Put the credentials in the environment, not in a Vagrantfile in git:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
export VAGRANT_XAPI_HOST=xcp-master.example.com
|
|
37
|
+
export VAGRANT_XAPI_USERNAME=vagrant-svc
|
|
38
|
+
export VAGRANT_XAPI_PASSWORD='...'
|
|
39
|
+
# optional: the network of the first VIF when a Vagrantfile has no
|
|
40
|
+
# public_network (name, UUID or bridge such as xenbr1)
|
|
41
|
+
export VAGRANT_XAPI_DEFAULT_NETWORK=xenbr1
|
|
42
|
+
# optional: TLS for self-signed certificates (the pins of all hosts,
|
|
43
|
+
# separated by commas) or your own CA, instead of tls_fingerprint or
|
|
44
|
+
# tls_ca_file in the Vagrantfile
|
|
45
|
+
export VAGRANT_XAPI_TLS_FINGERPRINT=AB:CD:...,12:34:...
|
|
46
|
+
export VAGRANT_XAPI_TLS_CA_FILE=~/certs/pool-ca.pem
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Vagrantfiles written for vagrant-xenserver (`config.vm.provider
|
|
50
|
+
"xenserver"` with `xs_*` options) keep working unchanged; see "Migrating
|
|
51
|
+
from vagrant-xenserver" in the README and section 17 of architecture.md.
|
|
52
|
+
Only the stand-in for the `xenapi` gem, for triggers that call XAPI
|
|
53
|
+
themselves, is temporary.
|
|
54
|
+
|
|
55
|
+
`host` may be any host of the pool; a pool member redirects to the master.
|
|
56
|
+
With fingerprint pinning that needs the pins of all hosts (see below).
|
|
57
|
+
|
|
58
|
+
### TLS
|
|
59
|
+
|
|
60
|
+
The certificate is always verified. Three ways to make that work:
|
|
61
|
+
|
|
62
|
+
1. **A certificate from a CA the local machine trusts**: nothing to configure.
|
|
63
|
+
2. **Your own CA**: `xapi.tls_ca_file = "~/certs/pool-ca.pem"`.
|
|
64
|
+
3. **Self-signed** (the default after installing XCP-ng/XenServer): pin the
|
|
65
|
+
SHA-256 fingerprint of the host certificate.
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
openssl s_client -connect xcp-master.example.com:443 </dev/null 2>/dev/null \
|
|
69
|
+
| openssl x509 -noout -fingerprint -sha256
|
|
70
|
+
# sha256 Fingerprint=AB:CD:...
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Without a pin, the error for a self-signed certificate shows the same
|
|
74
|
+
fingerprint of the certificate it got. Before you pin it, check it on the
|
|
75
|
+
host itself, where nothing can sit in between:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
# on the host (dom0)
|
|
79
|
+
openssl x509 -noout -fingerprint -sha256 -in /etc/xensource/xapi-ssl.pem
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
config.vm.provider :xapi do |xapi|
|
|
84
|
+
xapi.tls_fingerprint = "AB:CD:..." # with or without colons
|
|
85
|
+
end
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Every pool member has its own certificate. One pin only matches one host, so
|
|
89
|
+
either pin the master and use it as `host` (with a single pin on a member,
|
|
90
|
+
the plugin stops and names the master), or pin the certificates of all
|
|
91
|
+
hosts. Then any host can be `host`, and a change of master (HA, or
|
|
92
|
+
`xe pool-designate-new-master`) does not break the configuration:
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
vagrant xapi hosts # once connected to the master: every host's fingerprint
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
config.vm.provider :xapi do |xapi|
|
|
100
|
+
xapi.tls_fingerprint = ["AB:CD:...", "12:34:..."] # or one string with commas
|
|
101
|
+
end
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Uploads, downloads and consoles that run on another
|
|
105
|
+
member use the certificate the master reports for that member
|
|
106
|
+
(`host.get_server_certificate`), so they need no extra configuration. After
|
|
107
|
+
a certificate renewal (e.g. `xe host-refresh-server-certificate`) the pin
|
|
108
|
+
must be updated; the error says "certificate fingerprint ... does not
|
|
109
|
+
match".
|
|
110
|
+
|
|
111
|
+
`vagrant xapi hosts --pem` prints the certificates themselves, e.g. for a
|
|
112
|
+
`tls_ca_file`. With a CA file the hostname is checked, so the address used
|
|
113
|
+
must be in the certificate: the member's, and the master's as XAPI reports
|
|
114
|
+
it on the redirect (its IP address). The self-signed certificates of
|
|
115
|
+
XCP-ng and XenServer do not contain those IP addresses; pin them instead.
|
|
116
|
+
|
|
117
|
+
### Which user and role
|
|
118
|
+
|
|
119
|
+
With `pool-admin` everything works. The plugin needs to:
|
|
120
|
+
|
|
121
|
+
- create, change, start, stop and destroy VMs, VDIs, VBDs, VIFs, snapshots;
|
|
122
|
+
- import and export (`/import`, `/import_raw_vdi`, `/export`);
|
|
123
|
+
- write `pool.other_config` (locks);
|
|
124
|
+
- create and destroy networks (internal networks for `private_network`).
|
|
125
|
+
|
|
126
|
+
`vm-admin` covers the VM part, but may not cover the last two. Then `vagrant
|
|
127
|
+
up` stops with "The XAPI user may not write the pool's other_config ...".
|
|
128
|
+
|
|
129
|
+
## 3. Boxes
|
|
130
|
+
|
|
131
|
+
### Kinds
|
|
132
|
+
|
|
133
|
+
| Box provider | Use |
|
|
134
|
+
| --- | --- |
|
|
135
|
+
| `xapi` | Our own format: `metadata.json` (`provider`, `format`, `architecture`) and `box.<format>` (xva, vhd, qcow2 or raw) |
|
|
136
|
+
| `xenserver` | Boxes of vagrant-xenserver: `box.xva`, `box.vhd`, or a Vagrantfile with `xva_url` |
|
|
137
|
+
| `libvirt` | qcow2 boxes from the libvirt ecosystem (e.g. `generic/*`); they need cloud-init and a static IP when they have no Xen guest agent |
|
|
138
|
+
|
|
139
|
+
Vagrant chooses between providers of the same box version in this order:
|
|
140
|
+
`xapi`, `xenserver`, `libvirt`.
|
|
141
|
+
|
|
142
|
+
Always set `config.vm.box_architecture = "amd64"`: XenServer and XCP-ng only
|
|
143
|
+
run amd64 guests, and on a Mac with Apple silicon Vagrant otherwise looks for
|
|
144
|
+
an arm64 box. For the same reason, add a box *file* with
|
|
145
|
+
`vagrant box add --architecture amd64 ...`: Vagrant stores a local box file
|
|
146
|
+
under the local machine's architecture (it ignores `architecture` in its
|
|
147
|
+
`metadata.json`), and a Vagrantfile asking for amd64 then does not find it
|
|
148
|
+
and tries to download it instead ("could not be found in the remote
|
|
149
|
+
catalog"). Boxes from a registry carry their architecture and need nothing
|
|
150
|
+
extra. To remove a box added under the wrong architecture, use
|
|
151
|
+
`vagrant box remove <name> --all-architectures --force` or delete
|
|
152
|
+
`~/.vagrant.d/boxes/<name with / as -VAGRANTSLASH->/<version>/arm64`;
|
|
153
|
+
`vagrant box remove --architecture` does not match any box (Vagrant
|
|
154
|
+
compares the option as a string with symbols).
|
|
155
|
+
|
|
156
|
+
### Building a box
|
|
157
|
+
|
|
158
|
+
The recommended route is
|
|
159
|
+
[packer-plugin-xenserver](https://github.com/vatesfr/packer-plugin-xenserver),
|
|
160
|
+
producing an XVA with a guest agent (xe-guest-utilities or xen-guest-agent)
|
|
161
|
+
and cloud-init installed. Then:
|
|
162
|
+
|
|
163
|
+
```sh
|
|
164
|
+
cat > metadata.json <<'EOF'
|
|
165
|
+
{"provider": "xapi", "format": "xva", "architecture": "amd64"}
|
|
166
|
+
EOF
|
|
167
|
+
cat > Vagrantfile <<'EOF'
|
|
168
|
+
Vagrant.configure("2") do |config|
|
|
169
|
+
config.vm.provider :xapi do |xapi|
|
|
170
|
+
xapi.firmware = :uefi # whatever the image was built with
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
EOF
|
|
174
|
+
cp output/debian-12.xva box.xva
|
|
175
|
+
tar czf debian-12.box metadata.json Vagrantfile box.xva
|
|
176
|
+
vagrant box add --architecture amd64 --name acme/debian-12 debian-12.box
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Or make a box from a running machine with `vagrant package` (XVA by default,
|
|
180
|
+
`package_format = :vhd` or `:qcow2` for only the first disk). Remove SSH host
|
|
181
|
+
keys and `/etc/machine-id` in the guest first if the box will be shared.
|
|
182
|
+
|
|
183
|
+
The box needs the Vagrant insecure key (or a configured
|
|
184
|
+
`config.ssh.private_key_path`) for the `vagrant` user, as with any provider.
|
|
185
|
+
|
|
186
|
+
## 4. Templates
|
|
187
|
+
|
|
188
|
+
Each box version is imported once per SR as a template named
|
|
189
|
+
`vagrant-xapi: <box> <version>`. Templates are shared by every user of the
|
|
190
|
+
pool and take disk space on the SR.
|
|
191
|
+
|
|
192
|
+
```sh
|
|
193
|
+
vagrant xapi templates list # box, version, SR, size, clones
|
|
194
|
+
vagrant xapi templates prune --keep 1 # per box: keep the newest version
|
|
195
|
+
vagrant xapi templates remove "acme/debian-12 1.2.0"
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
`prune` and `remove` show which other users still have clones, and ask for
|
|
199
|
+
confirmation (`--force` skips that). Removing a template does not break its
|
|
200
|
+
clones: the storage layer keeps the shared base disk. The next `vagrant up`
|
|
201
|
+
with that box version imports it again.
|
|
202
|
+
|
|
203
|
+
The first `up` with a new box (or on a new SR) uploads and imports it; this
|
|
204
|
+
can take a while for large boxes (`task_timeout`, default one hour). A second
|
|
205
|
+
user starting the same box at the same time waits for the first import
|
|
206
|
+
("Waiting for lock 'template....' held by ...") instead of importing again.
|
|
207
|
+
|
|
208
|
+
## 5. Finding what the plugin created
|
|
209
|
+
|
|
210
|
+
Everything the plugin creates is marked (full list in architecture.md,
|
|
211
|
+
section 6). `vagrant xapi marked` lists it through XAPI, with the normal
|
|
212
|
+
connection settings, from any directory whose Vagrantfile uses the xapi
|
|
213
|
+
provider:
|
|
214
|
+
|
|
215
|
+
```sh
|
|
216
|
+
vagrant xapi marked # everything, of all users of the pool
|
|
217
|
+
vagrant xapi marked --mine # only your VMs, with their snapshots, disks, networks
|
|
218
|
+
vagrant xapi marked --project ~/src/shop # VMs, snapshots, networks of one project
|
|
219
|
+
vagrant xapi marked --vm <uuid> # one VM, its snapshots and its disks
|
|
220
|
+
vagrant xapi marked --box acme/debian-12 # the templates of one box
|
|
221
|
+
vagrant xapi marked --plain | grep '^vdi' # tab-separated, for scripts (or --json)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Filters can be repeated and combined; an object is listed when it matches
|
|
225
|
+
any of them. The project path may be given as you see it (symlinks are
|
|
226
|
+
resolved, e.g. `/var` → `/private/var` on macOS).
|
|
227
|
+
|
|
228
|
+
The same with `xe` on dom0:
|
|
229
|
+
|
|
230
|
+
```sh
|
|
231
|
+
# All VMs of one user
|
|
232
|
+
xe vm-list other-config:vagrant-xapi.user=alice params=uuid,name-label,power-state
|
|
233
|
+
|
|
234
|
+
# All VMs of one project directory
|
|
235
|
+
xe vm-list other-config:vagrant-xapi.project=/home/alice/src/shop
|
|
236
|
+
|
|
237
|
+
# Templates made by the plugin
|
|
238
|
+
xe template-list params=uuid,name-label | grep -B1 'vagrant-xapi:'
|
|
239
|
+
|
|
240
|
+
# Disks of one VM (including extra disks, ISOs and snapshot disks)
|
|
241
|
+
xe vdi-list other-config:vagrant-xapi.vm=<vm-uuid> params=uuid,name-label,virtual-size
|
|
242
|
+
|
|
243
|
+
# Snapshot copies a `vagrant xapi diff` is using, or left after it was killed
|
|
244
|
+
xe vdi-list name-label="vagrant-xapi diff of <vm-uuid>" params=uuid,other-config
|
|
245
|
+
|
|
246
|
+
# Internal networks created for private_network
|
|
247
|
+
xe network-list params=uuid,name-label,other-config | grep -B2 'vagrant-xapi.network'
|
|
248
|
+
|
|
249
|
+
# Locks currently held
|
|
250
|
+
xe pool-param-get uuid=$(xe pool-list --minimal) param-name=other-config | tr ';' '\n' | grep vagrant-xapi.lock
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Orphans
|
|
254
|
+
|
|
255
|
+
When a project directory is removed without `vagrant destroy`, its VMs keep
|
|
256
|
+
running. Find and remove them from any project with an xapi Vagrantfile:
|
|
257
|
+
|
|
258
|
+
```sh
|
|
259
|
+
vagrant xapi orphans # list VMs of this Vagrant installation whose machine is gone
|
|
260
|
+
vagrant xapi orphans --destroy # remove them, their disks, snapshots and unused internal networks
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Orphans are VMs of this Vagrant installation: VMs carry a random
|
|
264
|
+
`vagrant-xapi.client_id`, stored in
|
|
265
|
+
`~/.vagrant.d/data/vagrant-xapi/client-id`. (VMs from before that key match on
|
|
266
|
+
login name and local hostname.) A VM is not an orphan while any Vagrant
|
|
267
|
+
machine still points at it, also with a custom `VAGRANT_DOTFILE_PATH`. VMs of
|
|
268
|
+
colleagues are never listed. Removing the `client-id` file makes earlier VMs
|
|
269
|
+
look foreign; keep it with your Vagrant home. An administrator can find all
|
|
270
|
+
marked VMs with the `xe` commands above and remove them with `xe
|
|
271
|
+
vm-uninstall`.
|
|
272
|
+
|
|
273
|
+
### Taking over an existing VM
|
|
274
|
+
|
|
275
|
+
```sh
|
|
276
|
+
vagrant xapi adopt web 1c2d...-uuid # VM created by vagrant-xapi
|
|
277
|
+
vagrant xapi adopt web 1c2d...-uuid --force # any other VM
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
After `adopt`, `vagrant destroy` removes that VM and its disks.
|
|
281
|
+
|
|
282
|
+
Machines of a vagrant-xenserver Vagrantfile are taken over without `adopt`:
|
|
283
|
+
the first vagrant command finds the VM by the reference vagrant-xenserver
|
|
284
|
+
stored, marks it and its own disks, and stores its UUID. A reference that no
|
|
285
|
+
longer exists means the VM is gone (not created), as with vagrant-xenserver;
|
|
286
|
+
the plugin never takes a VM by its name. A VM that vagrant-xapi meanwhile
|
|
287
|
+
marked for another machine is left alone, with a warning.
|
|
288
|
+
|
|
289
|
+
## 6. Locks
|
|
290
|
+
|
|
291
|
+
Locks are keys `vagrant-xapi.lock.<name>` in the pool's `other_config`, with
|
|
292
|
+
the owner and an expiry time (pool master's clock) in the value. While a lock
|
|
293
|
+
is held, its owner refreshes `<name>.alive.0`/`.alive.1` every few minutes.
|
|
294
|
+
Locks are released when the operation ends, also on errors and Ctrl-C. The
|
|
295
|
+
lock of a crashed process stops being refreshed and is taken over once its
|
|
296
|
+
expiry and heartbeats have passed: template locks after 15 minutes, network
|
|
297
|
+
and placement locks after 10 minutes at most. Two takeovers never run at
|
|
298
|
+
once: a takeover first sets `vagrant-xapi.lock.<name>.takeover` (gone again
|
|
299
|
+
after a minute at most). To remove a stuck lock by hand (also its `.alive.*`
|
|
300
|
+
keys):
|
|
301
|
+
|
|
302
|
+
```sh
|
|
303
|
+
POOL=$(xe pool-list --minimal)
|
|
304
|
+
xe pool-param-get uuid=$POOL param-name=other-config param-key=vagrant-xapi.lock.<name>
|
|
305
|
+
xe pool-param-remove uuid=$POOL param-name=other-config param-key=vagrant-xapi.lock.<name>
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Only do that when the owner named in the value is really gone; otherwise two
|
|
309
|
+
imports of the same box can run at the same time.
|
|
310
|
+
|
|
311
|
+
## 7. Troubleshooting
|
|
312
|
+
|
|
313
|
+
Every error is a short message without a stack trace. A stack trace is a
|
|
314
|
+
bug: please report it with the output of `VAGRANT_LOG=debug`.
|
|
315
|
+
|
|
316
|
+
| Message (start) | Cause | What to do |
|
|
317
|
+
| --- | --- | --- |
|
|
318
|
+
| `XAPI refused the login` | Wrong username or password | Check `VAGRANT_XAPI_USERNAME`/`PASSWORD` |
|
|
319
|
+
| `Cannot connect to the XAPI host` | Host unreachable, wrong port, firewall | `curl -vk https://<host>/` from the local machine |
|
|
320
|
+
| `provider :xenserver runs in vagrant-xenserver compatibility mode` | A Vagrantfile written for vagrant-xenserver | Nothing; it keeps working. For the newer options, move to `:xapi` and run `vagrant xapi migrate` (README, "Migrating from vagrant-xenserver") |
|
|
321
|
+
| `a trigger uses XenApi::Client ... This stand-in is temporary` | A trigger calls XAPI through the `xenapi` gem of vagrant-xenserver | Replace the trigger with the provider's options (`cpus`, `config.vm.disk`) before the stand-in is removed |
|
|
322
|
+
| `vagrant-xenserver is installed too, so vagrant-xapi leaves the :xenserver provider to it` | Both plugins installed | `vagrant plugin uninstall vagrant-xenserver` |
|
|
323
|
+
| `Either a public network must be specified or the Host Internal Management Network parameter must be enabled` | A message of vagrant-xenserver itself: it is still installed and runs the `:xenserver` Vagrantfile | `vagrant plugin uninstall vagrant-xenserver` |
|
|
324
|
+
| `VM ..., which vagrant-xenserver created for this machine, now belongs to machine ...` | The VM vagrant-xenserver stored for this machine is marked for another machine (e.g. a copied project); this machine is now not created | Nothing, or `vagrant xapi adopt <uuid> --force` if it really is this machine's VM |
|
|
325
|
+
| `Machine '...' is in use by another Vagrant process` (`vagrant xapi migrate`) | Another vagrant command holds the machine | Run `vagrant xapi migrate` again when it has finished |
|
|
326
|
+
| `Stale VM reference, looking the VM up by name instead` (from a trigger) | Trigger code of a vagrant-xenserver Vagrantfile uses `machine.id` as VM reference; vagrant-xapi stores the UUID | Nothing: the trigger finds the VM by name. Gone once the trigger is replaced by plugin options |
|
|
327
|
+
| `The TLS certificate of ... could not be verified` | Self-signed certificate, wrong pin, renewed certificate; or `host` is a pool member and the master's certificate is not among the pins (the message names both) | The message shows the SHA-256 fingerprint of the certificate it got; check it on the host and set `tls_fingerprint` or `VAGRANT_XAPI_TLS_FINGERPRINT` (section 2). Once the master is pinned, `vagrant xapi hosts` shows every host's fingerprint |
|
|
328
|
+
| `The XAPI connection is not configured` | Host, username or password missing | Set the environment variables or the provider options |
|
|
329
|
+
| `The XAPI user lacks the permission` / `may not write the pool's other_config` | RBAC role too small | Use a role with more rights (section 2) |
|
|
330
|
+
| `Warning: The guest closed the SSH connection right away ... Retrying...` | sshd refuses new connections for a while after failed logins (OpenSSH 9.8+ `PerSourcePenalties`), e.g. while cloud-init on the first boot is still creating the `vagrant` user | Nothing; the plugin keeps trying until `boot_timeout` and repeats the warning every minute. If it never ends: check that no other machine uses the IP (another VM with the same static IP answers, refuses the key and is then penalized), and look at the VM with `vagrant xapi console` |
|
|
331
|
+
| A VNC viewer asks for a password (`vagrant xapi console`) | The console proxy asks for a one-time password | Use the password `vagrant xapi console` printed; it is valid while the command runs |
|
|
332
|
+
| `console runs without a password` | Vagrant's Ruby has no 3DES (e.g. a FIPS-only OpenSSL) | Nothing needed; the console works without password, but other local users could connect while it is open |
|
|
333
|
+
| The console (`vagrant xapi console`) shows GRUB's `error: out of memory` after `Loading initial ramdisk` | UEFI with too little memory: the firmware takes its share. Templates of disk-image boxes have 1 GiB; older ones, imported before that, still have the 256 MiB of XAPI's "Other install media" | Set `xapi.memory` (e.g. 2048), or remove the old template (`vagrant xapi templates remove`) so it is imported again |
|
|
334
|
+
| `The guest did not report an IP within ... seconds` | No guest agent in the box, VM not booting (e.g. a BIOS box with `firmware = :uefi`, or no signed boot loader with `secure_boot`), or no IP on the first network | `vagrant xapi console` to look at the VM; install a guest agent, or set a static `ip:` on the first network and `ip_detection = [:static]` |
|
|
335
|
+
| `The VM stopped ... while waiting for its IP` | The guest crashed or powered off during boot | `vagrant xapi console`, check firmware (`:bios`/`:uefi`) matches the image |
|
|
336
|
+
| `Network '...' was not found in the pool` | Typo, or the network has another name on this pool | `xe network-list params=name-label,bridge` |
|
|
337
|
+
| `There are N network objects named ...` | Duplicate names | Use the UUID |
|
|
338
|
+
| `Storage repository '...' was not found` / `The pool has no default SR` | Wrong `sr`, or no default SR | `xe sr-list`; set `sr` |
|
|
339
|
+
| `The storage repository is full` | Not enough space for the import or the clone | Free space, prune templates, or use another `sr` |
|
|
340
|
+
| `The host does not have enough free memory` | Not enough RAM on the host | Lower `memory`, or set `affinity_host` to another host |
|
|
341
|
+
| `This host cannot import qcow2 directly and qemu-img is not installed` | qcow2 box on a host whose XAPI cannot import qcow2 | Install `qemu-img` on the local machine |
|
|
342
|
+
| `... is a qcow2 image with compressed clusters` / `uses qcow2 features that XAPI cannot import` / `XAPI could not import ... as qcow2` | XAPI's qcow2 import cannot read this image (compressed clusters, zstd, extended L2 entries) | Install `qemu-img` on the local machine; the plugin converts the image to VHD |
|
|
343
|
+
| `Waiting for lock ... held by ...` (keeps waiting) | Another import of the same box runs, or a stale lock | Wait; or check the owner and remove the lock (section 6) |
|
|
344
|
+
| `The VM cannot be suspended: ... no working PV drivers` | No guest agent or PV drivers | Install them in the box, or use `halt` |
|
|
345
|
+
| `The VM cannot be suspended: the pool has no suspend SR` | No suspend SR | Set a suspend image SR on the pool |
|
|
346
|
+
| `Disk '...' cannot shrink` | `size` smaller than the existing disk | Disks only grow; recreate the machine to shrink |
|
|
347
|
+
| `Disk '...' can only grow while the VM is halted` | Resize on a running VM | Use `vagrant reload` |
|
|
348
|
+
| `The SSH tunnel for port(s) ... did not start` | Host port in use, or SSH to the guest fails | See `.vagrant/machines/<name>/xapi/tunnels.log`; pick another host port or set `auto_correct: true` |
|
|
349
|
+
| `This pool does not support vTPM` | XAPI without `VTPM` class | Remove `vtpm = true` |
|
|
350
|
+
| `Box format ... is not supported` / `Boxes for provider ... cannot be used` | Wrong box | Use an xapi, xenserver or libvirt box |
|
|
351
|
+
| `The box names ..., which is not a file inside the box directory` | The box's `metadata.json` or a symlink points outside the box | Do not use the box; ask its maker to fix it |
|
|
352
|
+
| `The qcow2 image ... refers to a backing file` / `uses an external data file` | A qcow2 overlay, not a self-contained image | Flatten it: `qemu-img convert -O qcow2 in.qcow2 out.qcow2` |
|
|
353
|
+
| `VM ... has no vagrant-xapi marking` | `destroy` of a VM the plugin did not create | Leave it, or `vagrant xapi adopt --force` it first |
|
|
354
|
+
| `VM ... belongs to machine '...' of <dir>, not to this machine and project` | The project directory was copied or moved; the VM is marked for the other one | After a move: `vagrant xapi adopt [vm] <uuid>`. After a copy: leave it; the original project owns the VM |
|
|
355
|
+
| `A network named '...' already exists and does not belong to this project` | A `private_network` name is used by another project | Choose another `name:`, or use `network: "<name>"` to attach to it on purpose |
|
|
356
|
+
| `VM ... belongs to machine '...' of ... (user ...)` on `adopt` | Adopting someone else's VM | Check the UUID; add `--force` only if you really take it over |
|
|
357
|
+
| `... is a member of a pool; its master is ...` | `host` is a pool member and `tls_fingerprint` is set | Use the master as `host` and pin its certificate |
|
|
358
|
+
| `vagrant xapi diff reads the files through the guest` | `diff` of a halted or suspended machine | `vagrant up` first |
|
|
359
|
+
| `Machine '...' uses the provider ...` on `diff --with` | The other machine is not a machine of vagrant-xapi | Compare with a machine of the `:xapi` (or `:xenserver`) provider |
|
|
360
|
+
| `The guest uses crypto_LUKS` (or btrfs, ZFS, RAID) on `diff` | A copy of such disks cannot be attached next to the running system | Compare two running machines with `--with` |
|
|
361
|
+
| `The guest lacks ...` on `diff` | Not a Linux guest with GNU findutils, coreutils and util-linux | Install them in the box |
|
|
362
|
+
| `The file listing from the guest is incomplete or malformed` on `diff` | find in the guest could not write its whole listing, usually because the guest's `/tmp` is full | Free space in the guest's `/tmp` (often RAM) and run `diff` again |
|
|
363
|
+
| `The snapshot disk contains crypto_LUKS` (or btrfs, ZFS, RAID) | The disk layout changed since the snapshot was taken | Compare with `--with`; if `lsblk` in the guest still shows volumes of the copy, reboot the guest |
|
|
364
|
+
| `The guest lacks vgimportclone (lvm2)` | The guest (or the snapshot) uses LVM, but lvm2 is not complete | Install lvm2 in the box |
|
|
365
|
+
| `A command in the guest failed (vgimportclone)` or `(vgchange)` | LVM could not import or activate the copy (e.g. a shared VG, or thin LVs without thin-provisioning-tools) | The message has LVM's text; `vagrant xapi diff` cleaned up |
|
|
366
|
+
| `Could not deactivate the volume group vagrant_xapi_diff_...` | A logical volume of the copy was still open | Nothing; its devices go once they are closed. `sudo dmsetup ls` in the guest shows them |
|
|
367
|
+
| `XAPI could not attach the snapshot disk to the running VM` | No PV drivers or guest agent, so XAPI refuses to hotplug a disk | Install xe-guest-utilities or xen-guest-agent in the box |
|
|
368
|
+
| `Could not remove the snapshot copy <uuid> of the destroyed VM ...` | `vagrant destroy` could not remove a copy of an interrupted `diff`, also not after the VM was gone | Nothing removes it later: `vagrant xapi marked --vm <vm-uuid>` lists it, `xe vdi-destroy uuid=<uuid>` removes it |
|
|
369
|
+
| `Could not remove the snapshot disk ...` | A `diff` could not unplug or destroy its copy (e.g. the guest kept it busy) | Run `vagrant xapi diff` again or `vagrant destroy`; both remove it. `vagrant reload` removes it too while it is still attached to the VM, not a copy whose VBD is already gone. Until then do not reboot from inside the guest: an attached copy has the same file system UUIDs |
|
|
370
|
+
| `... snapshot copy (copies) of an interrupted vagrant xapi diff could not be removed from VM ...` on `up`, `reload` or `package` | A copy of an interrupted `diff` is still attached and XAPI refused to remove it (the warning before it says why) | Fix the cause and run the command again, or remove the copy by hand as the message says; until then the VM does not start, because the copy has the same file system UUIDs |
|
|
371
|
+
| `Could not install the udev rule that keeps udev and systemd in the guest on its own disks ...` | `diff` could not write `/run/udev/rules.d/99-vagrant-xapi-diff.rules` or reload udev in the guest | The diff ran; check with `findmnt` that `/boot` and other fstab mounts by UUID are still mounted, and `sudo mount -a` if not |
|
|
372
|
+
| `XAPI did not finish cloning the snapshot disk ...` | `VDI.clone` took longer than `task_timeout`, or the connection was lost | A clone that appears later has no marking, so no cleanup removes it: find it with the `xe vdi-list` command in the message and remove it with `xe vdi-destroy` |
|
|
373
|
+
| `XAPI returned an error: <CODE>` | An XAPI error without its own text | Look the code up in the XAPI docs; the message names the call |
|
|
374
|
+
|
|
375
|
+
SSH problems:
|
|
376
|
+
|
|
377
|
+
- With `ssh_via_host`, the host key of dom0 must be in your `known_hosts`
|
|
378
|
+
(the ProxyCommand runs with `BatchMode=yes` and normal host key checking):
|
|
379
|
+
`ssh root@<host-address> true` once.
|
|
380
|
+
- `vagrant ssh-config` shows exactly what Vagrant uses.
|
|
381
|
+
|
|
382
|
+
### Debug logging
|
|
383
|
+
|
|
384
|
+
```sh
|
|
385
|
+
VAGRANT_LOG=debug vagrant up 2>debug.log
|
|
386
|
+
grep -E '^ *[A-Z]+ xapi' debug.log
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
The plugin's lines start with `xapi:` (the client and services) or
|
|
390
|
+
`xapi_<step>:` (the provider and each action step, e.g. `xapi_createvm:`).
|
|
391
|
+
|
|
392
|
+
Every XAPI call is logged as `xapi -> <method> <params>` and
|
|
393
|
+
`xapi <- <method> ok|error`. The password and the session id are replaced by
|
|
394
|
+
`[REDACTED]`/`<session>`; check before sharing a log anyway (VM names and
|
|
395
|
+
paths are in it).
|
|
396
|
+
|
|
397
|
+
### Files in the machine directory
|
|
398
|
+
|
|
399
|
+
`.vagrant/machines/<name>/xapi/`:
|
|
400
|
+
|
|
401
|
+
| File | Contents |
|
|
402
|
+
| --- | --- |
|
|
403
|
+
| `id` | VM UUID (Vagrant) |
|
|
404
|
+
| `forwarded_ports.json` | Running SSH tunnels: PID, addresses, the host port in use and the one in the Vagrantfile |
|
|
405
|
+
| `tunnels.log` | stderr of the SSH tunnels |
|
|
406
|
+
| `disk_meta` | Disks configured by `config.vm.disk` (Vagrant) |
|
|
407
|
+
| `action_cloud_init` | Sentinel: cloud-init ran for this VM (Vagrant) |
|
|
408
|
+
| `xapi_cloud_init_iso`, `vagrant-xapi-cidata-<sha>.iso` | Checksum and path of the cloud-init ISO |
|
|
409
|
+
|
|
410
|
+
In the Vagrant home, `~/.vagrant.d/data/vagrant-xapi/`:
|
|
411
|
+
|
|
412
|
+
| File | Contents |
|
|
413
|
+
| --- | --- |
|
|
414
|
+
| `digests.json` | Box digests, keyed on path, size and mtime; deleting it only costs one recomputation |
|
|
415
|
+
| `client-id` | Random id of this installation, used to recognise its own VMs (orphans) |
|
|
416
|
+
|
|
417
|
+
## 8. Development
|
|
418
|
+
|
|
419
|
+
### Environment
|
|
420
|
+
|
|
421
|
+
Ruby 3.0–3.4 (Vagrant does not support 3.5 or 4.x yet) with bundler.
|
|
422
|
+
|
|
423
|
+
```sh
|
|
424
|
+
bundle install
|
|
425
|
+
bundle exec rake # unit tests
|
|
426
|
+
bundle exec rspec spec/unit/api # one directory
|
|
427
|
+
bundle exec vagrant <cmd> # Vagrant (pinned in the Gemfile) with this plugin loaded
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
The Gemfile has Vagrant (pinned to a release tag, currently v2.4.9) from
|
|
431
|
+
git in group `:development` and the plugin itself in group `:plugins` (as `gem "vagrant-xapi", path:
|
|
432
|
+
"."`), which `bundle exec vagrant` loads. Set `VAGRANT_CHECKPOINT_DISABLE=1`
|
|
433
|
+
to stop Vagrant's version check. Running Vagrant outside its installer
|
|
434
|
+
complains about a missing `bsdtar`; that only matters for `vagrant box add`
|
|
435
|
+
of packed boxes and for `vagrant package` compression.
|
|
436
|
+
|
|
437
|
+
If native gems fail to link (for example with a Homebrew Ruby whose
|
|
438
|
+
`libruby` is built against Homebrew's glibc), build them with Homebrew's
|
|
439
|
+
compiler by putting `gcc`/`cc`/`g++` shims that point to `gcc-NN`/`g++-NN`
|
|
440
|
+
first in `PATH`.
|
|
441
|
+
|
|
442
|
+
### Where things go
|
|
443
|
+
|
|
444
|
+
- XAPI calls only in `lib/vagrant-xapi/api` and `services`; services never
|
|
445
|
+
require Vagrant.
|
|
446
|
+
- Every user-facing text in `locales/en.yml` (`messages`, `errors`,
|
|
447
|
+
`config`, `commands`, `states`). Do not use `%{format}`, `%{scope}` or other
|
|
448
|
+
I18n reserved names as parameters.
|
|
449
|
+
- New errors: raise `Services::Error.new(:key, **params)` in a service and add
|
|
450
|
+
`vagrant_xapi.errors.key`; `spec/unit/vagrant/errors_spec.rb` checks every
|
|
451
|
+
key renders.
|
|
452
|
+
- New XAPI calls the fake does not know: add a `x_<Class>_<method>` method to
|
|
453
|
+
`spec/support/fake_xapi.rb` (generic getters, setters, `add_to_*`,
|
|
454
|
+
`remove_from_*`, `create`, `destroy`, `get_by_*` already work), and
|
|
455
|
+
remember that the fake only proves what we think XAPI does.
|
|
456
|
+
- Anything the plugin creates in XAPI must carry a marking, and cleanup must
|
|
457
|
+
check it.
|
|
458
|
+
|
|
459
|
+
### Tests
|
|
460
|
+
|
|
461
|
+
- `spec/unit/api`: client and TLS (the TLS tests use a real local TLS
|
|
462
|
+
server, with WebMock disabled).
|
|
463
|
+
- `spec/unit/services`: one spec per service, against the fake XAPI.
|
|
464
|
+
- `spec/unit/vagrant`: config, errors, the real action stacks in a temporary
|
|
465
|
+
`Vagrant::Environment` (box placed straight in `VAGRANT_HOME`; SSH
|
|
466
|
+
communicator and guest stubbed), and the subcommands.
|
|
467
|
+
|
|
468
|
+
### CI
|
|
469
|
+
|
|
470
|
+
`.github/workflows/ci.yml` runs on every pull request and every push to
|
|
471
|
+
`master`:
|
|
472
|
+
|
|
473
|
+
- the unit tests on Ruby 3.1 to 3.4, the versions Vagrant's own CI tests
|
|
474
|
+
(Gemfile.lock is not checked in, so each run resolves the gems anew);
|
|
475
|
+
- `shellcheck` on the acceptance script;
|
|
476
|
+
- `gem build`, failing when the gem has a runtime dependency or lacks one of
|
|
477
|
+
the files listed under Releasing.
|
|
478
|
+
|
|
479
|
+
The actions are pinned to a commit; bump them deliberately. The acceptance
|
|
480
|
+
scenarios need a real pool and do not run in CI.
|
|
481
|
+
|
|
482
|
+
### Acceptance tests
|
|
483
|
+
|
|
484
|
+
Against a real pool; see [test/acceptance/README.md](../test/acceptance/README.md)
|
|
485
|
+
for the environment variables.
|
|
486
|
+
|
|
487
|
+
```sh
|
|
488
|
+
test/acceptance/scenarios.sh # A1-A19
|
|
489
|
+
test/acceptance/scenarios.sh A3 A13 # some
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
Run them before a release. The scenarios check the pool with
|
|
493
|
+
`vagrant xapi marked`, so they only need the normal connection settings, no
|
|
494
|
+
access to dom0.
|
|
495
|
+
|
|
496
|
+
## 9. Releasing
|
|
497
|
+
|
|
498
|
+
1. Run the unit tests and the acceptance scenarios.
|
|
499
|
+
2. Bump `VagrantPlugins::Xapi::VERSION` in `lib/vagrant-xapi/version.rb` and
|
|
500
|
+
add the changes to `CHANGELOG.md`, with the release date instead of
|
|
501
|
+
"unreleased".
|
|
502
|
+
3. `gem build vagrant-xapi.gemspec` and check the contents:
|
|
503
|
+
`tar -xOf vagrant-xapi-*.gem data.tar.gz | tar -tz` must list `lib/`,
|
|
504
|
+
`locales/en.yml`, `docs/architecture.md`, `docs/operations.md`,
|
|
505
|
+
`README.md`, `LICENSE`, `CHANGELOG.md`, and the gem must have no runtime
|
|
506
|
+
dependencies.
|
|
507
|
+
4. Try it in a clean Vagrant: `vagrant plugin install ./vagrant-xapi-X.Y.Z.gem`.
|
|
508
|
+
5. Once that is merged into `master`, build the gem again from a clean
|
|
509
|
+
checkout of `master` and push it to rubygems.org, with an account that
|
|
510
|
+
owns `vagrant-xapi` there (MFA is required, so `gem push` asks for a
|
|
511
|
+
one-time code). The gem is public: `spec.files` takes every matching file
|
|
512
|
+
in the working tree, tracked or not, so `git status` must be clean.
|
|
513
|
+
|
|
514
|
+
```sh
|
|
515
|
+
git status --short --ignored lib locales docs README.md LICENSE CHANGELOG.md # must print nothing
|
|
516
|
+
gem build vagrant-xapi.gemspec
|
|
517
|
+
gem push vagrant-xapi-X.Y.Z.gem
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
A pushed version cannot be replaced; a mistake needs a new version
|
|
521
|
+
(`gem yank` only hides it from new installs).
|
|
522
|
+
6. Tag the release on GitHub, with the release's section of `CHANGELOG.md`
|
|
523
|
+
as its notes:
|
|
524
|
+
|
|
525
|
+
```sh
|
|
526
|
+
gh release create vX.Y.Z -R exonet/vagrant-xapi \
|
|
527
|
+
--target master --title vX.Y.Z --notes-file notes.md
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
The gem is not attached: rubygems.org is the only place it comes from
|
|
531
|
+
(`docs/architecture.md`, section 15).
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "log4r"
|
|
4
|
+
|
|
5
|
+
require_relative "../errors"
|
|
6
|
+
require_relative "../glue"
|
|
7
|
+
|
|
8
|
+
module VagrantPlugins
|
|
9
|
+
module Xapi
|
|
10
|
+
module Action
|
|
11
|
+
# Shared helpers for our middleware.
|
|
12
|
+
class Base
|
|
13
|
+
def initialize(app, env)
|
|
14
|
+
@app = app
|
|
15
|
+
@logger = Log4r::Logger.new("vagrantplugins::xapi_#{self.class.name.split("::").last.downcase}")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
protected
|
|
19
|
+
|
|
20
|
+
def ctx(env)
|
|
21
|
+
env[:xapi_ctx] ||= Glue.context(env[:machine], env, client: env[:xapi])
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def vm(env)
|
|
25
|
+
ref = Glue.vm_ref(env[:machine], ctx(env))
|
|
26
|
+
raise Vagrant::Errors::VMNotCreatedError unless ref
|
|
27
|
+
|
|
28
|
+
ref
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def wrap(&block)
|
|
32
|
+
Errors.wrap(&block)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def config(env)
|
|
36
|
+
env[:machine].provider_config
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# First middleware of every stack: client and service errors become
|
|
41
|
+
# readable VagrantErrors, never stack traces.
|
|
42
|
+
class TranslateErrors
|
|
43
|
+
def initialize(app, _env)
|
|
44
|
+
@app = app
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def call(env)
|
|
48
|
+
@app.call(env)
|
|
49
|
+
rescue Api::Error, Services::Error => e
|
|
50
|
+
raise Errors.translate(e)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Puts the shared XAPI session in env[:xapi].
|
|
55
|
+
class ConnectXapi < Base
|
|
56
|
+
def call(env)
|
|
57
|
+
env[:xapi] = Glue.client(env[:machine])
|
|
58
|
+
env[:xapi_ctx] = Glue.context(env[:machine], env, client: env[:xapi])
|
|
59
|
+
previous = Thread.current[:vagrant_xapi_cancel]
|
|
60
|
+
Thread.current[:vagrant_xapi_cancel] = -> { env[:interrupted] ? true : false }
|
|
61
|
+
begin
|
|
62
|
+
@app.call(env)
|
|
63
|
+
ensure
|
|
64
|
+
Thread.current[:vagrant_xapi_cancel] = previous
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# env[:result] = whether the VM exists.
|
|
70
|
+
class IsCreated < Base
|
|
71
|
+
def call(env)
|
|
72
|
+
env[:result] = env[:machine].state.id != :not_created
|
|
73
|
+
@app.call(env)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Raises when the machine is not running (for ssh, ssh_run).
|
|
78
|
+
class CheckRunning < Base
|
|
79
|
+
def call(env)
|
|
80
|
+
state = env[:machine].state.id
|
|
81
|
+
raise Vagrant::Errors::VMNotCreatedError if state == :not_created
|
|
82
|
+
raise Vagrant::Errors::VMNotRunningError if state != :running
|
|
83
|
+
|
|
84
|
+
@app.call(env)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Prints a message from our locale file.
|
|
89
|
+
class Message < Base
|
|
90
|
+
def initialize(app, env, key, level = :info)
|
|
91
|
+
super(app, env)
|
|
92
|
+
@key = key
|
|
93
|
+
@level = level
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def call(env)
|
|
97
|
+
env[:ui].public_send(@level, I18n.t("vagrant_xapi.messages.#{@key}"))
|
|
98
|
+
@app.call(env)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|