docs(xo): import devops tools documentation from vates vms (#10062)
BIN
docs/docs/assets/hub_recipes.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
docs/docs/assets/k8s-cluster-tags-1.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
docs/docs/assets/k8s-cluster-tags-2.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
docs/docs/assets/k8s-cluster-tags-3.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
docs/docs/assets/k8s_cluster_custom_cidr.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
docs/docs/assets/kubernetes_cluster_creation.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
docs/docs/assets/running_cluster_deployment.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
docs/docs/assets/static_ip_addresses.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
docs/docs/assets/wb_xo_pl1.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
docs/docs/assets/wb_xo_pl2.png
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
docs/docs/assets/wb_xo_pl3.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
docs/docs/assets/wb_xo_psh1.png
Normal file
|
After Width: | Height: | Size: 465 KiB |
BIN
docs/docs/assets/wb_xo_psh2.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
docs/docs/assets/wb_xo_psh3.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
docs/docs/assets/wb_xo_psh4.png
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
docs/docs/assets/wb_xo_psh5.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
docs/docs/assets/wb_xo_psh6.png
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
docs/docs/assets/wb_xo_psh7.png
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
docs/docs/assets/wb_xo_tf1.png
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
docs/docs/assets/wb_xo_tf2.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
docs/docs/assets/wb_xo_tf3.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
520
docs/docs/xo6/ansible.md
Normal 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
@@ -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:
|
||||

|
||||
2. Go to the **Kubernetes cluster** recipe and click **Create**.\
|
||||
A cluster creation form appears:
|
||||

|
||||
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.
|
||||

|
||||
9. (Optional). If you want your cluster to use static IP addresses, check the **Static IP addresses** box and specify the IP address parameters:
|
||||

|
||||
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:
|
||||
:::
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## During deployment
|
||||
|
||||
Follow the progress on the **Task** screen while the cluster is being created:
|
||||

|
||||
|
||||
## 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, it’s 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/)
|
||||
1
docs/docs/xo6/packer-provider.md
Normal file
@@ -0,0 +1 @@
|
||||
# Packer provider
|
||||
141
docs/docs/xo6/powershell-module.md
Normal 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
|
||||
```
|
||||

|
||||
|
||||
* **Monitor ongoing tasks:**
|
||||
```bash
|
||||
Get-XoTask
|
||||
```
|
||||

|
||||
|
||||
* **Get information about virtual disks:**
|
||||
```bash
|
||||
Get-XoVdi
|
||||
```
|
||||

|
||||
|
||||
* **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
|
||||
```
|
||||

|
||||
|
||||
- **Step 2: Create a Snapshot**
|
||||
|
||||
```bash
|
||||
New-XoVmSnapshot -VmUuid "993d84c2-2571-8451-8073-afa8ef510a8d" -SnapshotName "your-snapshot-name"
|
||||
```
|
||||

|
||||
|
||||
- **Step 3: Verify Snapshot Creation**
|
||||
|
||||
```bash
|
||||
Get-XoVmSnapshot -Filter "name_label:your-snapshot-name"
|
||||
```
|
||||

|
||||
|
||||

|
||||
|
||||
<!--
|
||||
## 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)
|
||||
466
docs/docs/xo6/pulumi-provider.md
Normal 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.
|
||||
|
||||

|
||||
|
||||
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***
|
||||

|
||||
|
||||
* ***After adding the second network interface***
|
||||

|
||||
|
||||
|
||||
## 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/)
|
||||
598
docs/docs/xo6/terraform-provider.md
Normal 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
|
||||
Terraform’s 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, we’ll 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 we’ll 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 we’ll write it from scratch step by step.
|
||||
:::
|
||||
|
||||
### Installing Terraform
|
||||
|
||||
If you haven’t 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, let’s 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
|
||||
It’s 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, it’s 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 we’re 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**
|
||||
|
||||
It’s time to bring our VM to life !
|
||||
|
||||
* Run `terraform plan`
|
||||
|
||||
This command will analyze your code and show you what it’s 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.
|
||||
|
||||

|
||||
|
||||
|
||||
Any future modifications to this VM can now be easily **reviewed** and **version-controlled**.
|
||||
|
||||
To demonstrate this, let’s imagine that this VM needs a second network interface. Let’s see how easily we can make that change.
|
||||
|
||||
### Updating an Existing Infrastructure
|
||||
|
||||
One of Terraform’s 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. You’ll 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, you’ve modified your infrastructure in a controlled and reproducible way.
|
||||
|
||||
- ***Before the modification - Single network interface***
|
||||

|
||||
|
||||
- ***After adding the second network interface***
|
||||

|
||||
|
||||
## 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/)
|
||||
@@ -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',
|
||||
|
||||