Compare commits
No commits in common. "main" and "0.1.0" have entirely different histories.
4 changed files with 14 additions and 82 deletions
35
Changelog.md
35
Changelog.md
|
@ -1,35 +0,0 @@
|
||||||
# netbox-pve-sync
|
|
||||||
|
|
||||||
## [Unreleased]
|
|
||||||
|
|
||||||
## [0.2.2] - 07/05/2025
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Use `NB_CLUSTER_ID` even for VM update.
|
|
||||||
|
|
||||||
## [0.2.1] - 01/05/2025
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- [#7] Improve tag handling.
|
|
||||||
|
|
||||||
## [0.2.0] - 21/04/2025
|
|
||||||
|
|
||||||
### New
|
|
||||||
|
|
||||||
- Monitoring PVE HA/Replication.
|
|
||||||
|
|
||||||
## [0.1.1] - 19/02/2025
|
|
||||||
|
|
||||||
### New
|
|
||||||
|
|
||||||
- [#5] Allow to configure cluster ID.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- Add eth0 as raw_interface_name.
|
|
||||||
|
|
||||||
## [0.1.0] - 19/02/2025
|
|
||||||
|
|
||||||
- Initial release.
|
|
25
README.md
25
README.md
|
@ -9,12 +9,6 @@ This script work by pulling VMs information from the PVE API and create/update/d
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
This package is available on PyPi. You can install it using pip.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ pip install netbox-pve-sync
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### On NetBox
|
### On NetBox
|
||||||
|
@ -27,9 +21,6 @@ The following env variables will need to be set:
|
||||||
- **NB_API_URL**: The URL to your NetBox instance. (ex: https://netbox.example.org)
|
- **NB_API_URL**: The URL to your NetBox instance. (ex: https://netbox.example.org)
|
||||||
- **NB_API_TOKEN**: The token created previously. (ex: f74cb99cf552b7005fd1a616b53efba2ce0c9656)
|
- **NB_API_TOKEN**: The token created previously. (ex: f74cb99cf552b7005fd1a616b53efba2ce0c9656)
|
||||||
|
|
||||||
You can also set the `NB_CLUSTER_ID` env variable in order to indicate the ID of the cluster that will be used in
|
|
||||||
NetBox.
|
|
||||||
|
|
||||||
You'll also need to perform a minimal configuration on NetBox:
|
You'll also need to perform a minimal configuration on NetBox:
|
||||||
|
|
||||||
- Create the physical nodes hosting the cluster. (The name should match the one on Proxmox, so that the script can
|
- Create the physical nodes hosting the cluster. (The name should match the one on Proxmox, so that the script can
|
||||||
|
@ -37,19 +28,17 @@ You'll also need to perform a minimal configuration on NetBox:
|
||||||
- Create the cluster.
|
- Create the cluster.
|
||||||
- Add the following Custom Fields:
|
- Add the following Custom Fields:
|
||||||
|
|
||||||
| Name | Object types | Label | Type |
|
| Name | Object types | Label | Type |
|
||||||
|------------|-----------------|------------|---------|
|
|-----------|-----------------|-----------|---------|
|
||||||
| autostart | Virtual Machine | Autostart | Boolean |
|
| autostart | Virtual Machine | Autostart | Boolean |
|
||||||
| replicated | Virtual Machine | Replicated | Boolean |
|
| backup | Virtual Disk | Backup | Boolean |
|
||||||
| ha | Virtual Machine | Failover | Boolean |
|
| dns_name | Prefix | DNS Name | Text |
|
||||||
| backup | Virtual Disk | Backup | Boolean |
|
|
||||||
| dns_name | Prefix | DNS Name | Text |
|
|
||||||
|
|
||||||
### On the PVE API
|
### On the PVE API
|
||||||
|
|
||||||
You'll need to create a dedicated user (ex: netsync) on your PVE cluster and then create an API token.
|
You'll need to create a dedicated user (ex: netsync) on your PVE cluster and then create an API token.
|
||||||
|
|
||||||
The user needs to have access to the VM.Monitor, Pool.Audit, VM.Audit, Sys.Audit permissions.
|
The user needs to have access to the VM.Monitor, Pool.Audit, VM.Audit permissions.
|
||||||
|
|
||||||
The following env variables will need to be set:
|
The following env variables will need to be set:
|
||||||
|
|
||||||
|
@ -63,5 +52,5 @@ The following env variables will need to be set:
|
||||||
You can then execute the script using the following command:
|
You can then execute the script using the following command:
|
||||||
|
|
||||||
```
|
```
|
||||||
PVE_API_HOST=xx PVE_API_USER=xx PVE_API_TOKEN=xx PVE_API_SECRET=xx NB_API_URL=xx NB_API_TOKEN=xx nbpxsync
|
PVE_API_HOST=xx PVE_API_USER=xx PVE_API_TOKEN=xx PVE_API_SECRET=xx NB_API_URL=xx NB_API_TOKEN=xx python3 -m netbox_pve_sync
|
||||||
```
|
```
|
|
@ -88,7 +88,6 @@ def _process_pve_tags(
|
||||||
slug=f'pool-{_pve_pool["poolid"]}'.lower(),
|
slug=f'pool-{_pve_pool["poolid"]}'.lower(),
|
||||||
description=f'Proxmox pool {_pve_pool["poolid"]}',
|
description=f'Proxmox pool {_pve_pool["poolid"]}',
|
||||||
)
|
)
|
||||||
_nb_objects['tags'][_nb_tag.name] = _nb_tag
|
|
||||||
|
|
||||||
return _nb_objects
|
return _nb_objects
|
||||||
|
|
||||||
|
@ -99,9 +98,7 @@ def _process_pve_virtual_machine(
|
||||||
_nb_objects: dict,
|
_nb_objects: dict,
|
||||||
_nb_device: any,
|
_nb_device: any,
|
||||||
_pve_tags: [str],
|
_pve_tags: [str],
|
||||||
_pve_virtual_machine: dict,
|
_pve_virtual_machine: dict
|
||||||
_is_replicated: bool,
|
|
||||||
_has_ha: bool,
|
|
||||||
) -> dict:
|
) -> dict:
|
||||||
_pve_node_name = _nb_device.name.lower()
|
_pve_node_name = _nb_device.name.lower()
|
||||||
|
|
||||||
|
@ -128,7 +125,7 @@ def _process_pve_virtual_machine(
|
||||||
serial=_pve_virtual_machine['vmid'],
|
serial=_pve_virtual_machine['vmid'],
|
||||||
name=_pve_virtual_machine['name'],
|
name=_pve_virtual_machine['name'],
|
||||||
site=_nb_device.site.id,
|
site=_nb_device.site.id,
|
||||||
cluster=os.environ.get('NB_CLUSTER_ID', 1),
|
cluster=1, # TODO
|
||||||
device=_nb_device.id,
|
device=_nb_device.id,
|
||||||
vcpus=pve_virtual_machine_config['cores'],
|
vcpus=pve_virtual_machine_config['cores'],
|
||||||
memory=int(pve_virtual_machine_config['memory']),
|
memory=int(pve_virtual_machine_config['memory']),
|
||||||
|
@ -136,22 +133,18 @@ def _process_pve_virtual_machine(
|
||||||
tags=list(map(lambda _pve_tag_name: _nb_objects['tags'][_pve_tag_name].id, _pve_tags)),
|
tags=list(map(lambda _pve_tag_name: _nb_objects['tags'][_pve_tag_name].id, _pve_tags)),
|
||||||
custom_fields={
|
custom_fields={
|
||||||
'autostart': pve_virtual_machine_config.get('onboot') == 1,
|
'autostart': pve_virtual_machine_config.get('onboot') == 1,
|
||||||
'replicated': _is_replicated,
|
|
||||||
'ha': _has_ha,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
nb_virtual_machine.name = _pve_virtual_machine['name']
|
nb_virtual_machine.name = _pve_virtual_machine['name']
|
||||||
nb_virtual_machine.site = _nb_device.site.id
|
nb_virtual_machine.site = _nb_device.site.id
|
||||||
nb_virtual_machine.cluster = os.environ.get('NB_CLUSTER_ID', 1)
|
nb_virtual_machine.cluster = 1
|
||||||
nb_virtual_machine.device = _nb_device.id
|
nb_virtual_machine.device = _nb_device.id
|
||||||
nb_virtual_machine.vcpus = pve_virtual_machine_config['cores']
|
nb_virtual_machine.vcpus = pve_virtual_machine_config['cores']
|
||||||
nb_virtual_machine.memory = int(pve_virtual_machine_config['memory'])
|
nb_virtual_machine.memory = int(pve_virtual_machine_config['memory'])
|
||||||
nb_virtual_machine.status = 'active' if _pve_virtual_machine['status'] == 'running' else 'offline'
|
nb_virtual_machine.status = 'active' if _pve_virtual_machine['status'] == 'running' else 'offline'
|
||||||
nb_virtual_machine.tags = list(map(lambda _pve_tag_name: _nb_objects['tags'][_pve_tag_name].id, _pve_tags))
|
nb_virtual_machine.tags = list(map(lambda _pve_tag_name: _nb_objects['tags'][_pve_tag_name].id, _pve_tags))
|
||||||
nb_virtual_machine.custom_fields['autostart'] = pve_virtual_machine_config.get('onboot') == 1
|
nb_virtual_machine.custom_fields['autostart'] = pve_virtual_machine_config.get('onboot') == 1
|
||||||
nb_virtual_machine.custom_fields['replicated'] = _is_replicated
|
|
||||||
nb_virtual_machine.custom_fields['ha'] = _has_ha
|
|
||||||
nb_virtual_machine.save()
|
nb_virtual_machine.save()
|
||||||
|
|
||||||
# Handle the VM network interfaces
|
# Handle the VM network interfaces
|
||||||
|
@ -253,7 +246,7 @@ def _process_pve_virtual_machine_network_interface(
|
||||||
|
|
||||||
# TODO: Improve Multiple IP address handling
|
# TODO: Improve Multiple IP address handling
|
||||||
_pve_virtual_machine_ip_address = None
|
_pve_virtual_machine_ip_address = None
|
||||||
for raw_interface_name in ['eth0', 'ens18', 'ens19']:
|
for raw_interface_name in ['ens18', 'ens19']:
|
||||||
if raw_interface_name in _pve_virtual_machine_ip_addresses:
|
if raw_interface_name in _pve_virtual_machine_ip_addresses:
|
||||||
_pve_virtual_machine_ip_address = _pve_virtual_machine_ip_addresses[raw_interface_name][0]
|
_pve_virtual_machine_ip_address = _pve_virtual_machine_ip_addresses[raw_interface_name][0]
|
||||||
break
|
break
|
||||||
|
@ -434,25 +427,13 @@ def main():
|
||||||
for pve_vm_resource in pve_api.cluster.resources.get(type='vm'):
|
for pve_vm_resource in pve_api.cluster.resources.get(type='vm'):
|
||||||
pve_vm_tags[pve_vm_resource['vmid']] = []
|
pve_vm_tags[pve_vm_resource['vmid']] = []
|
||||||
|
|
||||||
if 'pool' in pve_vm_resource:
|
pve_vm_tags[pve_vm_resource['vmid']].append(f'Pool/{pve_vm_resource["pool"]}')
|
||||||
pve_vm_tags[pve_vm_resource['vmid']].append(f'Pool/{pve_vm_resource["pool"]}')
|
|
||||||
|
|
||||||
if 'tags' in pve_vm_resource:
|
if 'tags' in pve_vm_resource:
|
||||||
pass # TODO: pve_vm_tags[pve_vm_resource['vmid']].append(pve_vm_resource['tags'])
|
pass # TODO: pve_vm_tags[pve_vm_resource['vmid']].append(pve_vm_resource['tags'])
|
||||||
|
|
||||||
pve_ha_virtual_machine_ids = list(
|
|
||||||
map(
|
|
||||||
lambda r: int(r['sid'].split(':')[1]),
|
|
||||||
filter(lambda r: r['type'] == 'service', pve_api.cluster.ha.status.current.get())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Process Proxmox nodes
|
# Process Proxmox nodes
|
||||||
for pve_node in pve_api.nodes.get():
|
for pve_node in pve_api.nodes.get():
|
||||||
pve_replicated_virtual_machine_ids = list(
|
|
||||||
map(lambda r: r['guest'], pve_api.nodes(pve_node['node']).replication.get())
|
|
||||||
)
|
|
||||||
|
|
||||||
# This script does not create the hardware devices.
|
# This script does not create the hardware devices.
|
||||||
nb_device = nb_objects['devices'].get(pve_node['node'].lower())
|
nb_device = nb_objects['devices'].get(pve_node['node'].lower())
|
||||||
if nb_device is None:
|
if nb_device is None:
|
||||||
|
@ -471,8 +452,6 @@ def main():
|
||||||
nb_device,
|
nb_device,
|
||||||
pve_vm_tags.get(pve_virtual_machine['vmid'], []),
|
pve_vm_tags.get(pve_virtual_machine['vmid'], []),
|
||||||
pve_virtual_machine,
|
pve_virtual_machine,
|
||||||
pve_virtual_machine['vmid'] in pve_replicated_virtual_machine_ids,
|
|
||||||
pve_virtual_machine['vmid'] in pve_ha_virtual_machine_ids,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "netbox-pve-sync"
|
name = "netbox-pve-sync"
|
||||||
version = "0.2.2"
|
version = "0.1.0"
|
||||||
authors = [
|
authors = [
|
||||||
{ name = "Aloïs Micard", email = "alois@micard.lu" },
|
{ name = "Aloïs Micard", email = "alois@micard.lu" },
|
||||||
]
|
]
|
||||||
|
@ -26,7 +26,6 @@ dependencies = [
|
||||||
[project.urls]
|
[project.urls]
|
||||||
Homepage = "https://git.creekorful.cloud/creekorful/netbox-pve-sync"
|
Homepage = "https://git.creekorful.cloud/creekorful/netbox-pve-sync"
|
||||||
Issues = "https://git.creekorful.cloud/creekorful/netbox-pve-sync/issues"
|
Issues = "https://git.creekorful.cloud/creekorful/netbox-pve-sync/issues"
|
||||||
Changelog = "https://git.creekorful.cloud/creekorful/netbox-pve-sync/src/branch/main/Changelog.md"
|
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
nbpxsync = "netbox_pve_sync:main"
|
nbpxsync = "netbox_pve_sync:main"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue