Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multi-cluster support #122

Merged
merged 8 commits into from
Jul 21, 2023
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,17 +153,19 @@ Replace the values with your own following the [Configuration Parameters](#2-con
```python
PLUGINS_CONFIG = {
'netbox_proxbox': {
'proxmox': {
'domain': 'proxbox.example.com', # May also be IP address
'http_port': 8006,
'user': 'root@pam', # always required
'password': 'Strong@P4ssword', # only required, if you don't want to use token based authentication
'token': {
'name': 'tokenID', # Only type the token name and not the 'user@pam:tokenID' format
'value': '039az154-23b2-4be0-8d20-b66abc8c4686'
},
'ssl': False
},
'proxmox': [
{
'domain': 'proxbox.example.com', # May also be IP address
'http_port': 8006,
'user': 'root@pam', # always required
'password': 'Strong@P4ssword', # only required, if you don't want to use token based authentication
'token': {
'name': 'tokenID', # Only type the token name and not the 'user@pam:tokenID' format
'value': '039az154-23b2-4be0-8d20-b66abc8c4686'
},
'ssl': False
}
],
'netbox': {
'domain': 'localhost', # Ensure localhost is added to ALLOWED_HOSTS
'http_port': 8001, # Gunicorn port.
Expand Down Expand Up @@ -194,6 +196,7 @@ PLUGINS_CONFIG = {
```
(venv) $ cd /opt/netbox/netbox/
(venv) $ python3 manage.py migrate
(venv) $ python3 manage.py collectstatic --no-input
```

---
Expand All @@ -211,7 +214,7 @@ Restart the WSGI service to load the new plugin:

The following options are available:

* `proxmox`: (Dict) Proxmox related configuration to use proxmoxer.
* `proxmox`: (List) Proxmox related configuration to use proxmoxer.
* `proxmox.domain`: (String) Domain or IP address of Proxmox.
* `proxmox.http_port`: (Integer) Proxmox HTTP port (default: 8006).
* `proxmox.user`: (String) Proxmox Username.
Expand Down
5 changes: 5 additions & 0 deletions netbox_custom_fields.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Name,Content types,Label,Group name,Type,Required,Description,ID,Default,Search weight,Filter logic,UI visibility,Cloneable,Display weight,Choices,Created,Last updated
proxmox_id,virtualization.virtualmachine,[Proxmox] ID,,Integer,False,Proxmox VM/CT ID,1,,1000,Loose,Read/Write,False,100,[],2023-07-06 12:49,2023-07-06 12:50
proxmox_keep_interface,dcim.interface,,,Boolean (true/false),False,,4,,1000,Loose,Read/Write,False,100,[],2023-07-06 12:53,2023-07-06 12:53
proxmox_node,virtualization.virtualmachine,[Proxmox] Node,,Text,False,Proxmox Node (Server),2,,1000,Loose,Read/Write,False,100,[],2023-07-06 12:51,2023-07-06 12:51
proxmox_type,virtualization.virtualmachine,[Proxmox] Type,,Selection,False,Proxmox type (VM or CT),3,,1000,Loose,Read/Write,False,100,"['qemu', 'lxc']",2023-07-06 12:52,2023-07-06 12:52
24 changes: 13 additions & 11 deletions netbox_proxbox/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,19 @@ class ProxboxConfig(PluginConfig):
base_url = "proxbox"
required_settings = []
default_settings = {
'proxmox': {
'domain': 'proxbox.example.com', # May also be IP address
'http_port': 8006,
'user': 'root@pam',
'password': 'Strong@P4ssword',
'token': {
'name': 'tokenID',
'value': '039az154-23b2-4be0-8d20-b66abc8c4686'
},
'ssl': False
},
'proxmox': [
{
'domain': 'proxbox.example.com', # May also be IP address
'http_port': 8006,
'user': 'root@pam',
'password': 'Strong@P4ssword',
'token': {
'name': 'proxbox',
'value': '039az154-23b2-4be0-8d20-b66abc8c4686'
},
'ssl': False
}
],
'netbox': {
'domain': 'netbox.example.com', # May also be IP address
'http_port': 80,
Expand Down
4 changes: 2 additions & 2 deletions netbox_proxbox/proxbox_api/create/dcim.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def site(**kwargs):
#
# dcim.devices (nodes)
#
def node(proxmox_node):
def node(proxmox, proxmox_node):
# Create json with basic NODE information
node_json = {}
node_json["name"] = proxmox_node['name']
Expand All @@ -140,7 +140,7 @@ def node(proxmox_node):
node_json["status"] = 'active'
node_json["tags"] = [extras.tag().id]

cluster = virtualization.cluster()
cluster = virtualization.cluster(proxmox)
if cluster:
if cluster != None:
node_json["cluster"] = cluster.id
Expand Down
17 changes: 3 additions & 14 deletions netbox_proxbox/proxbox_api/create/virtualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
# PLUGIN_CONFIG variables
from ..plugins_config import (
NETBOX_SESSION as nb,
PROXMOX_SESSION as proxmox,
NETBOX_VM_ROLE_ID,

)

from . import (
Expand Down Expand Up @@ -54,7 +52,7 @@ def cluster_type():
#
# virtualization.clusters
#
def cluster():
def cluster(proxmox):
#
# Cluster
#
Expand Down Expand Up @@ -135,19 +133,10 @@ def cluster():
except:
return f"Error creating the '{proxmox_cluster_name}' cluster. Possible errors: the name '{proxmox_cluster_name}' is already used."










#
# virtualization.virtual_machines
#
def virtual_machine(proxmox_vm, duplicate):
def virtual_machine(proxmox, proxmox_vm, duplicate):
# Create json with basic VM/CT information
vm_json = {}
netbox_obj = None
Expand All @@ -164,7 +153,7 @@ def virtual_machine(proxmox_vm, duplicate):
vm_json["name"] = proxmox_vm['name']

vm_json["status"] = 'active'
vm_json["cluster"] = cluster().id
vm_json["cluster"] = cluster(proxmox).id
vm_json["role"] = extras.role(role_id = NETBOX_VM_ROLE_ID).id
vm_json["tags"] = [extras.tag().id]

Expand Down
164 changes: 98 additions & 66 deletions netbox_proxbox/proxbox_api/plugins_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@
# Proxmox related settings
#
# API URI
DEFAULT_PROXMOX = DEFAULT_PROXMOX_SETTING.get("domain")
DEFAULT_PROXMOX_PORT = DEFAULT_PROXMOX_SETTING.get("http_port")
DEFAULT_PROXMOX_SSL = DEFAULT_PROXMOX_SETTING.get("ssl")
DEFAULT_PROXMOX = DEFAULT_PROXMOX_SETTING[0].get("domain")
DEFAULT_PROXMOX_PORT = DEFAULT_PROXMOX_SETTING[0].get("http_port")
DEFAULT_PROXMOX_SSL = DEFAULT_PROXMOX_SETTING[0].get("ssl")

# ACCESS
DEFAULT_PROXMOX_USER = DEFAULT_PROXMOX_SETTING.get("user")
DEFAULT_PROXMOX_PASSWORD = DEFAULT_PROXMOX_SETTING.get("password")
DEFAULT_PROXMOX_USER = DEFAULT_PROXMOX_SETTING[0].get("user")
DEFAULT_PROXMOX_PASSWORD = DEFAULT_PROXMOX_SETTING[0].get("password")

DEFAULT_PROXMOX_TOKEN = DEFAULT_PROXMOX_SETTING.get("token")
DEFAULT_PROXMOX_TOKEN = DEFAULT_PROXMOX_SETTING[0].get("token")
DEFAULT_PROXMOX_TOKEN_NAME = DEFAULT_PROXMOX_TOKEN.get("name", None)
DEFAULT_PROXMOX_TOKEN_VALUE = DEFAULT_PROXMOX_TOKEN.get("value", None)

Expand Down Expand Up @@ -74,23 +74,6 @@
PROXMOX_SETTING = USER_PLUGINS_CONFIG.get("proxmox", DEFAULT_PROXMOX_SETTING)
NETBOX_SETTING = USER_PLUGINS_CONFIG.get("netbox", DEFAULT_NETBOX_SETTING)

#
# Proxmox related settings
#
# API URI
PROXMOX = PROXMOX_SETTING.get("domain", DEFAULT_PROXMOX)
PROXMOX_PORT = PROXMOX_SETTING.get("http_port", DEFAULT_PROXMOX_PORT)
PROXMOX_SSL = PROXMOX_SETTING.get("ssl", DEFAULT_PROXMOX_SSL)

# ACCESS
PROXMOX_USER = PROXMOX_SETTING.get("user", DEFAULT_PROXMOX_USER)
PROXMOX_PASSWORD = PROXMOX_SETTING.get("password", DEFAULT_PROXMOX_PASSWORD)

PROXMOX_TOKEN = PROXMOX_SETTING.get("token", DEFAULT_PROXMOX_TOKEN)
if PROXMOX_TOKEN != None:
PROXMOX_TOKEN_NAME = PROXMOX_TOKEN.get("name", DEFAULT_PROXMOX_TOKEN_NAME)
PROXMOX_TOKEN_VALUE = PROXMOX_TOKEN.get("value", DEFAULT_PROXMOX_TOKEN_VALUE)

#
# NETBOX RELATED SETTINGS
#
Expand All @@ -111,49 +94,98 @@
NETBOX_NODE_ROLE_ID = NETBOX_SETTINGS.get("node_role_id", DEFAULT_NETBOX_NODE_ROLE_ID)
NETBOX_SITE_ID = NETBOX_SETTINGS.get("site_id", DEFAULT_NETBOX_SITE_ID)


####################################################################################################
# #
# WITH PLUGIN CONFIGURED, STARTS BOTH PROXMOX AND NETBOX SESSION #
# #
####################################################################################################

#
# PROXMOX SESSION
#
# Check if token was provided
if PROXMOX_TOKEN_VALUE != None and len(PROXMOX_TOKEN_VALUE) > 0:
try:
if PROXMOX_SSL == False:
# DISABLE SSL WARNING
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# Start PROXMOX session using TOKEN
PROXMOX_SESSION = ProxmoxAPI(
PROXMOX,
port=PROXMOX_PORT,
user=PROXMOX_USER,
token_name=PROXMOX_TOKEN_NAME,
token_value=PROXMOX_TOKEN_VALUE,
verify_ssl=PROXMOX_SSL
)
except:
raise RuntimeError(f'Error trying to initialize Proxmox Session using TOKEN (token_name: {PROXMOX_TOKEN_NAME} and token_value: {PROXMOX_TOKEN_VALUE} provided')

# If token not provided, start session using user and passwd
else:
try:
# Start PROXMOX session using USER CREDENTIALS
PROXMOX_SESSION = ProxmoxAPI(
PROXMOX,
port=PROXMOX_PORT,
user=PROXMOX_USER,
password=PROXMOX_PASSWORD,
verify_ssl=PROXMOX_SSL
)
except:
raise RuntimeError(f'Error trying to initialize Proxmox Session using USER {PROXMOX_USER} and PASSWORD')
PROXMOX_SESSIONS = {}

def get_proxmox_session(PROXMOX_SETTING):
#
# Proxmox related settings
#
# API URI
PROXMOX = PROXMOX_SETTING.get("domain", DEFAULT_PROXMOX)
PROXMOX_PORT = PROXMOX_SETTING.get("http_port", DEFAULT_PROXMOX_PORT)
PROXMOX_SSL = PROXMOX_SETTING.get("ssl", DEFAULT_PROXMOX_SSL)

# ACCESS
PROXMOX_USER = PROXMOX_SETTING.get("user", DEFAULT_PROXMOX_USER)
PROXMOX_PASSWORD = PROXMOX_SETTING.get("password", DEFAULT_PROXMOX_PASSWORD)

output = {
'PROXMOX': PROXMOX,
'PROXMOX_PORT': PROXMOX_PORT,
'PROXMOX_SSL': PROXMOX_SSL,
'PROXMOX_TOKEN': None,
'PROXMOX_TOKEN_NAME': None,
'PROXMOX_TOKEN_VALUE': None
}

PROXMOX_TOKEN = PROXMOX_SETTING.get("token", DEFAULT_PROXMOX_TOKEN)
if PROXMOX_PASSWORD is None and PROXMOX_TOKEN is not None:
PROXMOX_TOKEN_NAME = PROXMOX_TOKEN.get("name", DEFAULT_PROXMOX_TOKEN_NAME)
PROXMOX_TOKEN_VALUE = PROXMOX_TOKEN.get("value", DEFAULT_PROXMOX_TOKEN_VALUE)
output["PROXMOX_TOKEN"] = PROXMOX_TOKEN
output["PROXMOX_TOKEN_NAME"] = PROXMOX_TOKEN_NAME
output["PROXMOX_TOKEN_VALUE"] = PROXMOX_TOKEN_VALUE
else:
PROXMOX_TOKEN_NAME = None
PROXMOX_TOKEN_VALUE = None

####################################################################################################
# #
# WITH PLUGIN CONFIGURED, STARTS BOTH PROXMOX AND NETBOX SESSION #
# #
####################################################################################################

#
# PROXMOX SESSION
#
# Check if token was provided
if PROXMOX_TOKEN_VALUE is not None and len(PROXMOX_TOKEN_VALUE) > 0:
try:
if PROXMOX_SSL == False:
# DISABLE SSL WARNING
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# Start PROXMOX session using TOKEN
PROXMOX_SESSION = ProxmoxAPI(
PROXMOX,
port=PROXMOX_PORT,
user=PROXMOX_USER,
token_name=PROXMOX_TOKEN_NAME,
token_value=PROXMOX_TOKEN_VALUE,
verify_ssl=PROXMOX_SSL
)
output['PROXMOX_SESSION'] = PROXMOX_SESSION
return output
except:
raise RuntimeError(f'Error trying to initialize Proxmox Session using TOKEN (token_name: {PROXMOX_TOKEN_NAME} and token_value: {PROXMOX_TOKEN_VALUE} provided')

# If token not provided, start session using user and passwd
else:
try:
if PROXMOX_SSL == False:
# DISABLE SSL WARNING
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# Start PROXMOX session using USER CREDENTIALS
PROXMOX_SESSION = ProxmoxAPI(
PROXMOX,
port=PROXMOX_PORT,
user=PROXMOX_USER,
password=PROXMOX_PASSWORD,
verify_ssl=PROXMOX_SSL
)
output['PROXMOX_SESSION'] = PROXMOX_SESSION
return output
except:
raise RuntimeError(f'Error trying to initialize Proxmox Session using USER {PROXMOX_USER} and PASSWORD')

for s in PROXMOX_SETTING:
P_Setting = get_proxmox_session(s)
if P_Setting is not None:
v = P_Setting['PROXMOX']
PROXMOX_SESSIONS[v] = P_Setting

#
# NETBOX SESSION
Expand Down
17 changes: 10 additions & 7 deletions netbox_proxbox/proxbox_api/remove.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@

# PLUGIN_CONFIG variables
from .plugins_config import (
PROXMOX_SESSION as proxmox,
NETBOX_SESSION as nb,
)

import logging

# Verify if VM/CT exists on Proxmox
def is_vm_on_proxmox(netbox_vm):
def is_vm_on_proxmox(proxmox_session, netbox_vm):
# Get json of all virtual machines from Proxmox
proxmox = proxmox_session.get('PROXMOX_SESSION')
PROXMOX = proxmox_session.get('PROXMOX')
PROXMOX_PORT = proxmox_session.get('PROXMOX_PORT')

all_proxmox_vms = proxmox.cluster.resources.get(type='vm')

# Netbox name
Expand Down Expand Up @@ -69,7 +72,7 @@ def is_vm_on_proxmox(netbox_vm):

# If 'local_context' is null, try updating it to be able to get ID from VM
if local_context == None:
local_context_updated = updates.local_context_data(netbox_vm, all_proxmox_vms[name_index])
local_context_updated = updates.local_context_data(netbox_vm, all_proxmox_vms[name_index], PROXMOX, PROXMOX_PORT)

if local_context_updated == True:
local_context = netbox_vm.local_context_data
Expand Down Expand Up @@ -105,11 +108,11 @@ def is_vm_on_proxmox(netbox_vm):
# Comparison failed, not able to find VM on Proxmox
return False

def all():
def all(proxmox_session, cluster):
json_vm_all = []

# Get all VM/CTs from Netbox
netbox_all_vms = nb.virtualization.virtual_machines.all()
# Get VM/CTs of the specific cluster from Netbox
netbox_all_vms = nb.virtualization.virtual_machines.filter(cluster=cluster.name)

for nb_vm_each in netbox_all_vms:
json_vm = {}
Expand All @@ -120,7 +123,7 @@ def all():
json_vm["name"] = netbox_name

# Verify if VM exists on Proxmox
vm_on_proxmox = is_vm_on_proxmox(nb_vm_each)
vm_on_proxmox = is_vm_on_proxmox(proxmox_session, nb_vm_each)

if vm_on_proxmox == True:
log_message = f'[OK] VM exists on both systems (Netbox and Proxmox) -> {netbox_name}'
Expand Down
Loading