Skip to content

Commit

Permalink
Merge pull request #122 from devopstales/develop
Browse files Browse the repository at this point in the history
Add multi-cluster support
  • Loading branch information
emersonfelipesp authored Jul 21, 2023
2 parents df27c08 + ec1afbc commit 64f6f82
Show file tree
Hide file tree
Showing 15 changed files with 569 additions and 381 deletions.
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

0 comments on commit 64f6f82

Please sign in to comment.