docs(xo): import devops tools documentation from vates vms (#10062)

This commit is contained in:
Thomas Moraine
2026-07-03 09:24:44 +02:00
committed by GitHub
parent 1b0dbc7d3b
commit d53dd3e990
28 changed files with 1973 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

520
docs/docs/xo6/ansible.md Normal file
View File

@@ -0,0 +1,520 @@
# Ansible dynamic inventory
## Introduction
Dynamic inventory is a powerful Ansible feature that enables you to automatically discover hosts to manage from an external source. With **Xen Orchestra**, you can now use dynamic inventory to automatically discover and manage your virtual machines (VMs) directly from your virtualized infrastructure.
This guide will show you how to configure Xen Orchestra's dynamic inventory and automate the management of your VM fleet.
:::note
This guide is designed for [Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) version 2.19 or higher and requires the `community.general` collection.
:::
:::tip
With dynamic inventory, there is no need to manually maintain static inventory files. Your VMs are automatically discovered and classified into groups based on their properties.
:::
## Configuring Xen Orchestra Dynamic Inventory
### Installing prerequisites
Ensure that you have the `community.general` collection installed.
```bash
# Install the community.general collection
ansible-galaxy collection install community.general
# Verify the installation
ansible-doc -t inventory community.general.xen_orchestra
```
### Basic configuration
1. **Create a configuration file for the dynamic inventory: `test.xen_orchestra.yaml`**
:::tip
Please note that the plugin configuration file must end with one of the following extensions: `xen_orchestra.yml` or `xen_orchestra.yaml` (e.g. `test.xen_orchestra.yml`)
:::
```yaml
# xen orchestra connection
plugin: community.general.xen_orchestra
api_host: ws://your-xo-hostname
user: your_username
password: your_password
validate_certs: false
use_ssl: false
# Automatic groups
groups:
running: power_state == “Running”
halted: power_state == “Halted”
windows: Windows in name_label”
linux: Linux in name_label” or “Ubuntu in name_label” or “CentOS in name_label” or “Debian in name_label”
# Compound variables
compose:
ansible_host: ipv4_addresses[0] if ipv4_addresses else None
ansible_user: “root”
xo_vm_name: name_label
xo_pool: pool_name
```
:::warning
For security reasons, we recommend using environment variables or Ansible Vault to store credentials.
:::
2. **Configuration with environment variables**
```yaml
plugin: community.general.xen_orchestra
api_host: “{{xen_api_host}}”
user: “{{ xen_api_user }}”
password: “{{ xen_api_password }}”
validate_certs: true
use_ssl: false
```
Use Ansible Vault to create an encrypted file for your secrets:
```bash
ansible-vault create vault.yml
```
and place the contents:
```yaml
xen_api_user: your_user
xen_api_password: your_password
xen_api_host: your-xo-hostname
```
## Using dynamic inventory
1. **Test dynamic inventory**
```yaml
# List all hosts
ansible-inventory -i xo_inventory.yaml --list
# Display groups in tree form
ansible-inventory -i xo_inventory.yaml --graph
# Provides information about a specific host (VM UUID in XO)
ansible-inventory -i xo_inventory.yaml --host=uuid-of-your-vm
```
:::tip
If you are using Ansible Vault, don't forget to add `--ask-vault-pass` to the end of your commands.
If you are using a vault password file, you can avoid typing the password each time by adding `--vault-password-file ~/.vault_pass.txt` to the end of your commands.
:::
2. **Example output**
```json
{
"ansible_host": null,
"cpus": 1,
"has_ip": false,
"ip": null,
"is_managed": true,
"memory": 21474xxx,
"name_label": "XO Tutorial",
"os_version": {
"distro": "Ubuntu",
"name": "Ubuntu 24.04",
"uname": "6.8.0-57-generic"
},
"power_state": "running",
"tags": [],
"type": "VM",
"uuid": "0ae54d06-xxx-100c-00e8-xxxxxxx",
"xo_power_state": "running",
"xo_vm_name": "XO Tutorial"
}
```
## Advanced Use of Dynamic Inventory
### Filtering VMs
You can filter the VMs included in the inventory:
```yaml
plugin: community.general.xen_orchestra
api_host: ws://your-xo-hostname
user: your_user
password: your_password
validate_certs: true
use_ssl: false
# Filters
filters:
- pool_name == “Production”
- power_state == “Running”
- name_label != “template-*”
# Exclusive filter
strict: false
```
### Complex custom groups
Create groups based on complex conditions:
```yaml
plugin: community.general.xen_orchestra
api_host: ws://your-xo-hostname
username: your_username
password: your_password
validate_certs: true
use_ssl: false
groups:
# By state
powered_on: power_state == “Running”
powered_off: power_state == “Halted”
# By operating system
ubuntu_servers: Ubuntu in name_label and server in name_label.lower()”
web_servers: web in name_label.lower() or apache in name_label.lower() or nginx in name_label.lower()”
db_servers: db in name_label.lower() or database in name_label.lower() or mysql in name_label.lower() or postgres in name_label.lower()”
# By pool
production_vms: pool_name == “your_production_name”
development_vms: pool_name == “your_development_name”
lab_vms: “pool_name == Main Lab
# By tags (if your XO uses tags)
critical_vms: "' critical' in tags" if tags is defined else false
backup_excluded: no-backup in tags” if tags is defined else false
keyed_groups:
# Creates groups by pool
- prefix: pool
key: pool_name
# Creates groups by VM template
- prefix: template
key: template_name
```
### Configuring host variables
Customize Ansible variables for each host:
```yaml
plugin: community.general.xen_orchestra
api_host: ws://your-xo-hostname
user: your_user
password: your_password
validate_certs: true
use_ssl: false
compose:
# Sets ansible_host as the first IPv4 address
ansible_host: |
{% if ipv4_addresses and ipv4_addresses[0] %}
{{ ipv4_addresses[0] }}
{% else %}
{{ name_label | lower | replace(' ', '-') }}.local
{% endif %}
# Sets the user based on the operating system
ansible_user: |
{% if Windows in name_label %}
administrator
{% elif Ubuntu in name_label %}
ubuntu
{% elif CentOS in name_label %}
centos
{% else %}
root
{% endif %}
# Xen Orchestra custom variables
xo_vm_id: id
xo_vm_name: name_label
xo_pool: pool_name
xo_template: template_name
xo_power_state: power_state
xo_memory: memory_max
xo_cpus: cpus
# Default variables
vars:
ansible_connection: ssh
ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
xo_inventory_source: “xen_orchestra”
```
## Use in Ansible Playbooks
### Playbook with dynamic inventory
```yaml
# playbook-xo-maintenance.yaml
---
- name: VM maintenance via XO inventory
hosts: uuid_of_your_vm # you can use (all/group_label/statut_vm/...)
gather_facts: true
become: yes
tasks:
- name: Update package index
apt:
update_cache: yes
cache_valid_time: 3600
when: ansible_distribution in [“Ubuntu”, “Debian”]
- name: Update system packages
apt:
name: “*”
state: latest
when: ansible_distribution in [“Ubuntu”, “Debian”]
register: apt_upgrade
- name: Check if a reboot is required
stat:
path: /var/run/reboot-required
register: reboot_required_file
when: ansible_distribution in [“Ubuntu”, “Debian”]
- name: Reboot if necessary
reboot:
msg: “Reboot after update”
connect_timeout: 5
reboot_timeout: 300
pre_reboot_delay: 0
post_reboot_delay: 30
test_command: uptime
when: reboot_required_file.stat.exists
- name: Clean up package cache
apt:
autoclean: yes
autoremove: yes
when: ansible_distribution in [“Ubuntu”, “Debian”]
```
### Managing VMs by group
```yaml
# manage-vm-groups.yaml
---
- name: Configuring application servers
hosts: group_label
gather_facts: true
become: yes
tasks:
- name: Installing basic packages
apt:
name:
- curl
- wget
- htop
- net-tools
state: present
update_cache: yes
- name: Timezone configuration
timezone:
name: Europe/Paris
- name: Creation of custom motd file
copy:
content: |
VM managed by Ansible via Xen Orchestra
Template: {{ xo_template }}
Pool: {{ xo_pool }}
dest: /etc/motd
owner: root
group: root
mode: 0644
- name: Maintain specific VMs
hosts: lab_vms
gather_facts: true
become: yes
tasks:
- name: Check disk space
shell: df -h /
register: disk_usage
- name: Check memory usage
shell: free -h
register: memory_usage
- name: Display system information
debug:
msg: |
VM: {{ xo_vm_name }}
Disk: {{ disk_usage.stdout_lines[1] if disk_usage.stdout_lines|length > 1 else N/A }}
Memory: {{ memory_usage.stdout_lines[1] if memory_usage.stdout_lines|length > 1 else N/A }}
```
### Monitoring and Reporting Playbook
```yaml
# monitoring-playbook.yaml
---
- name: Collect information from XO VMs
hosts: uuid_of_your_vm # use 'all' if you want to target all VMs
gather_facts: true
become: yes
tasks:
- name: Collect detailed information
setup:
gather_subset:
- hardware
- network
- virtual
- name: Check memory usage
shell: free -m | awk 'NR==2{printf "%.2f%%", $3*100/$2 }'
register: memory_usage
- name: Check CPU usage
shell: top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1
register: cpu_usage
- name: Check uptime
shell: uptime -p
register: uptime
- name: Create XO report
local_action:
module: copy
content: |
XEN ORCHESTRA REPORT - {{ ansible_date_time.iso8601 }}
===================================================
{% for host in groups['all'] %}
VM: {{ hostvars[host].xo_vm_name }}
UUID: {{ hostvars[host].xo_vm_id }}
IP: {{ hostvars[host].ansible_host }}
Hostname: {{ hostvars[host].ansible_hostname }}
Memory: {{ hostvars[host].memory_usage.stdout }}
CPU: {{ hostvars[host].cpu_usage.stdout }}%
Uptime: {{ hostvars[host].uptime.stdout }}
Pool: {{ hostvars[host].xo_pool }}
Template: {{ hostvars[host].xo_template }}
Status: {{ hostvars[host].xo_power_state }}
------------------------------------------
{% endfor %}
dest: "./xo-report-{{ ansible_date_time.epoch }}.txt"
run_once: true
- name: Monitoring summary
debug:
msg: |
XO monitoring completed
Report generated: xo-report-{{ ansible_date_time.epoch }}.txt
{{ groups['all'] | length }} VMs inventoried
```
## Best Practices and Security
### Using Ansible Vault
:::warning
Always secure your credentials with Ansible Vault in production environments to prevent unauthorized access and sensitive data leaks. Failing to protect secrets can expose passwords, API keys, and other confidential information, putting your infrastructure and data at risk.
:::
1. **Create a secure vault file**
```bash
ansible-vault create vault.yaml
```
```yaml
xen_api_user: your_username
xen_api_password: your_password
xen_api_host: your-xo-hostname
```
2. **Inventory configuration with vault**
```yaml
plugin: community.general.xen_orchestra
api_host: "{{xen_api_host}}"
user: "{{ xen_api_user }}"
password: "{{ xen_api_password }}"
validate_certs: true
use_ssl: false
```
3. **Execution with vault**
```bash
ansible-inventory -i test.xen_orchestra.yaml --list --ask-vault-pass
```
### Managing Multiple Environments
Create inventory configurations per environment:
```yaml
plugin: community.general.xen_orchestra
api_host: ws://xo-production.company.com
user: "{{ vault_xo_user }}"
password: "{{ vault_xo_password }}"
filters:
- pool_name == "your_pool_name"
```
## Troubleshooting and Debugging
### Testing and Validation
```bash
ansible-inventory -i your_file.xen_orchestra.yml --list
ANSIBLE_DEBUG=1 ansible-inventory -i your_file.xen_orchestra.yml --list
ansible-inventory -i your_file.xen_orchestra.yml --host=uuid-vm-specific
ansible -i your_file.xen_orchestra.yml all -m ping
```
### Common Issue Resolution
1. **Connection Problems**
- **Error**: Unable to connect to the Xen Orchestra API.
- **Reason**: Incorrect URL or credentials.
- **Solution**: Check the URL and credentials.
```bash
# Verify URL and credentials
ANSIBLE_DEBUG=1 ansible-inventory -i your_file.xen_orchestra.yml --list
```
2. **VMs Not Found**
- **Error**: No VMs found in inventory.
- **Reason**: Applied filters may be excluding all VMs.
- **Solution**: Check the applied filters.
```yaml
filters:
- power_state == "Running"
strict: false
```
3. **Variable Issues**
- **Error**: Undefined or incorrect variables.
- **Reason**: Issues with variable definitions in the configuration file.
- **Solution**: Ensure all variables are properly defined.
```yaml
compose:
ansible_host: ipv4_addresses[0] if ipv4_addresses else "unknown"
ansible_user: "{{ 'ubuntu' if 'Ubuntu' in name_label else 'root' }}"
```
## Conclusion
The Xen Orchestra dynamic inventory for Ansible provides a powerful and automated method to manage your virtualized infrastructure. By eliminating manual inventory maintenance, you gain agility, reliability, and efficiency.
## Related links
- [Dynamic inventory source code](https://github.com/ansible-collections/community.general/blob/main/plugins/inventory/xen_orchestra.py)
- [Ansible documentation on dynamic inventories](https://xen-orchestra.com/blog/virtops3-ansible-with-xen-orchestra/)
- [community.general collection](https://docs.ansible.com/ansible/latest/collections/community/general/xen_orchestra_inventory.html)
- [XCP-ng Forum](https://xcp-ng.org/forum/)

233
docs/docs/xo6/kubernetes.md Normal file
View File

@@ -0,0 +1,233 @@
# Deploy Kubernetes with recipes
## Introduction
Xen Orchestra includes a Kubernetes cluster [recipe](../xo5/advanced#recipes) that provides a simple way to deploy an official Kubernetes distribution called **MicroK8s** (maintained by Canonical).
:::tip
One of the key benefits of MicroK8s is its automatic security updates. For example, patch releases (like 1.30.x to 1.30.x+1) are applied automatically. This saves Kubernetes admins a lot of time and effort.
:::
### Networking and CNI
This recipe uses **Calico**, the default Container Network Interface (CNI) plugin included with MicroK8s, to handle container networking. Calico provides secure networking and network policies for Kubernetes, and its default configuration is ready for production—no additional setup required.
If you need to adjust the Calico setup (for example, to modify the CIDR range), check the [MicroK8s documentation](https://microk8s.io/docs/change-cidr) for step-by-step instructions.
#### Configure the pod CIDR
Since version 5.113 of Xen Orchestra, the pod and service CIDR can be customized via the recipe form. There is no need to perform manual configuration to change them. See [Deployment steps - 3.vii](./kubernetes.md#deployment-steps).
:::note
The default CIDR for pods is `10.1.0.0/16`. All pods are assigned an IP address in that range.
The default service CIDR is `10.152.183.0/24`. `10.152.183.1` will typically be reserved for the Kubernetes API, and `10.152.183.10` will be used by CoreDNS.
:::
### Cloud Controller Manager
This recipe automatically deploys the [Xen Orchestra Cloud Controller Manager](https://github.com/vatesfr/xenorchestra-cloud-controller-manager/tree/main). The Cloud Controller Manager (CCM) acts as a bridge between your Kubernetes cluster and the underlying Xen Orchestra instance.
It takes care of node initialization and sets the correct labels and taints for effective cluster management. When it notices that a VM has been deleted from Xen Orchestra, it automatically cleans up the associated node and removes it from the cluster.
For the CCM to function properly, the Xen Orchestra instance must be reachable by the cluster nodes (VMs) via either an FQDN or IP address. (See [Deployment steps - 3.vi](./kubernetes.md#deployment-steps).)
The recipe automatically generates an API token for the current user with a validity of 6 months.
:::warning
You will need to renew this token and update the `xenorchestra-cloud-controller-manager` secret in the Kubernetes cluster before it expires to maintain CCM functionality.
:::
#### Viewing the Current Token
To view the current token configuration in the secret:
```bash
kubectl get secret xenorchestra-cloud-controller-manager \
--namespace=kube-system \
-o json | jq -r '.data["config.yaml"]' | base64 -d
```
#### Refreshing the API Token
To refresh the token, generate a new one using the Xen Orchestra API and update the Kubernetes secret:
```bash
# 1. Generate a new token (replace with your XO URL)
# `-k` is needed if the cert is invalid
NEW_TOKEN=$(curl -X 'POST' \
--header 'Cookie: authenticationToken=<current-token>' \
'https://your-xo-instance.example.com/rest/v0/users/me/authentication_tokens' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"description": "token for CCM",
"expiresIn": "6 months"
}' | jq -r '.token.id')
# 2. Update the secret with the new token
kubectl get secret xenorchestra-cloud-controller-manager \
--namespace=kube-system \
-o json | \
jq --arg token "$NEW_TOKEN" '.data["config.yaml"] |= (@base64d | sub("token: .+"; "token: " + $token) | @base64)' | \
kubectl apply -f -
```
## Before you start
Make sure your infrastructure meets these requirements:
- A running Xen Orchestra instance connected to an XCP-ng pool
- A **VM template** for the base OS (e.g. an Ubuntu image)
- Enough resources to host the **control plane** and **worker nodes**
- The Xen Orchestra instance must be reachable by the cluster nodes/VMs - It can be reached via an FQDN or an IP address - This is for the XO CCM (Cloud Controller Manager).
## Deployment steps
1. In Xen Orchestra 5, go to **Hub → Recipes**.\
A list of recipes will appear:
![](../assets/hub_recipes.png)
2. Go to the **Kubernetes cluster** recipe and click **Create**.\
A cluster creation form appears:
![](../assets/kubernetes_cluster_creation.png)
3. Configure your cluster:
1. Select a pool where you want to deploy your cluster.
2. Select a storage repository, a network and a Kubernetes version.
3. Enter a name for your cluster.\
The name will be used to tag VMs (see [VM tagging](./kubernetes.md#vm-tagging)).
4. Define the number of worker nodes.
5. Define the number of nodes used for the control plane.
6. Define the FQDN or IP address that will be used by the Cloud Controller Manager (CCM) to reach this Xen Orchestra instance.\
*If the instance use a self signed HTTPS certificate, toggle "Allow insecure XO connection"*.
7. (Optional). If you want to change the default CIDR for your cluster pods and services, check the **Use a custom cluster CIDR** box and specify the new IP ranges to use.
![](../assets/k8s_cluster_custom_cidr.png)
9. (Optional). If you want your cluster to use static IP addresses, check the **Static IP addresses** box and specify the IP address parameters:
![](../assets/static_ip_addresses.png)
4. Click **OK** to start deploying the cluster.
Xen Orchestra handles the rest: cloning VMs, assigning IPs, bootstrapping Kubernetes and configuring internal networking.
### VM tagging
:::tip
The name provided to the cluster is also used to tag VMs, so that you can easily find them all:
:::
![](../assets/k8s-cluster-tags-1.png)
![](../assets/k8s-cluster-tags-2.png)
![](../assets/k8s-cluster-tags-3.png)
## During deployment
Follow the progress on the **Task** screen while the cluster is being created:
![](../assets/running_cluster_deployment.png)
## Using your cluster
### Connecting to your cluster
Once the cluster and its VMs are ready, SSH into the first control plane node. From there, you can manage your Kubernetes cluster.
For example:
```
$ ssh debian@<replace-by-vm-ip>
$ debian@cp-1:~$ microk8s kubectl get nodes
NAME STATUS ROLES AGE VERSION
cp-1 Ready <none> 40m v1.33.0
cp-2 Ready <none> 30m v1.33.0
cp-3 Ready <none> 31m v1.33.0
worker-1 Ready <none> 31m v1.33.0
worker-2 Ready <none> 31m v1.33.0
worker-3 Ready <none> 31m v1.33.0
```
### Adjusting VM Resources
The VMs in your Kubernetes cluster are created with default CPU and RAM settings, but you can easily adjust these to match your workload needs.
This gives you the flexibility to fine-tune performance or cut costs, depending on what your use case demands.
### Keeping your cluster updated
:::tip
MicroK8s handles **patch releases** automatically by design, so you always benefit from the latest security fixes and improvements without manual intervention. We think this is a great feature as it helps keep your cluster secure and up to date effortlessly.
:::
For **minor version upgrades** (for example, from `1.30.x` to `1.31.x`), you will need to follow the official [MicroK8s upgrade guide](https://microk8s.io/docs/upgrading?ref=xen-orchestra.com). These upgrades typically involve:
- Checking the current version with `microk8s version`
- Refreshing the MicroK8s snap to the desired channel
- Restarting the nodes if necessary
Example:
```bash
# Check current version
microk8s version
# Upgrade to a new minor release
sudo snap refresh microk8s --channel=1.31/stable
```
:::warning
Always review the MicroK8s documentation for the most up-to-date instructions before performing a minor upgrade.
:::
### Managing your cluster with external tools
Once the deployment finishes, Xen Orchestra provides a `kubeconfig` file. You can use it to manage your cluster with external tools:
For example:
```
$ microk8s config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: [...]
server: https://10.1.134.51:16443
name: microk8s-cluster
contexts:
- context:
cluster: microk8s-cluster
user: admin
name: microk8s
current-context: microk8s
kind: Config
preferences: {}
users:
- name: admin
user:
client-certificate-data: LS0tLS1CRU[...]
client-key-data: LS0tLS1CRUdJ[...]
```
### Add-ons
In addition to the core components of the Kubernetes control plane, this recipe automatically installs the following add-ons:
- **DNS:** Deploys CoreDNS for internal address resolution.
- **Helm:** Installs [Helm 3](https://helm.sh/), the Kubernetes package manager.
- **RBAC:** Enable [Role-based access control (RBAC)](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) for authorization.
When **high availability (HA)** is enabled, the recipe also includes:
- **HA-cluster:** Ensures high availability for clusters with three or more nodes.
- **[Kube-VIP](https://kube-vip.io/):** Provides a virtual IP and load balancer for the control plane, deployed via the official Helm chart.
## Best Practices
When deploying Kubernetes clusters with recipes, its important to plan for performance and reliability.
- Always allocate enough CPU and memory resources for both control plane and worker nodes. Using three control plane nodes ensures high availability in production environments.
- Place the VMs on shared storage to allow live migration if needed.
- For security, restrict SSH and api-server accesses and consider enabling RBAC and network policies once the cluster is running.
Finally, keep your base template up to date with the latest OS patches and Kubernetes tools to avoid compatibility issues.
## Related links
- [Kubernetes official documentation](https://kubernetes.io/docs/home/)
- [MicroK8s official documentation](https://microk8s.io/docs)
- [CoreDNS official documentation](https://coredns.io/manual/toc/)

View File

@@ -0,0 +1 @@
# Packer provider

View File

@@ -0,0 +1,141 @@
# Powershell module
## Introduction
Xen Orchestra (XO) is a powerful tool for managing XCP-ng and XenServer virtualisation environments. However, relying solely on the web interface can result in repetitive manual tasks. For system administrators, particularly those working in Windows-centric environments, **PowerShell** is the go-to automation tool. The `xo-powershell` module combines the strengths of these two tools by offering PowerShell's scripting capabilities to interact directly with the Xen Orchestra API. This article presents the most impactful features of the module, which can significantly simplify and accelerate the management of your virtualisation infrastructure.
## Single-Line Installation and Connection
The `xo-powershell` module stands out for its ease of adoption, with simple installation from the [PowerShell Gallery](https://www.powershellgallery.com/packages/xo-powershell/) in a single command.
:::info
**Prerequisites**: PowerShell 7.0 or higher. The module is compatible with Windows PowerShell and PowerShell Core.
:::
```bash
Install-Module -Name xo-powershell -AllowPrerelease
```
Likewise, connecting to your Xen Orchestra instance is just as straightforward, requiring only the host address and an API token.
:::info
**Obtaining the API token**: In Xen Orchestra, go to User Space → Edit my settings → Authentication tokens to generate an API token. [Learn more about authentication](https://docs.xcp-ng.org/management/manage-at-scale/xo-api/#authentification).
:::
```bash
Connect-XoSession -HostName "https://your-xo-server" -Token "your-api-token"
```
## The Power of the Pipeline for Advanced Automation
What distinguishes this module from a simple API wrapper is its deep integration with the PowerShell pipeline. Most commands are designed to pass objects to one another, allowing the creation of single-line commands that are both powerful and expressive.
### Example (Simple Usage Examples)
* **List XCP-ng servers:**
```bash
Get-XoServer
```
![](../assets/wb_xo_psh5.png)
* **Monitor ongoing tasks:**
```bash
Get-XoTask
```
![](../assets/wb_xo_psh6.png)
* **Get information about virtual disks:**
```bash
Get-XoVdi
```
![](../assets/wb_xo_psh7.png)
* **To stop all virtual machines whose name contains "`Test`," the following command suffices:**
```bash
Get-XoVm | Where-Object { $_.Name -like "*Test*" } | Stop-XoVm
```
- This command first retrieves the list of all VMs, filters it to keep only those whose name matches the criteria, and then passes only these VMs to the `Stop-XoVm` command.
- This is possible because `Get-XoVm` does not simply return text but a collection of PowerShell objects. Each VM object has properties (`.Name`, `.Memory`, etc.) that can be inspected by `Where-Object` before the complete object is passed to the next command.
* **This principle also applies to more complex filtering, such as suspending running VMs with more than 4 GB of memory.**
```bash
Get-XoVm -PowerState Running | Where-Object { $_.Memory.size -gt 4294967296 } | Suspend-XoVm
```
:::info
This capability transforms script writing, moving from a series of disconnected commands to a fluid flow of data and actions.
:::
## Extended Environment Control (VM Management)
Although virtual machine management is an essential function, the scope of the module is much broader, offering complete control over the entire virtualisation environment. It provides in-depth coverage of all facets of the infrastructure.
- **Practical Use Cases**
| Scenario | Command Sequence | Benefit |
| :--- | :--- | :--- |
| **Storage Audit** | `Get-XoSr` → `Get-XoVdi` → `Get-XoVmVdi` | Comprehensive storage utilization view |
| **Maintenance Planning** | `Get-XoHost` → `Get-XoVm` → `Stop-XoVm` → `Wait-XoTask` | Planned maintenance without data loss |
| **Session Verification** | `Test-XoSession` | Verify automation readiness |
This extended control is particularly useful. The 'Wait-XoTask' command enables the creation of robust scripts that wait for lengthy operations (such as creating a **snapshot**) to complete before continuing execution. This functionality makes the module a true command-line interface for Xen Orchestra and not just a tool for a few common tasks.
### Example: Creating virtual machine snapshots
This demonstration shows how to create and verify a virtual machine snapshot.
- **Step 1: Identify a Base VM**
```bash
Get-XoVm | Format-Table Name, Uuid, PowerState
```
![](../assets/wb_xo_psh1.png)
- **Step 2: Create a Snapshot**
```bash
New-XoVmSnapshot -VmUuid "993d84c2-2571-8451-8073-afa8ef510a8d" -SnapshotName "your-snapshot-name"
```
![](../assets/wb_xo_psh2.png)
- **Step 3: Verify Snapshot Creation**
```bash
Get-XoVmSnapshot -Filter "name_label:your-snapshot-name"
```
![](../assets/wb_xo_psh3.png)
![](../assets/wb_xo_psh4.png)
<!--
## Export Your Disks and Snapshots Directly to VHD or RAW
The module simplifies complex tasks such as exporting virtual disks (VDI) and their snapshots. The ideal way to back up the current state of a virtual disk is to use the `Export-XoVdi` command.
```bash
Export-XoVdi -VdiId "a1b2c3d4" -Format vhd -OutFile "C:\exports\disk_backup.vhd"
```
Furthermore, to create an archive of a *point-in-time* version of a disk, you can export one of its snapshots directly. This is ideal for backup or migration workflows based on specific restoration points, as it does not affect the active VM.
```bash
Export-XoVdiSnapshot -VdiSnapshotId "e5f6g7h8" -Format vhd -OutFile "C:\archives\disk_snapshot_archive.vhd"
```
This distinction enables granular backup and migration strategies that are fully script-managed.
-->
## Conclusion: Rethink Your XCP-ng Management
The `Xo-powershell` module is much more than just a collection of commands: it is a gateway to powerful, scalable and efficient automation within the XCP-ng/Xen Orchestra ecosystem. Leveraging the PowerShell pipeline and a comprehensive set of commands aligns it with the DevOps philosophy, bringing automation practices closer to Windows administrators and helping them save valuable time while reducing the risk of human error.
## Related links
- [PowerShell Gallery](https://www.powershellgallery.com/packages/xo-powershell/)
- [PowerShell module GitHub](https://xcp-ng.org/forum/category/29/infrastructure-as-code)
- [Learn more about authentication](https://docs.xcp-ng.org/management/manage-at-scale/xo-api/#authentification)

View File

@@ -0,0 +1,466 @@
# Pulumi provider
## Introduction
Manually managing infrastructure can lead to errors and increased complexity. With Infrastructure as Code (IaC), however, we can describe our infrastructure in configuration files, making it **predictable**, **reproducible** and **versioned**.
This tutorial will guide you through using **Pulumi**, a modern IaC tool, to automate the deployment and updating of your **virtual machines (VMs)** on **Xen Orchestra (XO)**.
:::note
Pulumi supports several programming languages (TypeScript, Python, Go, .NET, etc.), but we will use TypeScript for this example. To do this, you need to install Node/NPM version 20 or higher.
:::
:::tip
Pulumi's approach allows you to use real programming languages to define your infrastructure, offering more flexibility and power than traditional configuration languages.
:::
## Launching virtual machines in XO with Pulumi
In this tutorial, we will guide you through the process of using `Pulumi` to launch a virtual machine (VM) on your Xen Orchestra (XO) instance and demonstrate how to easily modify it.
:::note
Since Pulumi relies on the Xen Orchestra API to abstract hosts, pools, networks, disks and virtual machines (VMs), as well as to manipulate them declaratively, ensure you have a functioning Xen Orchestra instance connected to XCP-ng before you begin.
:::
**Here are the four main steps we will follow:**
1. Install Pulumi
2. Create a Pulumi project
3. Use Pulumi to provision the VM
4. Add an additional network interface to the VM
:::tip
The code used in this tutorial can be found on [GitHub](https://github.com/vatesfr/pulumi-xenorchestra), but we will write it from scratch step by step.
:::
### Installing Pulumi
If you haven't installed Pulumi yet, follow the [official Pulumi tutorial](https://www.pulumi.com/docs/install/) to install it on your system.
:::info
**Required version**: This tutorial requires Pulumi version v3.0+ or newer, as well as the Xen Orchestra provider version v2.0+.
:::
### Using VM Templates in Xen Orchestra
Pulumi needs a starting point to create a VM. This can be a `template` that already contains an operating system installed with **cloud-init** capabilities (or **Cloudbase-init** for Windows), as well as **Xen/Guest Tools** for better integration with Xen Orchestra.
:::info
We recommend using the pre-built templates from the **XOA Hub** for optimal results.
- **Debian 13** (with cloud-init)
- **Ubuntu 22.04/24.04** (with cloud-init)
- **etc.**
For more information on templates:
- [Creating VM templates](https://docs.xen-orchestra.com/vm-templates#creating-templates)
- [Cloud-init and Cloudbase-init](https://docs.xen-orchestra.com/vm-templates#cloud-init-and-cloudbase-init)
:::
### Provisioning your VM with Pulumi
Now that Pulumi is installed and you have a VM template ready in your environment, you can start writing the configuration files that describe your infrastructure.
1. **Creating the Pulumi project**
Create a new directory for your project and initialise the project:
```bash
mkdir xo-pulumi-project
cd xo-pulumi-project
pulumi new typescript
```
2. **Installing the Xen Orchestra provider**
Install the Pulumi Xen Orchestra package:
```bash
npm install @vates/pulumi-xenorchestra
```
3. **Securely configuring credentials**
In order to authenticate Pulumi with your **Xen Orchestra API**, credentials are required.
:::warning
Never store passwords directly in your code. The recommended method is to use environment variables.
:::
- Create a `~/.xoa` file in your home directory containing the following content:
```bash
export XOA_URL=ws://hostname-of-your-deployment
export XOA_USER=YOUR_USERNAME
export XOA_PASSWORD=YOUR_PASSWORD
```
Or, if you are using a token:
```bash
export XOA_URL=ws://hostname-of-your-deployment
export XOA_TOKEN=YOUR_TOKEN
```
- Then, before running Pulumi, load these variables into your terminal session:
```bash
eval $(cat ~/.xoa)
```
:::tip
It is also possible to use the Pulumi configuration to store the credentials.
```bash
pulumi config set xenorchestra:url ws://your-xo-hostname
pulumi config set xenorchestra:token YOUR_TOKEN --secret
```
:::
4. **Defining existing resources (data sources)**
Pulumi needs to be aware of the resources already in place in XO (e.g. your pool, network and storage). To achieve this, we use data calls to retrieve existing information.
Edit the `index.ts` file and replace its contents with:
```typescript
import * as pulumi from "@pulumi/pulumi";
import * as xenorchestra from "@vates/pulumi-xenorchestra";
// Retrieving the pool
const pool = xenorchestra.getXoaPool({
nameLabel: "Main pool",
});
// Retrieve the template
const template = xenorchestra.getXoaTemplate({
nameLabel: "Ubuntu 24.04 Cloud-Init",
});
// Retrieve the storage repository
const storageRepository = pool.then(p =>
xenorchestra.getXoaStorageRepository({
nameLabel: "ZFS",
poolId: p.id,
})
);
// Retrieve the network
const network = pool.then(p =>
xenorchestra.getXoaNetwork({
nameLabel: "Pool-wide network",
poolId: p.id,
})
);
```
:::tip
Using explicit `nameLabel` values is appropriate for this tutorial.
However, in real-world environments, it is recommended to use **unique names** to avoid conflicts or misconfigurations when multiple resources share similar labels.
:::
5. **Defining the VM resource**
Now that Pulumi knows where to find the template, storage and network, we can define the VM that we want to create.
Add the following code to the end of your `index.ts` file:
:::tip
If your template uses multiple disks, make sure you declare the same number of disks in your VM resource and pay attention to the order. The disks must be at least the same size as those in the template.
:::
```typescript
// Creating the VM
const vm = new xenorchestra.Vm("xo-pulumi-tutorial", {
memoryMax: 2 * 1024 * 1024 * 1024, // 2GB
cpus: 1,
nameLabel: "XO Pulumi Tutorial",
template: template.then(t => t.id),
networks: [
{
networkId: network.then(n => n.id),
},
],
disks: [
{
srId: storageRepository.then(sr => sr.id),
nameLabel: "VM root volume",
size: 50 * 1024 * 1024 * 1024, // 50GB
},
],
});
// Export
export const vmId = vm.id;
export const vmName = vm.nameLabel;
export const ipv4 = vm.ipv4Addresses;
```
This code describes the characteristics of the VM to be created, including its `name`, `memory` and `CPU`. It uses the retrieved data to connect to the correct model, network and storage.
6. **Deploying the VM**
It's time to bring our VM to life!
* Run `pulumi up`
This command will analyse your code and show you what it is about to do. The output will indicate that a new resource is going to be created.
```bash
pulumi up
```
Pulumi will then show you a preview of the changes and ask for confirmation before proceeding.
```bash
Previewing update (dev)
View in Browser (Ctrl+O): https://app.pulumi.com/batchayw-org/xo-pulumi-project/dev/previews/13fa0ed6-67f7-463d-8e18-83a1fa9571e2
Type Name Plan
+ pulumi:pulumi:Stack xo-pulumi-project-dev create
+ └─ xenorchestra:index:Vm xo-pulumi-tutorial create
Outputs:
ipv4 : [unknown]
vmId : [unknown]
vmName: "XO Pulumi Tutorial"
Resources:
+ 2 to create
Do you want to perform this update?
```
* Confirm with `yes`
Pulumi will then deploy the VM on Xen Orchestra.
```bash
Updating (dev)
View in Browser (Ctrl+O): https://app.pulumi.com/batchayw-org/xo-pulumi-project/dev/updates/1
Type Name Status
+ pulumi:pulumi:Stack xo-pulumi-project-dev created (19s)
+ └─ xenorchestra:index:Vm xo-pulumi-tutorial created (17s)
Outputs:
vmId : "0ae54d06-e3e2-100c-00e8-46f67945e37c"
vmName: "XO Pulumi Tutorial"
Resources:
+ 2 created
Duration: 21s
```
🚀🎉 Congratulations! Your VM has now been deployed via Pulumi on XO.
![](../assets/wb_xo_pl1.png)
Any future changes to this VM can now be easily **revised** and **versioned**.
To demonstrate this, let's imagine that this VM needs a second network interface. Let's see how we can easily implement this change.
### Updating existing infrastructure
One of Pulumi's greatest strengths lies in its ability to manage changes throughout your infrastructure's lifecycle.
Our goal is straightforward: to add a second network interface to the VM we just created.
To achieve this, simply edit the `index.ts` file and add a second network block to your VM definition.
```typescript
// Create the virtual machine with two network interfaces
const vm = new xenorchestra.Vm("xo-pulumi-tutorial", {
memoryMax: 2 * 1024 * 1024 * 1024, // 2GB
cpus: 1,
nameLabel: "XO Pulumi Tutorial",
template: template.then(t => t.id),
networks: [
{
networkId: network.then(n => n.id),
},
// Second network interface
{
networkId: network.then(n => n.id),
},
],
disks: [
{
srId: storageRepository.then(sr => sr.id),
nameLabel: "VM root volume",
size: 50 * 1024 * 1024 * 1024, // 50GB
},
],
});
```
The process for applying changes is exactly the same as for creating them.
* Run `pulumi up`
This time, the output will be different. Pulumi has detected that the resource already exists and needs to be modified, not created. You will be able to see exactly which network block is going to be added.
```bash
Previewing update (dev)
View in Browser (Ctrl+O): https://app.pulumi.com/batchayw-org/xo-pulumi-project/dev/previews/9c687495-ba9d-4a8a-8446-f9bb8c2f1826
Type Name Plan Info
pulumi:pulumi:Stack xo-pulumi-project-dev
~ └─ xenorchestra:index:Vm xo-pulumi-tutorial update [diff: ~networks]
Resources:
~ 1 to update
1 unchanged
Do you want to perform this update?
```
* Confirm with `yes`
After confirmation, Pulumi will add the new network interface to your existing VM.
```bash
Updating (dev)
View in Browser (Ctrl+O): https://app.pulumi.com/batchayw-org/xo-pulumi-project/dev/updates/2
Type Name Status Info
pulumi:pulumi:Stack xo-pulumi-project-dev
~ └─ xenorchestra:index:Vm xo-pulumi-tutorial updated (29s) [diff: ~networks]
Outputs:
vmId : "0ae54d06-e3e2-100c-00e8-46f67945e37c"
vmName: "XO Pulumi Tutorial"
Resources:
~ 1 updated
1 unchanged
Duration: 32s
```
With just a few lines of code, you can modify your infrastructure in a controlled and reproducible manner.
* ***Before modification: single network interface***
![](../assets/wb_xo_pl2.png)
* ***After adding the second network interface***
![](../assets/wb_xo_pl3.png)
## Advanced Features
### Using Cloud-Init
Pulumi supports `cloud-init` configuration to customize your VMs during deployment.
```typescript
const vmWithCloudInit = new xenorchestra.Vm("vm-with-cloudinit", {
// ... other parameters
cloudConfig: `#cloud-config
users:
- name: demo
sudo: ALL=(ALL) NOPASSWD:ALL
ssh-authorized-keys:
- ssh-rsa <YOUR_PUBLIC_KEY_HERE>
packages:
- nginx
- git
runcmd:
- systemctl enable nginx
- systemctl start nginx
`,
});
```
### Managing multiple disks
You can easily add multiple disks to a VM.
```typescript
const vmWithMultipleDisks = new xenorchestra.Vm(“vm-multi-disk”, {
// ... other parameters
disks: [
{
srId: storageRepository.then(sr => sr.id),
nameLabel: “System disk”,
size: 30 * 1024 * 1024 * 1024, // 30 GB
},
{
srId: storageRepository.then(sr => sr.id),
nameLabel: “Data disk”,
size: 100 * 1024 * 1024 * 1024, // 100 GB
},
],
});
```
### Tag configuration
Add tags to organize and manage your resources.
```typescript
const taggedVm = new xenorchestra.Vm(“tagged-vm”, {
// ... other parameters
tags: [“production”, “web-server”, “pulumi-managed”],
});
```
## Debugging and logs
The provider supports detailed logging to facilitate troubleshooting and debugging.
* **Enabling Pulumi logs**
To enable debug logging, use the verbosity flags.
```bash
pulumi up --debug
```
Or for more details
```bash
pulumi up --logtostderr -v=9
```
* **Xen Orchestra provider logs**
The Xen Orchestra provider also logs its activities. These logs can be viewed in the Pulumi output when debug mode is enabled.
:::note
Only enable debug logging when troubleshooting, as it can significantly increase log verbosity and impact performance.
:::
## Best practices
### State Management
:::warning
Pulumi state contains sensitive information about your infrastructure. Always use a secure backend such as a self-hosted solution or local encrypted storage.
:::
```bash
# Configuration with local encrypted backend (recommended for full control)
pulumi login file://~ # Encrypted local storage in home directory
pulumi login --local # Default location
# Or configuration with a self-hosted backend
pulumi login s3://my-pulumi-state-bucket
pulumi login gs://my-pulumi-state-bucket
pulumi login azblob://my-pulumi-state-bucket
```
## Conclusion
The Pulumi provider for Xen Orchestra is an important step towards VirtOps, which involves applying DevOps practices to virtualisation. By adopting Infrastructure as Code with Pulumi, you can achieve greater reliability, reproducibility and efficiency while transforming infrastructure management into a more collaborative and auditable process.
:::note
For detailed documentation on the provider, see the [official NPM package](https://github.com/vatesfr/pulumi-xenorchestra), which contains up-to-date information on all resources, data sources, and versions.
:::
## Related links
- [Pulumi documentation](https://www.pulumi.com/docs)
- [Pulumi code examples](https://github.com/vatesfr/pulumi-xenorchestra/tree/v2.3.0/examples)
- [Pulumi GitHub](https://github.com/vatesfr/pulumi-xenorchestra/issues)
- [Xen Orchestra docs](https://docs.xen-orchestra.com)
- [XCP-ng forum](https://xcp-ng.org/forum/)

View File

@@ -0,0 +1,598 @@
# Terraform provider
## Introduction
Managing infrastructure manually often leads to errors and complexity. With Infrastructure as Code (IaC), we describe our infrastructure in configuration files to make it **predictable**, **reproducible**, and **version-controlled**.
This tutorial will guide you through using **Terraform** or **OpenTofu**, the leading IaC tools, to automate the deployment and updating of your **VMs** on **Xen Orchestra**.
:::note
This guide works with both **Terraform** and **OpenTofu**. OpenTofu is a community-driven fork of Terraform that maintains compatibility.
:::
:::tip
Terraforms two-step workflow (`plan` then `apply`) gives you full control. You can preview all changes before applying them, ensuring safe and predictable deployments while saving time and effort.
:::
## Launching Virtual Machines in XO with Terraform
In this guide, well walk you step-by-step through using `Terraform` to launch a virtual machine (VM) on your Xen Orchestra (XO) instance, and then show you how to modify it easily.
:::note
*Before starting, make sure you have a running **Xen Orchestra** instance connected to an **XCP-ng** pool.*
:::
**Here are the 4 main steps well follow:**
1. Install Terraform
2. Create a VM template
3. Provision the VM with Terraform
4. Add an additional network interface to the VM
:::tip
The code used in this tutorial can be found on [GitHub](https://github.com/vatesfr/terraform-provider-xenorchestra), but well write it from scratch step by step.
:::
### Installing Terraform
If you havent installed Terraform yet, start by following the [official Hashicorp tutorial](https://developer.hashicorp.com/terraform/install) to install it on your system.
:::info
**Required Version**: This tutorial requires Terraform `1.13.1` or newer, or OpenTofu `1.10.0` or newer.
:::
### Using VM Templates in Xen Orchestra
Terraform needs a starting point to create a VM: a `template` that already contains an installed operating system with **cloud-init** capabilities (or **Cloudbase-init** for Windows), as well as **Xen/Guest Tools** for better integration with Xen Orchestra. This setup enables automatic customization during deployment and simplifies VM management, including IP assignment and hostname configuration.
:::info
We recommend using pre-built templates from the **XOA Hub** for optimal results:
- **Debian 13** (with cloud-init)
- **Ubuntu 22.04/24.04** (with cloud-init)
- **etc.**
For more information about templates:
- [Creating VM Templates](https://docs.xen-orchestra.com/vm-templates#creating-templates)
- [Cloud-init and Cloudbase-init](https://docs.xen-orchestra.com/vm-templates#cloud-init-and-cloudbase-init)
- [Windows Templates with Cloudbase-init](https://xen-orchestra.com/blog/windows-templates-with-cloudbase-init-step-by-step-guide-best-practices/)
:::
### Provisioning Your VM with Terraform
Now that Terraform is installed and your environment has a VM template ready, lets start writing the configuration files that describe our infrastructure.
We will now create the configuration files that describe our infrastructure.
1. **Configure the Provider**
The first step is to tell Terraform to communicate with Xen Orchestra by declaring the **official provider**. Create a file named `provider.tf` and add the following code.
:::info
**Provider Version**: This tutorial uses version `~> 0.35` of the Xen Orchestra provider. Check the [official provider documentation](https://registry.terraform.io/providers/vatesfr/xenorchestra/latest) for the latest version and release notes.
:::
```tf
# provider.tf
terraform {
required_providers {
xenorchestra = {
source = "vatesfr/xenorchestra"
version = "~> 0.35"
}
}
}
```
This code tells Terraform to download [Xen Orchestra Terraform provider](https://github.com/vatesfr/terraform-provider-xenorchestra) from the [official Terraform registry](https://registry.terraform.io/providers/vatesfr/xenorchestra/latest).
Next, open your terminal in this folder and run `terraform init`. This command reads your configuration, downloads the Xen Orchestra provider, and sets up your working environment.
You should see output confirming successful initialization.
```bash
william@william:~$ terraform init
Initializing the backend...
Initializing provider plugins...
- Finding vatesfr/xenorchestra versions matching "~> 0.35"...
- Installing vatesfr/xenorchestra v0.35.1...
- Installed vatesfr/xenorchestra v0.35.1 (self-signed, key ID 3084D82948625D89)
Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://developer.hashicorp.com/terraform/cli/plugins/signing
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
```
2. **Handle Credentials Securely**
To authenticate Terraform with your **Xen Orchestra API**, it needs credentials.
:::warning
Never store passwords directly in your code. The recommended method is to use environment variables.
:::
- Create a file `~/.xoa` in your home directory with the following content.
```bash
export XOA_URL=ws://hostname-of-your-deployment
export XOA_USER=YOUR_USERNAME
export XOA_PASSWORD=YOUR_PASSWORD
```
Or using a token:
```bash
export XOA_URL=ws://hostname-of-your-deployment
export XOA_TOKEN=YOUR_TOKEN
```
- Then, before running Terraform, load these variables into your terminal session.
```bash
eval $(cat ~/.xoa)
```
:::tip
Its also possible to use variables to configure authentication details.
This can be useful in some cases, especially to avoid storing credentials in plain text.
```bash
provider "xenorchestra" {
# Must be ws or wss
token = local.xoa_token # or set the XOA_TOKEN environment variable
url = "ws://${local.xoa_url}" # or set the XOA_URL environment variable
}
```
:::
3. **Define Existing Resources (Data Sources)**
Terraform needs to know about existing resources in XO (your pool, network, storage, etc.). For that, we use `data` blocks and read-only queries that fetch existing information. This avoids hardcoding technical identifiers (UUIDs, etc.) and makes your configuration more readable and portable.
Create a file named `vm.tf` (or `data-source.tf`, as most people do) and add the following code, making sure to replace the `name_label` values with the exact names of your resources in Xen Orchestra (the names of your pool, network, storage repository, and VM template, respectively).
```tf
# vm.tf
data "xenorchestra_pool" "pool" {
name_label = "Main pool"
}
data "xenorchestra_template" "vm_template" {
name_label = "Ubuntu 24.04 Cloud-Init"
}
data "xenorchestra_sr" "sr" {
name_label = "ZFS"
pool_id = data.xenorchestra_pool.pool.id
}
data "xenorchestra_network" "network" {
name_label = "Pool-wide network"
pool_id = data.xenorchestra_pool.pool.id
}
```
:::tip
Using explicit `name_label` values is fine for this tutorial.
However, in real environments, its recommended to use **unique names** to prevent conflicts or misconfigurations when multiple resources share similar labels.
:::
4. **Verify Data Sources**
At this stage, even before defining our VM, we can run `terraform plan` for the first time. This is an excellent practice to ensure that Terraform can successfully connect to Xen Orchestra and locate all the resources we have declared.
```bash
william@william:~$ terraform plan
data.xenorchestra_pool.pool: Reading...
data.xenorchestra_template.vm_template: Reading...
data.xenorchestra_pool.pool: Read complete after 0s [id=355ee47d-ff4c-4924-3db2-fd86ae629676]
data.xenorchestra_network.network: Reading...
data.xenorchestra_sr.sr: Reading...
data.xenorchestra_network.network: Read complete after 0s [id=a12df741-f34f-7d05-f120-462f0ab39a48]
data.xenorchestra_template.vm_template: Read complete after 0s [id=d0b0869b-2503-0c17-1e5e-3725f6eba342]
data.xenorchestra_sr.sr: Read complete after 0s [id=86a9757d-9c05-9fe0-e79a-8243cb1f37f3]
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
```
The message `No changes. Infrastructure is up-to-date.` or `No changes. Your infrastructure matches the configuration.` is exactly what were expecting. It confirms that our data sources are correctly configured and that Terraform has successfully found the corresponding `pool`, `template`, `SR`, and `network`.
5. **Define the VM Resource**
Now that Terraform knows where to find the template, storage, and network, we can finally define the VM we want to create.
Add the following code block at the end of your `vm.tf` file, or create a new file named `resources.tf`.
:::tip
If your template uses multiple disks, be careful to declare the same number of disks in your VM resource, paying attention to the order. The disks must be at least the same size as those in the template.
:::
```tf
resource "xenorchestra_vm" "vm" {
memory_max = 2147467264
cpus = 1
name_label = "XO terraform tutorial"
template = data.xenorchestra_template.vm_template.id
network {
network_id = data.xenorchestra_network.network.id
}
disk {
sr_id = data.xenorchestra_sr.sr.id
name_label = "VM root volume"
size = 50214207488
}
}
```
This `resource` block describes the characteristics of the VM to be created : its `name`, `memory`, and `CPU`. It uses the information retrieved from the data sources to connect to the correct template, network, and storage.
:::note
The code above uses the `.vm_template.id` and `.sr.id` references to match the data sources we defined, ensuring that the configuration works properly.
:::
6. **Plan and Deploy the VM**
Its time to bring our VM to life !
* Run `terraform plan`
This command will analyze your code and show you what its about to do. The output will indicate that a new resource is going to be created.
```bash
william@william:~$ terraform plan
data.xenorchestra_pool.pool: Reading...
data.xenorchestra_template.vm_template: Reading...
data.xenorchestra_pool.pool: Read complete after 1s [id=355ee47d-ff4c-4924-3db2-fd86ae629676]
data.xenorchestra_network.network: Reading...
data.xenorchestra_sr.sr: Reading...
data.xenorchestra_template.vm_template: Read complete after 1s [id=d0b0869b-2503-0c17-1e5e-3725f6eba342]
data.xenorchestra_network.network: Read complete after 0s [id=a12df741-f34f-7d05-f120-462f0ab39a48]
data.xenorchestra_sr.sr: Read complete after 0s [id=86a9757d-9c05-9fe0-e79a-8243cb1f37f3]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
+ create
Terraform will perform the following actions:
# xenorchestra_vm.vm will be created
+ resource "xenorchestra_vm" "vm" {
+ auto_poweron = false
+ clone_type = "fast"
+ core_os = false
+ cpu_cap = 0
+ cpu_weight = 0
+ cpus = 1
+ destroy_cloud_config_vdi_after_boot = false
+ exp_nested_hvm = false
+ hvm_boot_firmware = "bios"
+ id = (known after apply)
+ ipv4_addresses = (known after apply)
+ ipv6_addresses = (known after apply)
+ memory_max = 2147467264
+ memory_min = (known after apply)
+ name_label = "XO terraform tutorial"
+ power_state = "Running"
+ start_delay = 0
+ template = "d0b0869b-2503-0c17-1e5e-3725f6eba342"
+ vga = "std"
+ videoram = 8
+ disk {
+ name_label = "VM root volume"
+ position = (known after apply)
+ size = 50214207488
+ sr_id = "86a9757d-9c05-9fe0-e79a-8243cb1f37f3"
+ vbd_id = (known after apply)
+ vdi_id = (known after apply)
}
+ network {
+ device = (known after apply)
+ ipv4_addresses = (known after apply)
+ ipv6_addresses = (known after apply)
+ mac_address = (known after apply)
+ network_id = "a12df741-f34f-7d05-f120-462f0ab39a48"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
```
* Run `terraform apply`
If the plan looks good to you, run this command to apply the changes. Terraform will ask for final confirmation, type `yes` and press `Enter`.
```bash
william@william:~$ terraform apply
data.xenorchestra_template.vm_template: Reading...
data.xenorchestra_pool.pool: Reading...
data.xenorchestra_pool.pool: Read complete after 1s [id=355ee47d-ff4c-4924-3db2-fd86ae629676]
data.xenorchestra_network.network: Reading...
data.xenorchestra_sr.sr: Reading...
data.xenorchestra_template.vm_template: Read complete after 1s [id=d0b0869b-2503-0c17-1e5e-3725f6eba342]
data.xenorchestra_network.network: Read complete after 0s [id=a12df741-f34f-7d05-f120-462f0ab39a48]
data.xenorchestra_sr.sr: Read complete after 0s [id=86a9757d-9c05-9fe0-e79a-8243cb1f37f3]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
+ create
Terraform will perform the following actions:
# xenorchestra_vm.vm will be created
+ resource "xenorchestra_vm" "vm" {
+ auto_poweron = false
+ clone_type = "fast"
+ core_os = false
+ cpu_cap = 0
+ cpu_weight = 0
+ cpus = 1
+ destroy_cloud_config_vdi_after_boot = false
+ exp_nested_hvm = false
+ hvm_boot_firmware = "bios"
+ id = (known after apply)
+ ipv4_addresses = (known after apply)
+ ipv6_addresses = (known after apply)
+ memory_max = 2147467264
+ memory_min = (known after apply)
+ name_label = "XO terraform tutorial"
+ power_state = "Running"
+ start_delay = 0
+ template = "d0b0869b-2503-0c17-1e5e-3725f6eba342"
+ vga = "std"
+ videoram = 8
+ disk {
+ name_label = "VM root volume"
+ position = (known after apply)
+ size = 50214207488
+ sr_id = "86a9757d-9c05-9fe0-e79a-8243cb1f37f3"
+ vbd_id = (known after apply)
+ vdi_id = (known after apply)
}
+ network {
+ device = (known after apply)
+ ipv4_addresses = (known after apply)
+ ipv6_addresses = (known after apply)
+ mac_address = (known after apply)
+ network_id = "a12df741-f34f-7d05-f120-462f0ab39a48"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
xenorchestra_vm.vm: Creating...
xenorchestra_vm.vm: Still creating... [00m10s elapsed]
xenorchestra_vm.vm: Creation complete after 17s [id=66ec6080-1a77-b460-1d63-8b39baa4a844]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
```
🚀🎉 Congratulations! Your VM is now deployed via Terraform on XO.
![](../assets/wb_xo_tf1.png)
Any future modifications to this VM can now be easily **reviewed** and **version-controlled**.
To demonstrate this, lets imagine that this VM needs a second network interface. Lets see how easily we can make that change.
### Updating an Existing Infrastructure
One of Terraforms greatest advantages is its ability to manage changes throughout the entire lifecycle of your infrastructure.
Our goal is simple: to add a second network interface to the VM we just created.
To do this, simply modify the `resources.tf` file (or `vm.tf` if you combined everything) and add a second `network` block to your VM definition.
```tf
resource "xenorchestra_vm" "vm" {
memory_max = 2147467264
cpus = 1
name_label = "XO terraform tutorial"
template = data.xenorchestra_template.vm_template.id
# First network interface
network {
network_id = data.xenorchestra_network.network.id
}
# Second network interface
network {
network_id = data.xenorchestra_network.network.id
}
disk {
sr_id = data.xenorchestra_sr.sr.id
name_label = "VM root volume"
size = 50214207488
}
}
```
Once the file is modified, the process of applying the change is exactly the same as for creation.
* Run `terraform plan`
This time, the output will be different. Terraform has detected that the resource already exists and needs to be **modified**, not created. Youll be able to see exactly which `network` block is going to be added.
```bash
william@william:~$ terraform plan
data.xenorchestra_pool.pool: Reading...
data.xenorchestra_template.vm_template: Reading...
data.xenorchestra_pool.pool: Read complete after 0s [id=355ee47d-ff4c-4924-3db2-fd86ae629676]
data.xenorchestra_network.network: Reading...
data.xenorchestra_sr.sr: Reading...
data.xenorchestra_template.vm_template: Read complete after 0s [id=d0b0869b-2503-0c17-1e5e-3725f6eba342]
data.xenorchestra_network.network: Read complete after 0s [id=a12df741-f34f-7d05-f120-462f0ab39a48]
data.xenorchestra_sr.sr: Read complete after 0s [id=86a9757d-9c05-9fe0-e79a-8243cb1f37f3]
xenorchestra_vm.vm: Refreshing state... [id=66ec6080-1a77-b460-1d63-8b39baa4a844]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
~ update in-place
Terraform will perform the following actions:
# xenorchestra_vm.vm will be updated in-place
~ resource "xenorchestra_vm" "vm" {
id = "66ec6080-1a77-b460-1d63-8b39baa4a844"
tags = []
# (24 unchanged attributes hidden)
disk {
# (8 unchanged attributes hidden)
}
+ network {
+ attached = true
+ ipv4_addresses = (known after apply)
+ ipv6_addresses = (known after apply)
+ network_id = "a12df741-f34f-7d05-f120-462f0ab39a48"
}
# (1 unchanged block hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
```
* Run `terraform apply`
Run the command to apply the change. After confirming with `yes`, Terraform will add the new network interface to your existing VM.
```bash
william@william:~$ terraform apply
data.xenorchestra_pool.pool: Reading...
data.xenorchestra_template.vm_template: Reading...
data.xenorchestra_pool.pool: Read complete after 0s [id=355ee47d-ff4c-4924-3db2-fd86ae629676]
data.xenorchestra_network.network: Reading...
data.xenorchestra_sr.sr: Reading...
data.xenorchestra_template.vm_template: Read complete after 0s [id=d0b0869b-2503-0c17-1e5e-3725f6eba342]
data.xenorchestra_network.network: Read complete after 0s [id=a12df741-f34f-7d05-f120-462f0ab39a48]
data.xenorchestra_sr.sr: Read complete after 0s [id=86a9757d-9c05-9fe0-e79a-8243cb1f37f3]
xenorchestra_vm.vm: Refreshing state... [id=66ec6080-1a77-b460-1d63-8b39baa4a844]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
~ update in-place
Terraform will perform the following actions:
# xenorchestra_vm.vm will be updated in-place
~ resource "xenorchestra_vm" "vm" {
id = "66ec6080-1a77-b460-1d63-8b39baa4a844"
tags = []
# (24 unchanged attributes hidden)
# (3 unchanged blocks hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
xenorchestra_vm.vm: Modifying... [id=66ec6080-1a77-b460-1d63-8b39baa4a844]
xenorchestra_vm.vm: Still modifying... [id=66ec6080-1a77-b460-1d63-8b39baa4a844, 00m10s elapsed]
xenorchestra_vm.vm: Still modifying... [id=66ec6080-1a77-b460-1d63-8b39baa4a844, 00m20s elapsed]
xenorchestra_vm.vm: Still modifying... [id=66ec6080-1a77-b460-1d63-8b39baa4a844, 00m30s elapsed]
xenorchestra_vm.vm: Modifications complete after 36s [id=66ec6080-1a77-b460-1d63-8b39baa4a844]
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
```
In just a few lines of code, youve modified your infrastructure in a controlled and reproducible way.
- ***Before the modification - Single network interface***
![](../assets/wb_xo_tf2.png)
- ***After adding the second network interface***
![](../assets/wb_xo_tf3.png)
## Debugging and Logs
The provider supports detailed logging for troubleshooting and debugging purposes.
- **Enable Provider Logs**
To enable debug logging, set the `TF_LOG_PROVIDER` environment variable:
```bash
export TF_LOG_PROVIDER=DEBUG
terraform plan
```
- **Terraform Log Levels**
You can control the level of provider logging with the `TF_LOG_PROVIDER`environment variable:
```bash
export TF_LOG_PROVIDER=DEBUG
terraform apply
```
Valid `TF_LOG_PROVIDER` levels are: `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`.
- **Log to File**
To save logs to a file for analysis:
```bash
export TF_LOG_PROVIDER=DEBUG
export TF_LOG_PATH=./terraform.log
terraform apply
```
:::note
Only enable debug logging when troubleshooting, as it can significantly increase log verbosity and may impact performance.
:::
## Conclusion
The Terraform provider for Xen Orchestra represents an important step toward **VirtOps** (the application of DevOps practices to virtualization). By adopting **Infrastructure as Code**, you gain reliability, reproducibility, and efficiency, as it transforms infrastructure management into a collaborative and auditable process.
:::note
**Commercial Support**: For technical support, contact our support team through your customer portal.
**Community Support**:
- [XCP-ng Forum](https://xcp-ng.org/forum/)
- [Discord Community](https://discord.com/invite/ZpNq8ez)
- [GitHub Issues](https://github.com/vatesfr/terraform-provider-xenorchestra/issues)
For detailed provider documentation, check the [official Terraform registry](https://registry.terraform.io/providers/vatesfr/xenorchestra/latest) which contains up-to-date information on all resources, data sources, and releases.
:::
## Related links
* [Official Terraform Provider Documentation](https://docs.vates.tech/devops-tools/terraform-provider/)
* [Official Terraform Documentation](https://developer.hashicorp.com/terraform/docs)
* [Official Xen Orchestra Documentation](https://docs.xen-orchestra.com/)
* [Official XCP-ng Documentation](https://docs.xcp-ng.org/)
* [OpenTofu Documentation](https://opentofu.org/docs/)

View File

@@ -109,6 +109,20 @@ export default {
},
],
},
{
type: 'category',
label: 'DevOps tools',
collapsible: true,
collapsed: true,
items:[
'xo6/ansible',
'xo6/kubernetes',
'xo6/packer-provider',
'xo6/powershell-module',
'xo6/pulumi-provider',
'xo6/terraform-provider',
],
},
{
type: 'category',
label: 'Support',